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