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