1 /* 2 * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 @file:Suppress("DEPRECATION_ERROR") 5 6 package kotlinx.coroutines 7 8 import kotlinx.coroutines.CoroutineStart.* 9 import kotlinx.coroutines.intrinsics.* 10 import kotlin.coroutines.* 11 import kotlin.jvm.* 12 13 /** 14 * Abstract base class for implementation of coroutines in coroutine builders. 15 * 16 * This class implements completion [Continuation], [Job], and [CoroutineScope] interfaces. 17 * It stores the result of continuation in the state of the job. 18 * This coroutine waits for children coroutines to finish before completing and 19 * fails through an intermediate _failing_ state. 20 * 21 * The following methods are available for override: 22 * 23 * * [onStart] is invoked when the coroutine was created in non-active state and is being [started][Job.start]. 24 * * [onCancelling] is invoked as soon as the coroutine starts being cancelled for any reason (or completes). 25 * * [onCompleted] is invoked when the coroutine completes with a value. 26 * * [onCancelled] in invoked when the coroutine completes with an exception (cancelled). 27 * 28 * @param parentContext the context of the parent coroutine. 29 * @param active when `true` (by default), the coroutine is created in the _active_ state, otherwise it is created in the _new_ state. 30 * See [Job] for details. 31 * 32 * @suppress **This an internal API and should not be used from general code.** 33 */ 34 @InternalCoroutinesApi 35 public abstract class AbstractCoroutine<in T>( 36 /** 37 * The context of the parent coroutine. 38 */ 39 @JvmField 40 protected val parentContext: CoroutineContext, 41 active: Boolean = true 42 ) : JobSupport(active), Job, Continuation<T>, CoroutineScope { 43 /** 44 * The context of this coroutine that includes this coroutine as a [Job]. 45 */ 46 @Suppress("LeakingThis") 47 public final override val context: CoroutineContext = parentContext + this 48 49 /** 50 * The context of this scope which is the same as the [context] of this coroutine. 51 */ 52 public override val coroutineContext: CoroutineContext get() = context 53 54 override val isActive: Boolean get() = super.isActive 55 56 /** 57 * Initializes the parent job from the `parentContext` of this coroutine that was passed to it during construction. 58 * It shall be invoked at most once after construction after all other initialization. 59 * 60 * Invocation of this function may cause this coroutine to become cancelled if the parent is already cancelled, 61 * in which case it synchronously invokes all the corresponding handlers. 62 * @suppress **This is unstable API and it is subject to change.** 63 */ initParentJobnull64 internal fun initParentJob() { 65 initParentJobInternal(parentContext[Job]) 66 } 67 68 /** 69 * This function is invoked once when a non-active coroutine (constructed with `active` set to `false) 70 * is [started][start]. 71 */ onStartnull72 protected open fun onStart() {} 73 onStartInternalnull74 internal final override fun onStartInternal() { 75 onStart() 76 } 77 78 /** 79 * This function is invoked once when the job was completed normally with the specified [value], 80 * right before all the waiters for the coroutine's completion are notified. 81 */ onCompletednull82 protected open fun onCompleted(value: T) {} 83 84 /** 85 * This function is invoked once when the job was cancelled with the specified [cause], 86 * right before all the waiters for coroutine's completion are notified. 87 * 88 * **Note:** the state of the coroutine might not be final yet in this function and should not be queried. 89 * You can use [completionCause] and [completionCauseHandled] to recover parameters that we passed 90 * to this `onCancelled` invocation only when [isCompleted] returns `true`. 91 * 92 * @param cause The cancellation (failure) cause 93 * @param handled `true` if the exception was handled by parent (always `true` when it is a [CancellationException]) 94 */ onCancellednull95 protected open fun onCancelled(cause: Throwable, handled: Boolean) {} 96 cancellationExceptionMessagenull97 override fun cancellationExceptionMessage(): String = "$classSimpleName was cancelled" 98 99 @Suppress("UNCHECKED_CAST") 100 protected final override fun onCompletionInternal(state: Any?) { 101 if (state is CompletedExceptionally) 102 onCancelled(state.cause, state.handled) 103 else 104 onCompleted(state as T) 105 } 106 107 /** 108 * Completes execution of this with coroutine with the specified result. 109 */ resumeWithnull110 public final override fun resumeWith(result: Result<T>) { 111 val state = makeCompletingOnce(result.toState()) 112 if (state === COMPLETING_WAITING_CHILDREN) return 113 afterResume(state) 114 } 115 afterResumenull116 protected open fun afterResume(state: Any?): Unit = afterCompletion(state) 117 118 internal final override fun handleOnCompletionException(exception: Throwable) { 119 handleCoroutineException(context, exception) 120 } 121 nameStringnull122 internal override fun nameString(): String { 123 val coroutineName = context.coroutineName ?: return super.nameString() 124 return "\"$coroutineName\":${super.nameString()}" 125 } 126 127 /** 128 * Starts this coroutine with the given code [block] and [start] strategy. 129 * This function shall be invoked at most once on this coroutine. 130 * 131 * First, this function initializes parent job from the `parentContext` of this coroutine that was passed to it 132 * during construction. Second, it starts the coroutine based on [start] parameter: 133 * 134 * * [DEFAULT] uses [startCoroutineCancellable]. 135 * * [ATOMIC] uses [startCoroutine]. 136 * * [UNDISPATCHED] uses [startCoroutineUndispatched]. 137 * * [LAZY] does nothing. 138 */ startnull139 public fun start(start: CoroutineStart, block: suspend () -> T) { 140 initParentJob() 141 start(block, this) 142 } 143 144 /** 145 * Starts this coroutine with the given code [block] and [start] strategy. 146 * This function shall be invoked at most once on this coroutine. 147 * 148 * First, this function initializes parent job from the `parentContext` of this coroutine that was passed to it 149 * during construction. Second, it starts the coroutine based on [start] parameter: 150 * 151 * * [DEFAULT] uses [startCoroutineCancellable]. 152 * * [ATOMIC] uses [startCoroutine]. 153 * * [UNDISPATCHED] uses [startCoroutineUndispatched]. 154 * * [LAZY] does nothing. 155 */ startnull156 public fun <R> start(start: CoroutineStart, receiver: R, block: suspend R.() -> T) { 157 initParentJob() 158 start(block, receiver, this) 159 } 160 } 161