@@ -19,25 +19,36 @@ public interface ProducerScope<in E> : CoroutineScope, SendChannel<E> {
19
19
}
20
20
21
21
/* *
22
- * Suspends the current coroutine until the channel is either [closed][SendChannel.close] or [cancelled][ReceiveChannel.cancel]
23
- * and invokes the given [block] before resuming the coroutine .
22
+ * Suspends the current coroutine until the channel is either
23
+ * [closed][SendChannel.close] or [cancelled][ReceiveChannel.cancel] .
24
24
*
25
- * This suspending function is cancellable: if the [Job] of the current coroutine is cancelled while this
26
- * suspending function is waiting, this function immediately resumes with [CancellationException].
25
+ * The given [block] will be executed unconditionally before this function returns.
26
+ * `awaitClose { cleanup() }` is a convenient shorthand for the often useful form
27
+ * `try { awaitClose() } finally { cleanup() }`.
28
+ *
29
+ * This function can only be invoked directly inside the same coroutine that is its receiver.
30
+ * Specifying the receiver of [awaitClose] explicitly is most probably a mistake.
31
+ *
32
+ * This suspending function is cancellable: if the [Job] of the current coroutine is [cancelled][CoroutineScope.cancel]
33
+ * while this suspending function is waiting, this function immediately resumes with [CancellationException].
27
34
* There is a **prompt cancellation guarantee**: even if this function is ready to return, but was cancelled
28
35
* while suspended, [CancellationException] will be thrown. See [suspendCancellableCoroutine] for low-level details.
29
36
*
30
- * Note that when the producer channel is cancelled, this function resumes with a cancellation exception.
31
- * Therefore, in case of cancellation, no code after the call to this function will be executed.
32
- * That's why this function takes a lambda parameter.
33
- *
34
37
* Example of usage:
35
38
* ```
36
39
* val callbackEventsStream = produce {
37
40
* val disposable = registerChannelInCallback(channel)
38
41
* awaitClose { disposable.dispose() }
39
42
* }
40
43
* ```
44
+ *
45
+ * **Pitfall**: when used in [produce], if the channel is [cancelled][ReceiveChannel.cancel], [awaitClose] can either
46
+ * return normally or throw a [CancellationException] due to a race condition.
47
+ * The reason is that, for [produce], cancelling the channel and cancelling the coroutine of the [ProducerScope] is
48
+ * done simultaneously.
49
+ *
50
+ * @throws IllegalStateException if invoked from outside the [ProducerScope] (by leaking `this` outside the producer
51
+ * coroutine).
41
52
*/
42
53
public suspend fun ProducerScope <* >.awaitClose (block : () -> Unit = {}) {
43
54
check(kotlin.coroutines.coroutineContext[Job ] == = this ) { " awaitClose() can only be invoked from the producer context" }
0 commit comments