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