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