xref: /aosp_15_r20/external/kotlinx.coroutines/kotlinx-coroutines-core/common/src/Job.kt (revision 7a7160fed73afa6648ef8aa100d4a336fe921d9a)
1 @file:JvmMultifileClass
2 @file:JvmName("JobKt")
3 @file:Suppress("DEPRECATION_ERROR", "RedundantUnitReturnType")
4 
5 package kotlinx.coroutines
6 
7 import kotlinx.coroutines.selects.*
8 import kotlin.coroutines.*
9 import kotlin.jvm.*
10 
11 // --------------- core job interfaces ---------------
12 
13 /**
14  * A background job. Conceptually, a job is a cancellable thing with a life-cycle that
15  * culminates in its completion.
16  *
17  * Jobs can be arranged into parent-child hierarchies where cancellation
18  * of a parent leads to immediate cancellation of all its [children] recursively.
19  * Failure of a child with an exception other than [CancellationException] immediately cancels its parent and,
20  * consequently, all its other children. This behavior can be customized using [SupervisorJob].
21  *
22  * The most basic instances of `Job` interface are created like this:
23  *
24  * - **Coroutine job** is created with [launch][CoroutineScope.launch] coroutine builder.
25  *   It runs a specified block of code and completes on completion of this block.
26  * - **[CompletableJob]** is created with a `Job()` factory function.
27  *   It is completed by calling [CompletableJob.complete].
28  *
29  * Conceptually, an execution of a job does not produce a result value. Jobs are launched solely for their
30  * side effects. See [Deferred] interface for a job that produces a result.
31  *
32  * ### Job states
33  *
34  * A job has the following states:
35  *
36  * | **State**                        | [isActive] | [isCompleted] | [isCancelled] |
37  * | -------------------------------- | ---------- | ------------- | ------------- |
38  * | _New_ (optional initial state)   | `false`    | `false`       | `false`       |
39  * | _Active_ (default initial state) | `true`     | `false`       | `false`       |
40  * | _Completing_ (transient state)   | `true`     | `false`       | `false`       |
41  * | _Cancelling_ (transient state)   | `false`    | `false`       | `true`        |
42  * | _Cancelled_ (final state)        | `false`    | `true`        | `true`        |
43  * | _Completed_ (final state)        | `false`    | `true`        | `false`       |
44  *
45  * Usually, a job is created in the _active_ state (it is created and started). However, coroutine builders
46  * that provide an optional `start` parameter create a coroutine in the _new_ state when this parameter is set to
47  * [CoroutineStart.LAZY]. Such a job can be made _active_ by invoking [start] or [join].
48  *
49  * A job is _active_ while the coroutine is working or until [CompletableJob] is completed,
50  * or until it fails or cancelled.
51  *
52  * Failure of an _active_ job with an exception makes it _cancelling_.
53  * A job can be cancelled at any time with [cancel] function that forces it to transition to
54  * the _cancelling_ state immediately. The job becomes _cancelled_  when it finishes executing its work and
55  * all its children complete.
56  *
57  * Completion of an _active_ coroutine's body or a call to [CompletableJob.complete] transitions the job to
58  * the _completing_ state. It waits in the _completing_ state for all its children to complete before
59  * transitioning to the _completed_ state.
60  * Note that _completing_ state is purely internal to the job. For an outside observer a _completing_ job is still
61  * active, while internally it is waiting for its children.
62  *
63  * ```
64  *                                       wait children
65  * +-----+ start  +--------+ complete   +-------------+  finish  +-----------+
66  * | New | -----> | Active | ---------> | Completing  | -------> | Completed |
67  * +-----+        +--------+            +-------------+          +-----------+
68  *                  |  cancel / fail       |
69  *                  |     +----------------+
70  *                  |     |
71  *                  V     V
72  *              +------------+                           finish  +-----------+
73  *              | Cancelling | --------------------------------> | Cancelled |
74  *              +------------+                                   +-----------+
75  * ```
76  *
77  * A `Job` instance in the
78  * [coroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/coroutine-context.html)
79  * represents the coroutine itself.
80  *
81  * ### Cancellation cause
82  *
83  * A coroutine job is said to _complete exceptionally_ when its body throws an exception;
84  * a [CompletableJob] is completed exceptionally by calling [CompletableJob.completeExceptionally].
85  * An exceptionally completed job is cancelled and the corresponding exception becomes the _cancellation cause_ of the job.
86  *
87  * Normal cancellation of a job is distinguished from its failure by the type of this exception that caused its cancellation.
88  * A coroutine that threw [CancellationException] is considered to be _cancelled normally_.
89  * If a cancellation cause is a different exception type, then the job is considered to have _failed_.
90  * When a job has _failed_, then its parent gets cancelled with the exception of the same type,
91  * thus ensuring transparency in delegating parts of the job to its children.
92  *
93  * Note, that [cancel] function on a job only accepts [CancellationException] as a cancellation cause, thus
94  * calling [cancel] always results in a normal cancellation of a job, which does not lead to cancellation
95  * of its parent. This way, a parent can [cancel] its own children (cancelling all their children recursively, too)
96  * without cancelling itself.
97  *
98  * ### Concurrency and synchronization
99  *
100  * All functions on this interface and on all interfaces derived from it are **thread-safe** and can
101  * be safely invoked from concurrent coroutines without external synchronization.
102  *
103  * ### Not stable for inheritance
104  *
105  * **`Job` interface and all its derived interfaces are not stable for inheritance in 3rd party libraries**,
106  * as new methods might be added to this interface in the future, but is stable for use.
107  */
108 public interface Job : CoroutineContext.Element {
109     /**
110      * Key for [Job] instance in the coroutine context.
111      */
112     public companion object Key : CoroutineContext.Key<Job>
113 
114     // ------------ state query ------------
115 
116     /**
117      * Returns the parent of the current job if the parent-child relationship
118      * is established or `null` if the job has no parent or was successfully completed.
119      *
120      * Accesses to this property are not idempotent, the property becomes `null` as soon
121      * as the job is transitioned to its final state, whether it is cancelled or completed,
122      * and all job children are completed.
123      *
124      * For a coroutine, its corresponding job completes as soon as the coroutine itself
125      * and all its children are complete.
126      *
127      * @see [Job] state transitions for additional details.
128      */
129     @ExperimentalCoroutinesApi
130     public val parent: Job?
131 
132     /**
133      * Returns `true` when this job is active -- it was already started and has not completed nor was cancelled yet.
134      * The job that is waiting for its [children] to complete is still considered to be active if it
135      * was not cancelled nor failed.
136      *
137      * See [Job] documentation for more details on job states.
138      */
139     public val isActive: Boolean
140 
141     /**
142      * Returns `true` when this job has completed for any reason. A job that was cancelled or failed
143      * and has finished its execution is also considered complete. Job becomes complete only after
144      * all its [children] complete.
145      *
146      * See [Job] documentation for more details on job states.
147      */
148     public val isCompleted: Boolean
149 
150     /**
151      * Returns `true` if this job was cancelled for any reason, either by explicit invocation of [cancel] or
152      * because it had failed or its child or parent was cancelled.
153      * In the general case, it does not imply that the
154      * job has already [completed][isCompleted], because it may still be finishing whatever it was doing and
155      * waiting for its [children] to complete.
156      *
157      * See [Job] documentation for more details on cancellation and failures.
158      */
159     public val isCancelled: Boolean
160 
161     /**
162      * Returns [CancellationException] that signals the completion of this job. This function is
163      * used by [cancellable][suspendCancellableCoroutine] suspending functions. They throw exception
164      * returned by this function when they suspend in the context of this job and this job becomes _complete_.
165      *
166      * This function returns the original [cancel] cause of this job if that `cause` was an instance of
167      * [CancellationException]. Otherwise (if this job was cancelled with a cause of a different type, or
168      * was cancelled without a cause, or had completed normally), an instance of [CancellationException] is
169      * returned. The [CancellationException.cause] of the resulting [CancellationException] references
170      * the original cancellation cause that was passed to [cancel] function.
171      *
172      * This function throws [IllegalStateException] when invoked on a job that is still active.
173      *
174      * @suppress **This an internal API and should not be used from general code.**
175      */
176     @InternalCoroutinesApi
getCancellationExceptionnull177     public fun getCancellationException(): CancellationException
178 
179     // ------------ state update ------------
180 
181     /**
182      * Starts coroutine related to this job (if any) if it was not started yet.
183      * The result is `true` if this invocation actually started coroutine or `false`
184      * if it was already started or completed.
185      */
186     public fun start(): Boolean
187 
188 
189     /**
190      * Cancels this job with an optional cancellation [cause].
191      * A cause can be used to specify an error message or to provide other details on
192      * the cancellation reason for debugging purposes.
193      * See [Job] documentation for full explanation of cancellation machinery.
194      */
195     public fun cancel(cause: CancellationException? = null)
196 
197     /**
198      * @suppress This method implements old version of JVM ABI. Use [cancel].
199      */
200     @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
201     public fun cancel(): Unit = cancel(null)
202 
203     /**
204      * @suppress This method has bad semantics when cause is not a [CancellationException]. Use [cancel].
205      */
206     @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
207     public fun cancel(cause: Throwable? = null): Boolean
208 
209     // ------------ parent-child ------------
210 
211     /**
212      * Returns a sequence of this job's children.
213      *
214      * A job becomes a child of this job when it is constructed with this job in its
215      * [CoroutineContext] or using an explicit `parent` parameter.
216      *
217      * A parent-child relation has the following effect:
218      *
219      * - Cancellation of parent with [cancel] or its exceptional completion (failure)
220      *   immediately cancels all its children.
221      * - Parent cannot complete until all its children are complete. Parent waits for all its children to
222      *   complete in _completing_ or _cancelling_ state.
223      * - Uncaught exception in a child, by default, cancels parent. This applies even to
224      *   children created with [async][CoroutineScope.async] and other future-like
225      *   coroutine builders, even though their exceptions are caught and are encapsulated in their result.
226      *   This default behavior can be overridden with [SupervisorJob].
227      */
228     public val children: Sequence<Job>
229 
230     /**
231      * Attaches child job so that this job becomes its parent and
232      * returns a handle that should be used to detach it.
233      *
234      * A parent-child relation has the following effect:
235      * - Cancellation of parent with [cancel] or its exceptional completion (failure)
236      *   immediately cancels all its children.
237      * - Parent cannot complete until all its children are complete. Parent waits for all its children to
238      *   complete in _completing_ or _cancelling_ states.
239      *
240      * **A child must store the resulting [ChildHandle] and [dispose][DisposableHandle.dispose] the attachment
241      * to its parent on its own completion.**
242      *
243      * Coroutine builders and job factory functions that accept `parent` [CoroutineContext] parameter
244      * lookup a [Job] instance in the parent context and use this function to attach themselves as a child.
245      * They also store a reference to the resulting [ChildHandle] and dispose a handle when they complete.
246      *
247      * @suppress This is an internal API. This method is too error prone for public API.
248      */
249     // ChildJob and ChildHandle are made internal on purpose to further deter 3rd-party impl of Job
250     @InternalCoroutinesApi
251     public fun attachChild(child: ChildJob): ChildHandle
252 
253     // ------------ state waiting ------------
254 
255     /**
256      * Suspends the coroutine until this job is complete. This invocation resumes normally (without exception)
257      * when the job is complete for any reason and the [Job] of the invoking coroutine is still [active][isActive].
258      * This function also [starts][Job.start] the corresponding coroutine if the [Job] was still in _new_ state.
259      *
260      * Note that the job becomes complete only when all its children are complete.
261      *
262      * This suspending function is cancellable and **always** checks for a cancellation of the invoking coroutine's Job.
263      * If the [Job] of the invoking coroutine is cancelled or completed when this
264      * suspending function is invoked or while it is suspended, this function
265      * throws [CancellationException].
266      *
267      * In particular, it means that a parent coroutine invoking `join` on a child coroutine throws
268      * [CancellationException] if the child had failed, since a failure of a child coroutine cancels parent by default,
269      * unless the child was launched from within [supervisorScope].
270      *
271      * This function can be used in [select] invocation with [onJoin] clause.
272      * Use [isCompleted] to check for a completion of this job without waiting.
273      *
274      * There is [cancelAndJoin] function that combines an invocation of [cancel] and `join`.
275      */
276     public suspend fun join()
277 
278     /**
279      * Clause for [select] expression of [join] suspending function that selects when the job is complete.
280      * This clause never fails, even if the job completes exceptionally.
281      */
282     public val onJoin: SelectClause0
283 
284     // ------------ low-level state-notification ------------
285 
286     /**
287      * Registers handler that is **synchronously** invoked once on completion of this job.
288      * When the job is already complete, then the handler is immediately invoked
289      * with the job's exception or cancellation cause or `null`. Otherwise, the handler will be invoked once when this
290      * job is complete.
291      *
292      * The meaning of `cause` that is passed to the handler:
293      * - Cause is `null` when the job has completed normally.
294      * - Cause is an instance of [CancellationException] when the job was cancelled _normally_.
295      *   **It should not be treated as an error**. In particular, it should not be reported to error logs.
296      * - Otherwise, the job had _failed_.
297      *
298      * The resulting [DisposableHandle] can be used to [dispose][DisposableHandle.dispose] the
299      * registration of this handler and release its memory if its invocation is no longer needed.
300      * There is no need to dispose the handler after completion of this job. The references to
301      * all the handlers are released when this job completes.
302      *
303      * Installed [handler] should not throw any exceptions. If it does, they will get caught,
304      * wrapped into [CompletionHandlerException], and rethrown, potentially causing crash of unrelated code.
305      *
306      * **Note**: Implementation of `CompletionHandler` must be fast, non-blocking, and thread-safe.
307      * This handler can be invoked concurrently with the surrounding code.
308      * There is no guarantee on the execution context in which the [handler] is invoked.
309      */
310     public fun invokeOnCompletion(handler: CompletionHandler): DisposableHandle
311 
312     /**
313      * Kept for preserving compatibility. Shouldn't be used by anyone.
314      * @suppress
315      */
316     @InternalCoroutinesApi
317     public fun invokeOnCompletion(
318         onCancelling: Boolean = false,
319         invokeImmediately: Boolean = true,
320         handler: CompletionHandler): DisposableHandle
321 
322     // ------------ unstable internal API ------------
323 
324     /**
325      * @suppress **Error**: Operator '+' on two Job objects is meaningless.
326      * Job is a coroutine context element and `+` is a set-sum operator for coroutine contexts.
327      * The job to the right of `+` just replaces the job the left of `+`.
328      */
329     @Suppress("DeprecatedCallableAddReplaceWith")
330     @Deprecated(message = "Operator '+' on two Job objects is meaningless. " +
331         "Job is a coroutine context element and `+` is a set-sum operator for coroutine contexts. " +
332         "The job to the right of `+` just replaces the job the left of `+`.",
333         level = DeprecationLevel.ERROR)
334     public operator fun plus(other: Job): Job = other
335 }
336 
337 /**
338  * Registers a handler that is **synchronously** invoked once on cancellation or completion of this job.
339  *
340  * If the handler would have been invoked earlier if it was registered at that time, then it is invoked immediately,
341  * unless [invokeImmediately] is set to `false`.
342  *
343  * The handler is scheduled to be invoked once the job is cancelled or is complete.
344  * This behavior can be changed by setting the [onCancelling] parameter to `true`.
345  * In this case, the handler is invoked as soon as the job becomes _cancelling_ instead.
346  *
347  * The meaning of `cause` that is passed to the handler is:
348  * - It is `null` if the job has completed normally.
349  * - It is an instance of [CancellationException] if the job was cancelled _normally_.
350  *   **It should not be treated as an error**. In particular, it should not be reported to error logs.
351  * - Otherwise, the job had _failed_.
352  *
353  * The resulting [DisposableHandle] can be used to [dispose][DisposableHandle.dispose] of the registration of this
354  * handler and release its memory if its invocation is no longer needed.
355  * There is no need to dispose of the handler after completion of this job. The references to
356  * all the handlers are released when this job completes.
357  */
358 internal fun Job.invokeOnCompletion(
359     onCancelling: Boolean = false,
360     invokeImmediately: Boolean = true,
361     handler: InternalCompletionHandler
362 ): DisposableHandle = when (this) {
363     is JobSupport -> invokeOnCompletionInternal(onCancelling, invokeImmediately, handler)
364     else -> invokeOnCompletion(onCancelling, invokeImmediately, handler::invoke)
365 }
366 
367 /**
368  * Creates a job object in an active state.
369  * A failure of any child of this job immediately causes this job to fail, too, and cancels the rest of its children.
370  *
371  * To handle children failure independently of each other use [SupervisorJob].
372  *
373  * If [parent] job is specified, then this job becomes a child job of its parent and
374  * is cancelled when its parent fails or is cancelled. All this job's children are cancelled in this case, too.
375  *
376  * Conceptually, the resulting job works in the same way as the job created by the `launch { body }` invocation
377  * (see [launch]), but without any code in the body. It is active until cancelled or completed. Invocation of
378  * [CompletableJob.complete] or [CompletableJob.completeExceptionally] corresponds to the successful or
379  * failed completion of the body of the coroutine.
380  *
381  * @param parent an optional parent job.
382  */
383 @Suppress("FunctionName")
Jobnull384 public fun Job(parent: Job? = null): CompletableJob = JobImpl(parent)
385 
386 /** @suppress Binary compatibility only */
387 @Suppress("FunctionName")
388 @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
389 @JvmName("Job")
390 public fun Job0(parent: Job? = null): Job = Job(parent)
391 
392 /**
393  * A handle to an allocated object that can be disposed to make it eligible for garbage collection.
394  */
395 public fun interface DisposableHandle {
396     /**
397      * Disposes the corresponding object, making it eligible for garbage collection.
398      * Repeated invocation of this function has no effect.
399      */
400     public fun dispose()
401 }
402 
403 // -------------------- Parent-child communication --------------------
404 
405 /**
406  * A reference that parent receives from its child so that it can report its cancellation.
407  *
408  * @suppress **This is unstable API and it is subject to change.**
409  */
410 @InternalCoroutinesApi
411 @Deprecated(level = DeprecationLevel.ERROR, message = "This is internal API and may be removed in the future releases")
412 public interface ChildJob : Job {
413     /**
414      * Parent is cancelling its child by invoking this method.
415      * Child finds the cancellation cause using [ParentJob.getChildJobCancellationCause].
416      * This method does nothing is the child is already being cancelled.
417      *
418      * @suppress **This is unstable API and it is subject to change.**
419      */
420     @InternalCoroutinesApi
parentCancellednull421     public fun parentCancelled(parentJob: ParentJob)
422 }
423 
424 /**
425  * A reference that child receives from its parent when it is being cancelled by the parent.
426  *
427  * @suppress **This is unstable API and it is subject to change.**
428  */
429 @InternalCoroutinesApi
430 @Deprecated(level = DeprecationLevel.ERROR, message = "This is internal API and may be removed in the future releases")
431 public interface ParentJob : Job {
432     /**
433      * Child job is using this method to learn its cancellation cause when the parent cancels it with [ChildJob.parentCancelled].
434      * This method is invoked only if the child was not already being cancelled.
435      *
436      * Note that [CancellationException] is the method's return type: if child is cancelled by its parent,
437      * then the original exception is **already** handled by either the parent or the original source of failure.
438      *
439      * @suppress **This is unstable API and it is subject to change.**
440      */
441     @InternalCoroutinesApi
442     public fun getChildJobCancellationCause(): CancellationException
443 }
444 
445 /**
446  * A handle that child keep onto its parent so that it is able to report its cancellation.
447  *
448  * @suppress **This is unstable API and it is subject to change.**
449  */
450 @InternalCoroutinesApi
451 @Deprecated(level = DeprecationLevel.ERROR, message = "This is internal API and may be removed in the future releases")
452 public interface ChildHandle : DisposableHandle {
453 
454     /**
455      * Returns the parent of the current parent-child relationship.
456      * @suppress **This is unstable API and it is subject to change.**
457      */
458     @InternalCoroutinesApi
459     public val parent: Job?
460 
461     /**
462      * Child is cancelling its parent by invoking this method.
463      * This method is invoked by the child twice. The first time child report its root cause as soon as possible,
464      * so that all its siblings and the parent can start cancelling their work asap. The second time
465      * child invokes this method when it had aggregated and determined its final cancellation cause.
466      *
467      * @suppress **This is unstable API and it is subject to change.**
468      */
469     @InternalCoroutinesApi
childCancellednull470     public fun childCancelled(cause: Throwable): Boolean
471 }
472 
473 // -------------------- Job extensions --------------------
474 
475 /**
476  * Disposes a specified [handle] when this job is complete.
477  *
478  * This is a shortcut for the following code with slightly more efficient implementation (one fewer object created).
479  * ```
480  * invokeOnCompletion { handle.dispose() }
481  * ```
482  */
483 internal fun Job.disposeOnCompletion(handle: DisposableHandle): DisposableHandle =
484     invokeOnCompletion(handler = DisposeOnCompletion(handle))
485 
486 /**
487  * Cancels the job and suspends the invoking coroutine until the cancelled job is complete.
488  *
489  * This suspending function is cancellable and **always** checks for a cancellation of the invoking coroutine's Job.
490  * If the [Job] of the invoking coroutine is cancelled or completed when this
491  * suspending function is invoked or while it is suspended, this function
492  * throws [CancellationException].
493  *
494  * In particular, it means that a parent coroutine invoking `cancelAndJoin` on a child coroutine throws
495  * [CancellationException] if the child had failed, since a failure of a child coroutine cancels parent by default,
496  * unless the child was launched from within [supervisorScope].
497  *
498  * This is a shortcut for the invocation of [cancel][Job.cancel] followed by [join][Job.join].
499  */
500 public suspend fun Job.cancelAndJoin() {
501     cancel()
502     return join()
503 }
504 
505 /**
506  * Cancels all [children][Job.children] jobs of this coroutine using [Job.cancel] for all of them
507  * with an optional cancellation [cause].
508  * Unlike [Job.cancel] on this job as a whole, the state of this job itself is not affected.
509  */
cancelChildrennull510 public fun Job.cancelChildren(cause: CancellationException? = null) {
511     children.forEach { it.cancel(cause) }
512 }
513 
514 /**
515  * @suppress This method implements old version of JVM ABI. Use [cancel].
516  */
517 @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
cancelChildrennull518 public fun Job.cancelChildren(): Unit = cancelChildren(null)
519 
520 /**
521  * @suppress This method has bad semantics when cause is not a [CancellationException]. Use [Job.cancelChildren].
522  */
523 @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
524 public fun Job.cancelChildren(cause: Throwable? = null) {
525     children.forEach { (it as? JobSupport)?.cancelInternal(cause.orCancellation(this)) }
526 }
527 
528 // -------------------- CoroutineContext extensions --------------------
529 
530 /**
531  * Returns `true` when the [Job] of the coroutine in this context is still active
532  * (has not completed and was not cancelled yet) or the context does not have a [Job] in it.
533  *
534  * Check this property in long-running computation loops to support cancellation
535  * when [CoroutineScope.isActive] is not available:
536  *
537  * ```
538  * while (coroutineContext.isActive) {
539  *     // do some computation
540  * }
541  * ```
542  *
543  * The `coroutineContext.isActive` expression is a shortcut for `get(Job)?.isActive ?: true`.
544  * See [Job.isActive].
545  */
546 public val CoroutineContext.isActive: Boolean
547     get() = get(Job)?.isActive ?: true
548 
549 /**
550  * Cancels [Job] of this context with an optional cancellation cause.
551  * See [Job.cancel] for details.
552  */
cancelnull553 public fun CoroutineContext.cancel(cause: CancellationException? = null) {
554     this[Job]?.cancel(cause)
555 }
556 
557 /**
558  * @suppress This method implements old version of JVM ABI. Use [CoroutineContext.cancel].
559  */
560 @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
cancelnull561 public fun CoroutineContext.cancel(): Unit = cancel(null)
562 
563 /**
564  * Ensures that current job is [active][Job.isActive].
565  * If the job is no longer active, throws [CancellationException].
566  * If the job was cancelled, thrown exception contains the original cancellation cause.
567  *
568  * This method is a drop-in replacement for the following code, but with more precise exception:
569  * ```
570  * if (!job.isActive) {
571  *     throw CancellationException()
572  * }
573  * ```
574  */
575 public fun Job.ensureActive(): Unit {
576     if (!isActive) throw getCancellationException()
577 }
578 
579 /**
580  * Ensures that job in the current context is [active][Job.isActive].
581  *
582  * If the job is no longer active, throws [CancellationException].
583  * If the job was cancelled, thrown exception contains the original cancellation cause.
584  * This function does not do anything if there is no [Job] in the context, since such a coroutine cannot be cancelled.
585  *
586  * This method is a drop-in replacement for the following code, but with more precise exception:
587  * ```
588  * if (!isActive) {
589  *     throw CancellationException()
590  * }
591  * ```
592  */
ensureActivenull593 public fun CoroutineContext.ensureActive() {
594     get(Job)?.ensureActive()
595 }
596 
597 /**
598  * Cancels current job, including all its children with a specified diagnostic error [message].
599  * A [cause] can be specified to provide additional details on a cancellation reason for debugging purposes.
600  */
cancelnull601 public fun Job.cancel(message: String, cause: Throwable? = null): Unit = cancel(CancellationException(message, cause))
602 
603 /**
604  * @suppress This method has bad semantics when cause is not a [CancellationException]. Use [CoroutineContext.cancel].
605  */
606 @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
607 public fun CoroutineContext.cancel(cause: Throwable? = null): Boolean {
608     val job = this[Job] as? JobSupport ?: return false
609     job.cancelInternal(cause.orCancellation(job))
610     return true
611 }
612 
613 /**
614  * Cancels all children of the [Job] in this context, without touching the state of this job itself
615  * with an optional cancellation cause. See [Job.cancel].
616  * It does not do anything if there is no job in the context or it has no children.
617  */
cancelChildrennull618 public fun CoroutineContext.cancelChildren(cause: CancellationException? = null) {
619     this[Job]?.children?.forEach { it.cancel(cause) }
620 }
621 
622 /**
623  * @suppress This method implements old version of JVM ABI. Use [CoroutineContext.cancelChildren].
624  */
625 @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
cancelChildrennull626 public fun CoroutineContext.cancelChildren(): Unit = cancelChildren(null)
627 
628 /**
629  * Retrieves the current [Job] instance from the given [CoroutineContext] or
630  * throws [IllegalStateException] if no job is present in the context.
631  *
632  * This method is a short-cut for `coroutineContext[Job]!!` and should be used only when it is known in advance that
633  * the context does have instance of the job in it.
634  */
635 public val CoroutineContext.job: Job get() = get(Job) ?: error("Current context doesn't contain Job in it: $this")
636 
637 /**
638  * @suppress This method has bad semantics when cause is not a [CancellationException]. Use [CoroutineContext.cancelChildren].
639  */
640 @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
641 public fun CoroutineContext.cancelChildren(cause: Throwable? = null) {
642     val job = this[Job] ?: return
643     job.children.forEach { (it as? JobSupport)?.cancelInternal(cause.orCancellation(job)) }
644 }
645 
Throwablenull646 private fun Throwable?.orCancellation(job: Job): Throwable = this ?: JobCancellationException("Job was cancelled", null, job)
647 
648 /**
649  * No-op implementation of [DisposableHandle].
650  * @suppress **This an internal API and should not be used from general code.**
651  */
652 @InternalCoroutinesApi
653 public object NonDisposableHandle : DisposableHandle, ChildHandle {
654 
655     override val parent: Job? get() = null
656 
657     /**
658      * Does not do anything.
659      * @suppress
660      */
661     override fun dispose() {}
662 
663     /**
664      * Returns `false`.
665      * @suppress
666      */
667     override fun childCancelled(cause: Throwable): Boolean = false
668 
669     /**
670      * Returns "NonDisposableHandle" string.
671      * @suppress
672      */
673     override fun toString(): String = "NonDisposableHandle"
674 }
675