Skip to content

Commit f6fed2a

Browse files
committed
Support failed channels (closed for cause), buildChannel coroutine builder
1 parent 7b2d8b0 commit f6fed2a

File tree

9 files changed

+255
-100
lines changed

9 files changed

+255
-100
lines changed

kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Builders.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ private class StandaloneCoroutine(
7373
) : AbstractCoroutine<Unit>(parentContext) {
7474
override fun afterCompletion(state: Any?) {
7575
// note the use of the parent's job context below!
76-
if (state is CompletedExceptionally) handleCoroutineException(parentContext, state.cancelReason)
76+
if (state is CompletedExceptionally) handleCoroutineException(parentContext, state.cancelCause)
7777
}
7878
}
7979

kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CancellableContinuation.kt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,14 @@ public interface CancellableContinuation<in T> : Continuation<T>, Job {
2929
fun tryResume(value: T): Any?
3030

3131
/**
32-
* Completes the execution of [tryResume] on its non-null result.
32+
* Tries to resume this continuation with a given exception and returns non-null object token if it was successful,
33+
* or `null` otherwise (it was already resumed or cancelled). When non-null object was returned,
34+
* [completeResume] must be invoked with it.
35+
*/
36+
fun tryResumeWithException(exception: Throwable): Any?
37+
38+
/**
39+
* Completes the execution of [tryResume] or [tryResumeWithException] on its non-null result.
3340
*/
3441
fun completeResume(token: Any)
3542

@@ -117,6 +124,16 @@ internal class SafeCancellableContinuation<in T>(
117124
}
118125
}
119126

127+
override fun tryResumeWithException(exception: Throwable): Any? {
128+
while (true) { // lock-free loop on state
129+
val state = getState() // atomic read
130+
when (state) {
131+
is Active -> if (tryUpdateState(state, Failed(exception))) return state
132+
else -> return null // cannot resume -- not active anymore
133+
}
134+
}
135+
}
136+
120137
override fun completeResume(token: Any) {
121138
completeUpdateState(token, getState())
122139
}

kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Job.kt

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public interface Job : CoroutineContext.Element {
5757
public fun onCompletion(handler: CompletionHandler): Registration
5858

5959
/**
60-
* Cancel this activity with an optional cancellation [reason]. The result is `true` if this job was
60+
* Cancel this activity with an optional cancellation [cause]. The result is `true` if this job was
6161
* cancelled as a result of this invocation and `false` otherwise
6262
* (if it was already cancelled or it is [NonCancellable]).
6363
* Repeated invocation of this function has no effect and always produces `false`.
@@ -66,7 +66,7 @@ public interface Job : CoroutineContext.Element {
6666
* at the corresponding original cancellation site and passed into this method to aid in debugging by providing
6767
* both the context of cancellation and text description of the reason.
6868
*/
69-
public fun cancel(reason: Throwable? = null): Boolean
69+
public fun cancel(cause: Throwable? = null): Boolean
7070

7171
@Suppress("DeprecatedCallableAddReplaceWith")
7272
@Deprecated(message = "Operator '+' on two Job objects is meaningless. " +
@@ -231,7 +231,7 @@ internal open class JobSupport : AbstractCoroutineContextElement(Job), Job {
231231

232232
fun completeUpdateState(expect: Any, update: Any?) {
233233
// #3. Invoke completion handlers
234-
val reason = (update as? CompletedExceptionally)?.cancelReason
234+
val reason = (update as? CompletedExceptionally)?.cancelCause
235235
var completionException: Throwable? = null
236236
when (expect) {
237237
// SINGLE/SINGLE+ state -- one completion handler (common case)
@@ -295,7 +295,7 @@ internal open class JobSupport : AbstractCoroutineContextElement(Job), Job {
295295
}
296296
// is not active anymore
297297
else -> {
298-
handler((state as? Cancelled)?.cancelReason)
298+
handler((state as? Cancelled)?.cancelCause)
299299
return EmptyRegistration
300300
}
301301
}
@@ -327,10 +327,10 @@ internal open class JobSupport : AbstractCoroutineContextElement(Job), Job {
327327
}
328328
}
329329

330-
final override fun cancel(reason: Throwable?): Boolean {
330+
final override fun cancel(cause: Throwable?): Boolean {
331331
while (true) { // lock-free loop on state
332332
val state = this.state as? Active ?: return false // quit if not active anymore
333-
if (updateState(state, Cancelled(reason))) return true
333+
if (updateState(state, Cancelled(cause))) return true
334334
}
335335
}
336336

@@ -371,31 +371,31 @@ internal open class JobSupport : AbstractCoroutineContextElement(Job), Job {
371371
* Abstract class for a [state][getState] of a job that had completed exceptionally, including cancellation.
372372
*/
373373
internal abstract class CompletedExceptionally {
374-
abstract val cancelReason: Throwable // original reason or fresh CancellationException
374+
abstract val cancelCause: Throwable // original reason or fresh CancellationException
375375
abstract val exception: Throwable // the exception to be thrown in continuation
376376

377-
// convert cancelReason to CancellationException on first need
377+
// convert cancelCause to CancellationException on first need
378378
@Volatile
379379
private var _cancellationException: CancellationException? = null
380380

381381
val cancellationException: CancellationException get() =
382382
_cancellationException ?: // atomic read volatile var or else build new
383-
(cancelReason as? CancellationException ?:
384-
CancellationException(cancelReason.message).apply { initCause(cancelReason) })
385-
.also { _cancellationException = it }
386-
383+
(cancelCause as? CancellationException ?:
384+
CancellationException(cancelCause.message)
385+
.apply { initCause(cancelCause) })
386+
.also { _cancellationException = it }
387387
}
388388

389389
/**
390390
* Represents a [state][getState] of a cancelled job.
391391
*/
392-
internal class Cancelled(specifiedReason: Throwable?) : CompletedExceptionally() {
392+
internal class Cancelled(specifiedCause: Throwable?) : CompletedExceptionally() {
393393
@Volatile
394-
private var _cancelReason = specifiedReason // materialize CancellationException on first need
394+
private var _cancelCause = specifiedCause // materialize CancellationException on first need
395395

396-
override val cancelReason: Throwable get() =
397-
_cancelReason ?: // atomic read volatile var or else create new
398-
CancellationException("Job was cancelled without specified reason").also { _cancelReason = it }
396+
override val cancelCause: Throwable get() =
397+
_cancelCause ?: // atomic read volatile var or else create new
398+
CancellationException("Job was cancelled").also { _cancelCause = it }
399399

400400
override val exception: Throwable get() = cancellationException
401401
}
@@ -404,7 +404,7 @@ internal open class JobSupport : AbstractCoroutineContextElement(Job), Job {
404404
* Represents a [state][getState] of a failed job.
405405
*/
406406
internal class Failed(override val exception: Throwable) : CompletedExceptionally() {
407-
override val cancelReason: Throwable get() = exception
407+
override val cancelCause: Throwable get() = exception
408408
}
409409
}
410410

kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/NonCancellable.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ object NonCancellable : AbstractCoroutineContextElement(Job), Job {
1616
override val isActive: Boolean get() = true
1717
override fun getInactiveCancellationException(): CancellationException = throw IllegalStateException("This job is always active")
1818
override fun onCompletion(handler: CompletionHandler): Job.Registration = EmptyRegistration
19-
override fun cancel(reason: Throwable?): Boolean = false
19+
override fun cancel(cause: Throwable?): Boolean = false
2020
}

0 commit comments

Comments
 (0)