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