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