Skip to content

Commit

Permalink
Reword the prompt cancellation guarantee
Browse files Browse the repository at this point in the history
Emphasize the fact that the function fails to resume *even if it
already completed* but wasn't dispatched yet. Before the change,
when translating the documentation to Chinese, there could be a
confusion as to what "it will not resume successfully" means.

Fixes #3888
  • Loading branch information
dkhalanskyjb committed Feb 15, 2024
1 parent 8eb4963 commit 92df6e1
Show file tree
Hide file tree
Showing 12 changed files with 101 additions and 96 deletions.
36 changes: 16 additions & 20 deletions kotlinx-coroutines-core/common/src/Await.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ import kotlin.coroutines.*
* This function is **not** equivalent to `deferreds.map { it.await() }` which fails only when it sequentially
* gets to wait for the failing deferred, while this `awaitAll` fails immediately as soon as any of the deferreds fail.
*
* This suspending function is cancellable.
* If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting,
* this function immediately resumes with [CancellationException].
* There is a **prompt cancellation guarantee**. If the job was cancelled while this function was
* suspended, it will not resume successfully. See [suspendCancellableCoroutine] documentation for low-level details.
* This suspending function is cancellable: if the [Job] of the current coroutine is cancelled or completed while this
* suspending function is waiting, this function immediately resumes with [CancellationException].
* There is a **prompt cancellation guarantee**: even if this function is ready to return the result, but was cancelled
* while suspended, [CancellationException] will be thrown. See [suspendCancellableCoroutine] for low-level details.
*/
public suspend fun <T> awaitAll(vararg deferreds: Deferred<T>): List<T> =
if (deferreds.isEmpty()) emptyList() else AwaitAll(deferreds).await()
Expand All @@ -28,11 +27,10 @@ public suspend fun <T> awaitAll(vararg deferreds: Deferred<T>): List<T> =
* This function is **not** equivalent to `this.map { it.await() }` which fails only when it sequentially
* gets to wait for the failing deferred, while this `awaitAll` fails immediately as soon as any of the deferreds fail.
*
* This suspending function is cancellable.
* If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting,
* this function immediately resumes with [CancellationException].
* There is a **prompt cancellation guarantee**. If the job was cancelled while this function was
* suspended, it will not resume successfully. See [suspendCancellableCoroutine] documentation for low-level details.
* This suspending function is cancellable: if the [Job] of the current coroutine is cancelled or completed while this
* suspending function is waiting, this function immediately resumes with [CancellationException].
* There is a **prompt cancellation guarantee**: even if this function is ready to return the result, but was cancelled
* while suspended, [CancellationException] will be thrown. See [suspendCancellableCoroutine] for low-level details.
*/
public suspend fun <T> Collection<Deferred<T>>.awaitAll(): List<T> =
if (isEmpty()) emptyList() else AwaitAll(toTypedArray()).await()
Expand All @@ -41,23 +39,21 @@ public suspend fun <T> Collection<Deferred<T>>.awaitAll(): List<T> =
* Suspends current coroutine until all given jobs are complete.
* This method is semantically equivalent to joining all given jobs one by one with `jobs.forEach { it.join() }`.
*
* This suspending function is cancellable.
* If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting,
* this function immediately resumes with [CancellationException].
* There is a **prompt cancellation guarantee**. If the job was cancelled while this function was
* suspended, it will not resume successfully. See [suspendCancellableCoroutine] documentation for low-level details.
* This suspending function is cancellable: if the [Job] of the current coroutine is cancelled or completed while this
* suspending function is waiting, this function immediately resumes with [CancellationException].
* There is a **prompt cancellation guarantee**: even if this function is ready to return the result, but was cancelled
* while suspended, [CancellationException] will be thrown. See [suspendCancellableCoroutine] for low-level details.
*/
public suspend fun joinAll(vararg jobs: Job): Unit = jobs.forEach { it.join() }

/**
* Suspends current coroutine until all given jobs are complete.
* This method is semantically equivalent to joining all given jobs one by one with `forEach { it.join() }`.
*
* This suspending function is cancellable.
* If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting,
* this function immediately resumes with [CancellationException].
* There is a **prompt cancellation guarantee**. If the job was cancelled while this function was
* suspended, it will not resume successfully. See [suspendCancellableCoroutine] documentation for low-level details.
* This suspending function is cancellable: if the [Job] of the current coroutine is cancelled or completed while this
* suspending function is waiting, this function immediately resumes with [CancellationException].
* There is a **prompt cancellation guarantee**: even if this function is ready to return the result, but was cancelled
* while suspended, [CancellationException] will be thrown. See [suspendCancellableCoroutine] for low-level details.
*/
public suspend fun Collection<Job>.joinAll(): Unit = forEach { it.join() }

Expand Down
18 changes: 9 additions & 9 deletions kotlinx-coroutines-core/common/src/CancellableContinuation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -238,25 +238,25 @@ public interface CancellableContinuation<in T> : Continuation<T> {
*
* This function provides **prompt cancellation guarantee**.
* If the [Job] of the current coroutine was cancelled while this function was suspended it will not resume
* successfully.
* successfully, even if [CancellableContinuation.resume] was already invoked.
*
* The cancellation of the coroutine's job is generally asynchronous with respect to the suspended coroutine.
* The suspended coroutine is resumed with the call it to its [Continuation.resumeWith] member function or to
* The suspended coroutine is resumed with a call to its [Continuation.resumeWith] member function or to the
* [resume][Continuation.resume] extension function.
* However, when coroutine is resumed, it does not immediately start executing, but is passed to its
* [CoroutineDispatcher] to schedule its execution when dispatcher's resources become available for execution.
* The job's cancellation can happen both before, after, and concurrently with the call to `resume`. In any
* case, prompt cancellation guarantees that the the coroutine will not resume its code successfully.
* The job's cancellation can happen before, after, and concurrently with the call to `resume`. In any
* case, prompt cancellation guarantees that the coroutine will not resume its code successfully.
*
* If the coroutine was resumed with an exception (for example, using [Continuation.resumeWithException] extension
* function) and cancelled, then the resulting exception of the `suspendCancellableCoroutine` function is determined
* by whichever action (exceptional resume or cancellation) that happened first.
* function) and cancelled, then the exception thrown by the `suspendCancellableCoroutine` function is determined
* by what happened first: exceptional resume or cancellation.
*
* ### Returning resources from a suspended coroutine
*
* As a result of a prompt cancellation guarantee, when a closeable resource
* (like open file or a handle to another native resource) is returned from a suspended coroutine as a value
* it can be lost when the coroutine is cancelled. In order to ensure that the resource can be properly closed
* As a result of the prompt cancellation guarantee, when a closeable resource
* (like open file or a handle to another native resource) is returned from a suspended coroutine as a value,
* it can be lost when the coroutine is cancelled. To ensure that the resource can be properly closed
* in this case, the [CancellableContinuation] interface provides two functions.
*
* - [invokeOnCancellation][CancellableContinuation.invokeOnCancellation] installs a handler that is called
Expand Down
4 changes: 2 additions & 2 deletions kotlinx-coroutines-core/common/src/Deferred.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ public interface Deferred<out T> : Job {
* }
* ```
*
* There is a **prompt cancellation guarantee**. If the job was cancelled while this function was
* suspended, it will not resume successfully. See [suspendCancellableCoroutine] documentation for low-level details.
* There is a **prompt cancellation guarantee**: even if this function is ready to return the result, but was cancelled
* while suspended, [CancellationException] will be thrown. See [suspendCancellableCoroutine] for low-level details.
*
* This function can be used in [select] invocations with an [onAwait] clause.
* Use [isCompleted] to check for completion of this deferred value without waiting, and
Expand Down
18 changes: 8 additions & 10 deletions kotlinx-coroutines-core/common/src/Delay.kt
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,10 @@ public suspend fun awaitCancellation(): Nothing = suspendCancellableCoroutine {}
* Delays coroutine for at least the given time without blocking a thread and resumes it after a specified time.
* If the given [timeMillis] is non-positive, this function returns immediately.
*
* This suspending function is cancellable.
* If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
* immediately resumes with [CancellationException].
* There is a **prompt cancellation guarantee**. If the job was cancelled while this function was
* suspended, it will not resume successfully. See [suspendCancellableCoroutine] documentation for low-level details.
* This suspending function is cancellable: if the [Job] of the current coroutine is cancelled or completed while this
* suspending function is waiting, this function immediately resumes with [CancellationException].
* There is a **prompt cancellation guarantee**: even if this function is ready to return the result, but was cancelled
* while suspended, [CancellationException] will be thrown. See [suspendCancellableCoroutine] for low-level details.
*
* If you want to delay forever (until cancellation), consider using [awaitCancellation] instead.
*
Expand All @@ -133,11 +132,10 @@ public suspend fun delay(timeMillis: Long) {
* Delays coroutine for at least the given [duration] without blocking a thread and resumes it after the specified time.
* If the given [duration] is non-positive, this function returns immediately.
*
* This suspending function is cancellable.
* If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
* immediately resumes with [CancellationException].
* There is a **prompt cancellation guarantee**. If the job was cancelled while this function was
* suspended, it will not resume successfully. See [suspendCancellableCoroutine] documentation for low-level details.
* This suspending function is cancellable: if the [Job] of the current coroutine is cancelled or completed while this
* suspending function is waiting, this function immediately resumes with [CancellationException].
* There is a **prompt cancellation guarantee**: even if this function is ready to return the result, but was cancelled
* while suspended, [CancellationException] will be thrown. See [suspendCancellableCoroutine] for low-level details.
*
* If you want to delay forever (until cancellation), consider using [awaitCancellation] instead.
*
Expand Down
11 changes: 5 additions & 6 deletions kotlinx-coroutines-core/common/src/Yield.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ import kotlin.coroutines.intrinsics.*
/**
* Yields the thread (or thread pool) of the current coroutine dispatcher
* to other coroutines on the same dispatcher to run if possible.
*
* This suspending function is cancellable.
* If the [Job] of the current coroutine is cancelled or completed when this suspending function is invoked or while
* this function is waiting for dispatch, it resumes with a [CancellationException].
* There is a **prompt cancellation guarantee**. If the job was cancelled while this function was
* suspended, it will not resume successfully. See [suspendCancellableCoroutine] documentation for low-level details.
*
* This suspending function is cancellable: if the [Job] of the current coroutine is cancelled or completed while
* [yield] is invoked or while waiting for dispatch, it immediately resumes with [CancellationException].
* There is a **prompt cancellation guarantee**: even if this function is ready to return the result, but was cancelled
* while suspended, [CancellationException] will be thrown. See [suspendCancellableCoroutine] for low-level details.
*
* **Note**: This function always [checks for cancellation][ensureActive] even when it does not suspend.
*
Expand Down
Loading

0 comments on commit 92df6e1

Please sign in to comment.