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