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