xref: /aosp_15_r20/external/kotlinx.coroutines/kotlinx-coroutines-core/common/src/AbstractCoroutine.kt (revision 7a7160fed73afa6648ef8aa100d4a336fe921d9a)
1 @file:Suppress("DEPRECATION_ERROR")
2 
3 package kotlinx.coroutines
4 
5 import kotlinx.coroutines.CoroutineStart.*
6 import kotlinx.coroutines.intrinsics.*
7 import kotlin.coroutines.*
8 
9 /**
10  * Abstract base class for implementation of coroutines in coroutine builders.
11  *
12  * This class implements completion [Continuation], [Job], and [CoroutineScope] interfaces.
13  * It stores the result of continuation in the state of the job.
14  * This coroutine waits for children coroutines to finish before completing and
15  * fails through an intermediate _failing_ state.
16  *
17  * The following methods are available for override:
18  *
19  * - [onStart] is invoked when the coroutine was created in non-active state and is being [started][Job.start].
20  * - [onCancelling] is invoked as soon as the coroutine starts being cancelled for any reason (or completes).
21  * - [onCompleted] is invoked when the coroutine completes with a value.
22  * - [onCancelled] in invoked when the coroutine completes with an exception (cancelled).
23  *
24  * @param parentContext the context of the parent coroutine.
25  * @param initParentJob specifies whether the parent-child relationship should be instantiated directly
26  *               in `AbstractCoroutine` constructor. If set to `false`, it's the responsibility of the child class
27  *               to invoke [initParentJob] manually.
28  * @param active when `true` (by default), the coroutine is created in the _active_ state, otherwise it is created in the _new_ state.
29  *               See [Job] for details.
30  *
31  * @suppress **This an internal API and should not be used from general code.**
32  */
33 @InternalCoroutinesApi
34 public abstract class AbstractCoroutine<in T>(
35     parentContext: CoroutineContext,
36     initParentJob: Boolean,
37     active: Boolean
38 ) : JobSupport(active), Job, Continuation<T>, CoroutineScope {
39 
40     init {
41         /*
42          * Setup parent-child relationship between the parent in the context and the current coroutine.
43          * It may cause this coroutine to become _cancelling_ if the parent is already cancelled.
44          * It is dangerous to install parent-child relationship here if the coroutine class
45          * operates its state from within onCancelled or onCancelling
46          * (with exceptions for rx integrations that can't have any parent)
47          */
48         if (initParentJob) initParentJob(parentContext[Job])
49     }
50 
51     /**
52      * The context of this coroutine that includes this coroutine as a [Job].
53      */
54     @Suppress("LeakingThis")
55     public final override val context: CoroutineContext = parentContext + this
56 
57     /**
58      * The context of this scope which is the same as the [context] of this coroutine.
59      */
60     public override val coroutineContext: CoroutineContext get() = context
61 
62     override val isActive: Boolean get() = super.isActive
63 
64     /**
65      * This function is invoked once when the job was completed normally with the specified [value],
66      * right before all the waiters for the coroutine's completion are notified.
67      */
onCompletednull68     protected open fun onCompleted(value: T) {}
69 
70     /**
71      * This function is invoked once when the job was cancelled with the specified [cause],
72      * right before all the waiters for coroutine's completion are notified.
73      *
74      * **Note:** the state of the coroutine might not be final yet in this function and should not be queried.
75      * You can use [completionCause] and [completionCauseHandled] to recover parameters that we passed
76      * to this `onCancelled` invocation only when [isCompleted] returns `true`.
77      *
78      * @param cause The cancellation (failure) cause
79      * @param handled `true` if the exception was handled by parent (always `true` when it is a [CancellationException])
80      */
onCancellednull81     protected open fun onCancelled(cause: Throwable, handled: Boolean) {}
82 
cancellationExceptionMessagenull83     override fun cancellationExceptionMessage(): String = "$classSimpleName was cancelled"
84 
85     @Suppress("UNCHECKED_CAST")
86     protected final override fun onCompletionInternal(state: Any?) {
87         if (state is CompletedExceptionally)
88             onCancelled(state.cause, state.handled)
89         else
90             onCompleted(state as T)
91     }
92 
93     /**
94      * Completes execution of this with coroutine with the specified result.
95      */
resumeWithnull96     public final override fun resumeWith(result: Result<T>) {
97         val state = makeCompletingOnce(result.toState())
98         if (state === COMPLETING_WAITING_CHILDREN) return
99         afterResume(state)
100     }
101 
afterResumenull102     protected open fun afterResume(state: Any?): Unit = afterCompletion(state)
103 
104     internal final override fun handleOnCompletionException(exception: Throwable) {
105         handleCoroutineException(context, exception)
106     }
107 
nameStringnull108     internal override fun nameString(): String {
109         val coroutineName = context.coroutineName ?: return super.nameString()
110         return "\"$coroutineName\":${super.nameString()}"
111     }
112 
113     /**
114      * Starts this coroutine with the given code [block] and [start] strategy.
115      * This function shall be invoked at most once on this coroutine.
116      *
117      * - [DEFAULT] uses [startCoroutineCancellable].
118      * - [ATOMIC] uses [startCoroutine].
119      * - [UNDISPATCHED] uses [startCoroutineUndispatched].
120      * - [LAZY] does nothing.
121      */
startnull122     public fun <R> start(start: CoroutineStart, receiver: R, block: suspend R.() -> T) {
123         start(block, receiver, this)
124     }
125 }
126