• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3  */
4 
5 package kotlinx.coroutines.intrinsics
6 
7 import kotlinx.coroutines.*
8 import kotlinx.coroutines.internal.*
9 import kotlin.coroutines.*
10 import kotlin.coroutines.intrinsics.*
11 
12 /**
13  * Use this function to start coroutine in a cancellable way, so that it can be cancelled
14  * while waiting to be dispatched.
15  */
16 @InternalCoroutinesApi
<lambda>null17 public fun <T> (suspend () -> T).startCoroutineCancellable(completion: Continuation<T>): Unit = runSafely(completion) {
18     createCoroutineUnintercepted(completion).intercepted().resumeCancellableWith(Result.success(Unit))
19 }
20 
21 /**
22  * Use this function to start coroutine in a cancellable way, so that it can be cancelled
23  * while waiting to be dispatched.
24  */
startCoroutineCancellablenull25 internal fun <R, T> (suspend (R) -> T).startCoroutineCancellable(
26     receiver: R, completion: Continuation<T>,
27     onCancellation: ((cause: Throwable) -> Unit)? = null
28 ) =
29     runSafely(completion) {
30         createCoroutineUnintercepted(receiver, completion).intercepted().resumeCancellableWith(Result.success(Unit), onCancellation)
31     }
32 
33 /**
34  * Similar to [startCoroutineCancellable], but for already created coroutine.
35  * [fatalCompletion] is used only when interception machinery throws an exception
36  */
startCoroutineCancellablenull37 internal fun Continuation<Unit>.startCoroutineCancellable(fatalCompletion: Continuation<*>) =
38     runSafely(fatalCompletion) {
39         intercepted().resumeCancellableWith(Result.success(Unit))
40     }
41 
42 /**
43  * Runs given block and completes completion with its exception if it occurs.
44  * Rationale: [startCoroutineCancellable] is invoked when we are about to run coroutine asynchronously in its own dispatcher.
45  * Thus if dispatcher throws an exception during coroutine start, coroutine never completes, so we should treat dispatcher exception
46  * as its cause and resume completion.
47  */
runSafelynull48 private inline fun runSafely(completion: Continuation<*>, block: () -> Unit) {
49     try {
50         block()
51     } catch (e: Throwable) {
52         dispatcherFailure(completion, e)
53     }
54 }
55 
dispatcherFailurenull56 private fun dispatcherFailure(completion: Continuation<*>, e: Throwable) {
57     /*
58      * This method is invoked when we failed to start a coroutine due to the throwing
59      * dispatcher implementation or missing Dispatchers.Main.
60      * This situation is not recoverable, so we are trying to deliver the exception by all means:
61      * 1) Resume the coroutine with an exception, so it won't prevent its parent from completion
62      * 2) Rethrow the exception immediately, so it will crash the caller (e.g. when the coroutine had
63      *    no parent or it was async/produce over MainScope).
64      */
65     completion.resumeWith(Result.failure(e))
66     throw e
67 }
68