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 @OptIn(ExperimentalSubclassOptIn::class)
104 @SubclassOptInRequired(InternalForInheritanceCoroutinesApi::class)
105 public interface Job : CoroutineContext.Element {
106 /**
107 * Key for [Job] instance in the coroutine context.
108 */
109 public companion object Key : CoroutineContext.Key<Job>
110
111 // ------------ state query ------------
112
113 /**
114 * Returns the parent of the current job if the parent-child relationship
115 * is established or `null` if the job has no parent or was successfully completed.
116 *
117 * Accesses to this property are not idempotent, the property becomes `null` as soon
118 * as the job is transitioned to its final state, whether it is cancelled or completed,
119 * and all job children are completed.
120 *
121 * For a coroutine, its corresponding job completes as soon as the coroutine itself
122 * and all its children are complete.
123 *
124 * @see [Job] state transitions for additional details.
125 */
126 @ExperimentalCoroutinesApi
127 public val parent: Job?
128
129 /**
130 * Returns `true` when this job is active -- it was already started and has not completed nor was cancelled yet.
131 * The job that is waiting for its [children] to complete is still considered to be active if it
132 * was not cancelled nor failed.
133 *
134 * See [Job] documentation for more details on job states.
135 */
136 public val isActive: Boolean
137
138 /**
139 * Returns `true` when this job has completed for any reason. A job that was cancelled or failed
140 * and has finished its execution is also considered complete. Job becomes complete only after
141 * all its [children] complete.
142 *
143 * See [Job] documentation for more details on job states.
144 */
145 public val isCompleted: Boolean
146
147 /**
148 * Returns `true` if this job was cancelled for any reason, either by explicit invocation of [cancel] or
149 * because it had failed or its child or parent was cancelled.
150 * In the general case, it does not imply that the
151 * job has already [completed][isCompleted], because it may still be finishing whatever it was doing and
152 * waiting for its [children] to complete.
153 *
154 * See [Job] documentation for more details on cancellation and failures.
155 */
156 public val isCancelled: Boolean
157
158 /**
159 * Returns [CancellationException] that signals the completion of this job. This function is
160 * used by [cancellable][suspendCancellableCoroutine] suspending functions. They throw exception
161 * returned by this function when they suspend in the context of this job and this job becomes _complete_.
162 *
163 * This function returns the original [cancel] cause of this job if that `cause` was an instance of
164 * [CancellationException]. Otherwise (if this job was cancelled with a cause of a different type, or
165 * was cancelled without a cause, or had completed normally), an instance of [CancellationException] is
166 * returned. The [CancellationException.cause] of the resulting [CancellationException] references
167 * the original cancellation cause that was passed to [cancel] function.
168 *
169 * This function throws [IllegalStateException] when invoked on a job that is still active.
170 *
171 * @suppress **This an internal API and should not be used from general code.**
172 */
173 @InternalCoroutinesApi
getCancellationExceptionnull174 public fun getCancellationException(): CancellationException
175
176 // ------------ state update ------------
177
178 /**
179 * Starts coroutine related to this job (if any) if it was not started yet.
180 * The result is `true` if this invocation actually started coroutine or `false`
181 * if it was already started or completed.
182 */
183 public fun start(): Boolean
184
185
186 /**
187 * Cancels this job with an optional cancellation [cause].
188 * A cause can be used to specify an error message or to provide other details on
189 * the cancellation reason for debugging purposes.
190 * See [Job] documentation for full explanation of cancellation machinery.
191 */
192 public fun cancel(cause: CancellationException? = null)
193
194 /**
195 * @suppress This method implements old version of JVM ABI. Use [cancel].
196 */
197 @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
198 public fun cancel(): Unit = cancel(null)
199
200 /**
201 * @suppress This method has bad semantics when cause is not a [CancellationException]. Use [cancel].
202 */
203 @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
204 public fun cancel(cause: Throwable? = null): Boolean
205
206 // ------------ parent-child ------------
207
208 /**
209 * Returns a sequence of this job's children.
210 *
211 * A job becomes a child of this job when it is constructed with this job in its
212 * [CoroutineContext] or using an explicit `parent` parameter.
213 *
214 * A parent-child relation has the following effect:
215 *
216 * - Cancellation of parent with [cancel] or its exceptional completion (failure)
217 * immediately cancels all its children.
218 * - Parent cannot complete until all its children are complete. Parent waits for all its children to
219 * complete in _completing_ or _cancelling_ state.
220 * - Uncaught exception in a child, by default, cancels parent. This applies even to
221 * children created with [async][CoroutineScope.async] and other future-like
222 * coroutine builders, even though their exceptions are caught and are encapsulated in their result.
223 * This default behavior can be overridden with [SupervisorJob].
224 */
225 public val children: Sequence<Job>
226
227 /**
228 * Attaches child job so that this job becomes its parent and
229 * returns a handle that should be used to detach it.
230 *
231 * A parent-child relation has the following effect:
232 * - Cancellation of parent with [cancel] or its exceptional completion (failure)
233 * immediately cancels all its children.
234 * - Parent cannot complete until all its children are complete. Parent waits for all its children to
235 * complete in _completing_ or _cancelling_ states.
236 *
237 * **A child must store the resulting [ChildHandle] and [dispose][DisposableHandle.dispose] the attachment
238 * to its parent on its own completion.**
239 *
240 * Coroutine builders and job factory functions that accept `parent` [CoroutineContext] parameter
241 * lookup a [Job] instance in the parent context and use this function to attach themselves as a child.
242 * They also store a reference to the resulting [ChildHandle] and dispose a handle when they complete.
243 *
244 * @suppress This is an internal API. This method is too error prone for public API.
245 */
246 // ChildJob and ChildHandle are made internal on purpose to further deter 3rd-party impl of Job
247 @InternalCoroutinesApi
248 public fun attachChild(child: ChildJob): ChildHandle
249
250 // ------------ state waiting ------------
251
252 /**
253 * Suspends the coroutine until this job is complete. This invocation resumes normally (without exception)
254 * when the job is complete for any reason and the [Job] of the invoking coroutine is still [active][isActive].
255 * This function also [starts][Job.start] the corresponding coroutine if the [Job] was still in _new_ state.
256 *
257 * Note that the job becomes complete only when all its children are complete.
258 *
259 * This suspending function is cancellable and **always** checks for a cancellation of the invoking coroutine's Job.
260 * If the [Job] of the invoking coroutine is cancelled or completed when this
261 * suspending function is invoked or while it is suspended, this function
262 * throws [CancellationException].
263 *
264 * In particular, it means that a parent coroutine invoking `join` on a child coroutine throws
265 * [CancellationException] if the child had failed, since a failure of a child coroutine cancels parent by default,
266 * unless the child was launched from within [supervisorScope].
267 *
268 * This function can be used in [select] invocation with [onJoin] clause.
269 * Use [isCompleted] to check for a completion of this job without waiting.
270 *
271 * There is [cancelAndJoin] function that combines an invocation of [cancel] and `join`.
272 */
273 public suspend fun join()
274
275 /**
276 * Clause for [select] expression of [join] suspending function that selects when the job is complete.
277 * This clause never fails, even if the job completes exceptionally.
278 */
279 public val onJoin: SelectClause0
280
281 // ------------ low-level state-notification ------------
282
283 /**
284 * Registers handler that is **synchronously** invoked once on completion of this job.
285 * When the job is already complete, then the handler is immediately invoked
286 * with the job's exception or cancellation cause or `null`. Otherwise, the handler will be invoked once when this
287 * job is complete.
288 *
289 * The meaning of `cause` that is passed to the handler:
290 * - Cause is `null` when the job has completed normally.
291 * - Cause is an instance of [CancellationException] when the job was cancelled _normally_.
292 * **It should not be treated as an error**. In particular, it should not be reported to error logs.
293 * - Otherwise, the job had _failed_.
294 *
295 * The resulting [DisposableHandle] can be used to [dispose][DisposableHandle.dispose] the
296 * registration of this handler and release its memory if its invocation is no longer needed.
297 * There is no need to dispose the handler after completion of this job. The references to
298 * all the handlers are released when this job completes.
299 *
300 * Installed [handler] should not throw any exceptions. If it does, they will get caught,
301 * wrapped into [CompletionHandlerException], and rethrown, potentially causing crash of unrelated code.
302 *
303 * **Note**: Implementation of `CompletionHandler` must be fast, non-blocking, and thread-safe.
304 * This handler can be invoked concurrently with the surrounding code.
305 * There is no guarantee on the execution context in which the [handler] is invoked.
306 */
307 public fun invokeOnCompletion(handler: CompletionHandler): DisposableHandle
308
309 /**
310 * Kept for preserving compatibility. Shouldn't be used by anyone.
311 * @suppress
312 */
313 @InternalCoroutinesApi
314 public fun invokeOnCompletion(
315 onCancelling: Boolean = false,
316 invokeImmediately: Boolean = true,
317 handler: CompletionHandler): DisposableHandle
318
319 // ------------ unstable internal API ------------
320
321 /**
322 * @suppress **Error**: Operator '+' on two Job objects is meaningless.
323 * Job is a coroutine context element and `+` is a set-sum operator for coroutine contexts.
324 * The job to the right of `+` just replaces the job the left of `+`.
325 */
326 @Suppress("DeprecatedCallableAddReplaceWith")
327 @Deprecated(message = "Operator '+' on two Job objects is meaningless. " +
328 "Job is a coroutine context element and `+` is a set-sum operator for coroutine contexts. " +
329 "The job to the right of `+` just replaces the job the left of `+`.",
330 level = DeprecationLevel.ERROR)
331 public operator fun plus(other: Job): Job = other
332 }
333
334 /**
335 * Registers a handler that is **synchronously** invoked once on cancellation or completion of this job.
336 *
337 * If the handler would have been invoked earlier if it was registered at that time, then it is invoked immediately,
338 * unless [invokeImmediately] is set to `false`.
339 *
340 * The meaning of `cause` that is passed to the handler is:
341 * - It is `null` if the job has completed normally.
342 * - It is an instance of [CancellationException] if the job was cancelled _normally_.
343 * **It should not be treated as an error**. In particular, it should not be reported to error logs.
344 * - Otherwise, the job had _failed_.
345 *
346 * The resulting [DisposableHandle] can be used to [dispose][DisposableHandle.dispose] of the registration of this
347 * handler and release its memory if its invocation is no longer needed.
348 * There is no need to dispose of the handler after completion of this job. The references to
349 * all the handlers are released when this job completes.
350 */
351 internal fun Job.invokeOnCompletion(
352 invokeImmediately: Boolean = true,
353 handler: JobNode,
354 ): DisposableHandle = when (this) {
355 is JobSupport -> invokeOnCompletionInternal(invokeImmediately, handler)
356 else -> invokeOnCompletion(handler.onCancelling, invokeImmediately, handler::invoke)
357 }
358
359 /**
360 * Creates a job object in an active state.
361 * A failure of any child of this job immediately causes this job to fail, too, and cancels the rest of its children.
362 *
363 * To handle children failure independently of each other use [SupervisorJob].
364 *
365 * If [parent] job is specified, then this job becomes a child job of its parent and
366 * is cancelled when its parent fails or is cancelled. All this job's children are cancelled in this case, too.
367 *
368 * Conceptually, the resulting job works in the same way as the job created by the `launch { body }` invocation
369 * (see [launch]), but without any code in the body. It is active until cancelled or completed. Invocation of
370 * [CompletableJob.complete] or [CompletableJob.completeExceptionally] corresponds to the successful or
371 * failed completion of the body of the coroutine.
372 *
373 * @param parent an optional parent job.
374 */
375 @Suppress("FunctionName")
Jobnull376 public fun Job(parent: Job? = null): CompletableJob = JobImpl(parent)
377
378 /** @suppress Binary compatibility only */
379 @Suppress("FunctionName")
380 @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
381 @JvmName("Job")
382 public fun Job0(parent: Job? = null): Job = Job(parent)
383
384 /**
385 * A handle to an allocated object that can be disposed to make it eligible for garbage collection.
386 */
387 public fun interface DisposableHandle {
388 /**
389 * Disposes the corresponding object, making it eligible for garbage collection.
390 * Repeated invocation of this function has no effect.
391 */
392 public fun dispose()
393 }
394
395 // -------------------- Parent-child communication --------------------
396
397 /**
398 * A reference that parent receives from its child so that it can report its cancellation.
399 *
400 * @suppress **This is unstable API and it is subject to change.**
401 */
402 @InternalCoroutinesApi
403 @Deprecated(level = DeprecationLevel.ERROR, message = "This is internal API and may be removed in the future releases")
404 @OptIn(InternalForInheritanceCoroutinesApi::class)
405 public interface ChildJob : Job {
406 /**
407 * Parent is cancelling its child by invoking this method.
408 * Child finds the cancellation cause using [ParentJob.getChildJobCancellationCause].
409 * This method does nothing is the child is already being cancelled.
410 *
411 * @suppress **This is unstable API and it is subject to change.**
412 */
413 @InternalCoroutinesApi
parentCancellednull414 public fun parentCancelled(parentJob: ParentJob)
415 }
416
417 /**
418 * A reference that child receives from its parent when it is being cancelled by the parent.
419 *
420 * @suppress **This is unstable API and it is subject to change.**
421 */
422 @InternalCoroutinesApi
423 @Deprecated(level = DeprecationLevel.ERROR, message = "This is internal API and may be removed in the future releases")
424 @OptIn(InternalForInheritanceCoroutinesApi::class)
425 public interface ParentJob : Job {
426 /**
427 * Child job is using this method to learn its cancellation cause when the parent cancels it with [ChildJob.parentCancelled].
428 * This method is invoked only if the child was not already being cancelled.
429 *
430 * Note that [CancellationException] is the method's return type: if child is cancelled by its parent,
431 * then the original exception is **already** handled by either the parent or the original source of failure.
432 *
433 * @suppress **This is unstable API and it is subject to change.**
434 */
435 @InternalCoroutinesApi
436 public fun getChildJobCancellationCause(): CancellationException
437 }
438
439 /**
440 * A handle that child keep onto its parent so that it is able to report its cancellation.
441 *
442 * @suppress **This is unstable API and it is subject to change.**
443 */
444 @InternalCoroutinesApi
445 @Deprecated(level = DeprecationLevel.ERROR, message = "This is internal API and may be removed in the future releases")
446 public interface ChildHandle : DisposableHandle {
447
448 /**
449 * Returns the parent of the current parent-child relationship.
450 * @suppress **This is unstable API and it is subject to change.**
451 */
452 @InternalCoroutinesApi
453 public val parent: Job?
454
455 /**
456 * Child is cancelling its parent by invoking this method.
457 * This method is invoked by the child twice. The first time child report its root cause as soon as possible,
458 * so that all its siblings and the parent can start cancelling their work asap. The second time
459 * child invokes this method when it had aggregated and determined its final cancellation cause.
460 *
461 * @suppress **This is unstable API and it is subject to change.**
462 */
463 @InternalCoroutinesApi
childCancellednull464 public fun childCancelled(cause: Throwable): Boolean
465 }
466
467 // -------------------- Job extensions --------------------
468
469 /**
470 * Disposes a specified [handle] when this job is complete.
471 *
472 * This is a shortcut for the following code with slightly more efficient implementation (one fewer object created).
473 * ```
474 * invokeOnCompletion { handle.dispose() }
475 * ```
476 */
477 internal fun Job.disposeOnCompletion(handle: DisposableHandle): DisposableHandle =
478 invokeOnCompletion(handler = DisposeOnCompletion(handle))
479
480 /**
481 * Cancels the job and suspends the invoking coroutine until the cancelled job is complete.
482 *
483 * This suspending function is cancellable and **always** checks for a cancellation of the invoking coroutine's Job.
484 * If the [Job] of the invoking coroutine is cancelled or completed when this
485 * suspending function is invoked or while it is suspended, this function
486 * throws [CancellationException].
487 *
488 * In particular, it means that a parent coroutine invoking `cancelAndJoin` on a child coroutine throws
489 * [CancellationException] if the child had failed, since a failure of a child coroutine cancels parent by default,
490 * unless the child was launched from within [supervisorScope].
491 *
492 * This is a shortcut for the invocation of [cancel][Job.cancel] followed by [join][Job.join].
493 */
494 public suspend fun Job.cancelAndJoin() {
495 cancel()
496 return join()
497 }
498
499 /**
500 * Cancels all [children][Job.children] jobs of this coroutine using [Job.cancel] for all of them
501 * with an optional cancellation [cause].
502 * Unlike [Job.cancel] on this job as a whole, the state of this job itself is not affected.
503 */
cancelChildrennull504 public fun Job.cancelChildren(cause: CancellationException? = null) {
505 children.forEach { it.cancel(cause) }
506 }
507
508 /**
509 * @suppress This method implements old version of JVM ABI. Use [cancel].
510 */
511 @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
cancelChildrennull512 public fun Job.cancelChildren(): Unit = cancelChildren(null)
513
514 /**
515 * @suppress This method has bad semantics when cause is not a [CancellationException]. Use [Job.cancelChildren].
516 */
517 @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
518 public fun Job.cancelChildren(cause: Throwable? = null) {
519 children.forEach { (it as? JobSupport)?.cancelInternal(cause.orCancellation(this)) }
520 }
521
522 // -------------------- CoroutineContext extensions --------------------
523
524 /**
525 * Returns `true` when the [Job] of the coroutine in this context is still active
526 * (has not completed and was not cancelled yet) or the context does not have a [Job] in it.
527 *
528 * Check this property in long-running computation loops to support cancellation
529 * when [CoroutineScope.isActive] is not available:
530 *
531 * ```
532 * while (coroutineContext.isActive) {
533 * // do some computation
534 * }
535 * ```
536 *
537 * The `coroutineContext.isActive` expression is a shortcut for `get(Job)?.isActive ?: true`.
538 * See [Job.isActive].
539 */
540 public val CoroutineContext.isActive: Boolean
541 get() = get(Job)?.isActive ?: true
542
543 /**
544 * Cancels [Job] of this context with an optional cancellation cause.
545 * See [Job.cancel] for details.
546 */
cancelnull547 public fun CoroutineContext.cancel(cause: CancellationException? = null) {
548 this[Job]?.cancel(cause)
549 }
550
551 /**
552 * @suppress This method implements old version of JVM ABI. Use [CoroutineContext.cancel].
553 */
554 @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
cancelnull555 public fun CoroutineContext.cancel(): Unit = cancel(null)
556
557 /**
558 * Ensures that current job is [active][Job.isActive].
559 * If the job is no longer active, throws [CancellationException].
560 * If the job was cancelled, thrown exception contains the original cancellation cause.
561 *
562 * This method is a drop-in replacement for the following code, but with more precise exception:
563 * ```
564 * if (!job.isActive) {
565 * throw CancellationException()
566 * }
567 * ```
568 */
569 public fun Job.ensureActive(): Unit {
570 if (!isActive) throw getCancellationException()
571 }
572
573 /**
574 * Ensures that job in the current context is [active][Job.isActive].
575 *
576 * If the job is no longer active, throws [CancellationException].
577 * If the job was cancelled, thrown exception contains the original cancellation cause.
578 * This function does not do anything if there is no [Job] in the context, since such a coroutine cannot be cancelled.
579 *
580 * This method is a drop-in replacement for the following code, but with more precise exception:
581 * ```
582 * if (!isActive) {
583 * throw CancellationException()
584 * }
585 * ```
586 */
ensureActivenull587 public fun CoroutineContext.ensureActive() {
588 get(Job)?.ensureActive()
589 }
590
591 /**
592 * Cancels current job, including all its children with a specified diagnostic error [message].
593 * A [cause] can be specified to provide additional details on a cancellation reason for debugging purposes.
594 */
cancelnull595 public fun Job.cancel(message: String, cause: Throwable? = null): Unit = cancel(CancellationException(message, cause))
596
597 /**
598 * @suppress This method has bad semantics when cause is not a [CancellationException]. Use [CoroutineContext.cancel].
599 */
600 @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
601 public fun CoroutineContext.cancel(cause: Throwable? = null): Boolean {
602 val job = this[Job] as? JobSupport ?: return false
603 job.cancelInternal(cause.orCancellation(job))
604 return true
605 }
606
607 /**
608 * Cancels all children of the [Job] in this context, without touching the state of this job itself
609 * with an optional cancellation cause. See [Job.cancel].
610 * It does not do anything if there is no job in the context or it has no children.
611 */
cancelChildrennull612 public fun CoroutineContext.cancelChildren(cause: CancellationException? = null) {
613 this[Job]?.children?.forEach { it.cancel(cause) }
614 }
615
616 /**
617 * @suppress This method implements old version of JVM ABI. Use [CoroutineContext.cancelChildren].
618 */
619 @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
cancelChildrennull620 public fun CoroutineContext.cancelChildren(): Unit = cancelChildren(null)
621
622 /**
623 * Retrieves the current [Job] instance from the given [CoroutineContext] or
624 * throws [IllegalStateException] if no job is present in the context.
625 *
626 * This method is a short-cut for `coroutineContext[Job]!!` and should be used only when it is known in advance that
627 * the context does have instance of the job in it.
628 */
629 public val CoroutineContext.job: Job get() = get(Job) ?: error("Current context doesn't contain Job in it: $this")
630
631 /**
632 * @suppress This method has bad semantics when cause is not a [CancellationException]. Use [CoroutineContext.cancelChildren].
633 */
634 @Deprecated(level = DeprecationLevel.HIDDEN, message = "Since 1.2.0, binary compatibility with versions <= 1.1.x")
635 public fun CoroutineContext.cancelChildren(cause: Throwable? = null) {
636 val job = this[Job] ?: return
637 job.children.forEach { (it as? JobSupport)?.cancelInternal(cause.orCancellation(job)) }
638 }
639
Throwablenull640 private fun Throwable?.orCancellation(job: Job): Throwable = this ?: JobCancellationException("Job was cancelled", null, job)
641
642 /**
643 * No-op implementation of [DisposableHandle].
644 * @suppress **This an internal API and should not be used from general code.**
645 */
646 @InternalCoroutinesApi
647 public object NonDisposableHandle : DisposableHandle, ChildHandle {
648
649 override val parent: Job? get() = null
650
651 /**
652 * Does not do anything.
653 * @suppress
654 */
655 override fun dispose() {}
656
657 /**
658 * Returns `false`.
659 * @suppress
660 */
661 override fun childCancelled(cause: Throwable): Boolean = false
662
663 /**
664 * Returns "NonDisposableHandle" string.
665 * @suppress
666 */
667 override fun toString(): String = "NonDisposableHandle"
668 }
669
670 private class DisposeOnCompletion(
671 private val handle: DisposableHandle
672 ) : JobNode() {
673 override val onCancelling get() = false
674
invokenull675 override fun invoke(cause: Throwable?) = handle.dispose()
676 }
677