1 /* 2 * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 package kotlinx.coroutines 5 6 import kotlinx.coroutines.CoroutineStart.* 7 import kotlinx.coroutines.intrinsics.* 8 import kotlin.coroutines.* 9 10 /** 11 * Defines start options for coroutines builders. 12 * It is used in `start` parameter of [launch][CoroutineScope.launch], [async][CoroutineScope.async], and other coroutine builder functions. 13 * 14 * The summary of coroutine start options is: 15 * * [DEFAULT] -- immediately schedules coroutine for execution according to its context; 16 * * [LAZY] -- starts coroutine lazily, only when it is needed; 17 * * [ATOMIC] -- atomically (in a non-cancellable way) schedules coroutine for execution according to its context; 18 * * [UNDISPATCHED] -- immediately executes coroutine until its first suspension point _in the current thread_. 19 */ 20 public enum class CoroutineStart { 21 /** 22 * Default -- immediately schedules the coroutine for execution according to its context. 23 * 24 * If the [CoroutineDispatcher] of the coroutine context returns `true` from [CoroutineDispatcher.isDispatchNeeded] 25 * function as most dispatchers do, then the coroutine code is dispatched for execution later, while the code that 26 * invoked the coroutine builder continues execution. 27 * 28 * Note that [Dispatchers.Unconfined] always returns `false` from its [CoroutineDispatcher.isDispatchNeeded] 29 * function, so starting a coroutine with [Dispatchers.Unconfined] by [DEFAULT] is the same as using [UNDISPATCHED]. 30 * 31 * If coroutine [Job] is cancelled before it even had a chance to start executing, then it will not start its 32 * execution at all, but will complete with an exception. 33 * 34 * Cancellability of a coroutine at suspension points depends on the particular implementation details of 35 * suspending functions. Use [suspendCancellableCoroutine] to implement cancellable suspending functions. 36 */ 37 DEFAULT, 38 39 /** 40 * Starts the coroutine lazily, only when it is needed. 41 * 42 * See the documentation for the corresponding coroutine builders for details 43 * (like [launch][CoroutineScope.launch] and [async][CoroutineScope.async]). 44 * 45 * If coroutine [Job] is cancelled before it even had a chance to start executing, then it will not start its 46 * execution at all, but will complete with an exception. 47 */ 48 LAZY, 49 50 /** 51 * Atomically (i.e., in a non-cancellable way) schedules the coroutine for execution according to its context. 52 * This is similar to [DEFAULT], but the coroutine cannot be cancelled before it starts executing. 53 * 54 * Cancellability of coroutine at suspension points depends on the particular implementation details of 55 * suspending functions as in [DEFAULT]. 56 */ 57 @ExperimentalCoroutinesApi // Since 1.0.0, no ETA on stability 58 ATOMIC, 59 60 /** 61 * Immediately executes the coroutine until its first suspension point _in the current thread_ similarly to 62 * the coroutine being started using [Dispatchers.Unconfined]. However, when the coroutine is resumed from suspension 63 * it is dispatched according to the [CoroutineDispatcher] in its context. 64 * 65 * This is similar to [ATOMIC] in the sense that coroutine starts executing even if it was already cancelled, 66 * but the difference is that it starts executing in the same thread. 67 * 68 * Cancellability of coroutine at suspension points depends on the particular implementation details of 69 * suspending functions as in [DEFAULT]. 70 * 71 * ### Unconfined event loop 72 * 73 * Unlike [Dispatchers.Unconfined] and [MainCoroutineDispatcher.immediate], nested undispatched coroutines do not form 74 * an event loop that otherwise prevents potential stack overflow in case of unlimited nesting. 75 */ 76 UNDISPATCHED; 77 78 /** 79 * Starts the corresponding block as a coroutine with this coroutine's start strategy. 80 * 81 * * [DEFAULT] uses [startCoroutineCancellable]. 82 * * [ATOMIC] uses [startCoroutine]. 83 * * [UNDISPATCHED] uses [startCoroutineUndispatched]. 84 * * [LAZY] does nothing. 85 * 86 * @suppress **This an internal API and should not be used from general code.** 87 */ 88 @InternalCoroutinesApi invokenull89 public operator fun <T> invoke(block: suspend () -> T, completion: Continuation<T>): Unit = 90 when (this) { 91 DEFAULT -> block.startCoroutineCancellable(completion) 92 ATOMIC -> block.startCoroutine(completion) 93 UNDISPATCHED -> block.startCoroutineUndispatched(completion) 94 LAZY -> Unit // will start lazily 95 } 96 97 /** 98 * Starts the corresponding block with receiver as a coroutine with this coroutine start strategy. 99 * 100 * * [DEFAULT] uses [startCoroutineCancellable]. 101 * * [ATOMIC] uses [startCoroutine]. 102 * * [UNDISPATCHED] uses [startCoroutineUndispatched]. 103 * * [LAZY] does nothing. 104 * 105 * @suppress **This an internal API and should not be used from general code.** 106 */ 107 @InternalCoroutinesApi invokenull108 public operator fun <R, T> invoke(block: suspend R.() -> T, receiver: R, completion: Continuation<T>): Unit = 109 when (this) { 110 DEFAULT -> block.startCoroutineCancellable(receiver, completion) 111 ATOMIC -> block.startCoroutine(receiver, completion) 112 UNDISPATCHED -> block.startCoroutineUndispatched(receiver, completion) 113 LAZY -> Unit // will start lazily 114 } 115 116 /** 117 * Returns `true` when [LAZY]. 118 * 119 * @suppress **This an internal API and should not be used from general code.** 120 */ 121 @InternalCoroutinesApi 122 public val isLazy: Boolean get() = this === LAZY 123 } 124