Revert "Removed legacy onFinishing handler support from JobSupport"
This reverts commit b209e9b
diff --git a/common/kotlinx-coroutines-core-common/src/Builders.common.kt b/common/kotlinx-coroutines-core-common/src/Builders.common.kt
index 480aaf5..4bfba1d 100644
--- a/common/kotlinx-coroutines-core-common/src/Builders.common.kt
+++ b/common/kotlinx-coroutines-core-common/src/Builders.common.kt
@@ -210,9 +210,17 @@
private val parentContext: CoroutineContext,
active: Boolean
) : AbstractCoroutine<Unit>(parentContext, active) {
+ override fun hasOnFinishingHandler(update: Any?) = update is CompletedExceptionally
+
override fun handleJobException(exception: Throwable) {
handleCoroutineException(parentContext, exception, this)
}
+
+ override fun onFinishingInternal(update: Any?) {
+ if (update is CompletedExceptionally && update.cause !is CancellationException) {
+ parentContext[Job]?.cancel(update.cause)
+ }
+ }
}
private class LazyStandaloneCoroutine(
diff --git a/common/kotlinx-coroutines-core-common/src/JobSupport.kt b/common/kotlinx-coroutines-core-common/src/JobSupport.kt
index 65b48c8..4c8945d 100644
--- a/common/kotlinx-coroutines-core-common/src/JobSupport.kt
+++ b/common/kotlinx-coroutines-core-common/src/JobSupport.kt
@@ -640,6 +640,7 @@
private fun tryMakeCancelling(expect: Incomplete, list: NodeList, cause: Throwable?): Boolean {
val cancelled = Cancelled(this, cause)
if (!_state.compareAndSet(expect, Finishing(list, cancelled, false))) return false
+ onFinishingInternal(cancelled)
onCancellationInternal(cancelled)
// Materialize cause
notifyCancellation(list, cancelled.cause)
@@ -678,10 +679,10 @@
if (state is Finishing && state.completing)
return COMPLETING_ALREADY_COMPLETING
val child: ChildJob? = firstChild(state) ?: // or else complete immediately w/o children
- if (tryFinalizeState(state, proposedUpdate, mode)) {
- return COMPLETING_COMPLETED
- } else {
- return@loopOnState // retry
+ when {
+ state !is Finishing && hasOnFinishingHandler(proposedUpdate) -> null // unless it has onFinishing handler
+ tryFinalizeState(state, proposedUpdate, mode) -> return COMPLETING_COMPLETED
+ else -> return@loopOnState
}
val list = state.list ?: // must promote to list to correctly operate on child lists
when (state) {
@@ -703,6 +704,7 @@
val completing = Finishing(list, cancelled, true)
if (_state.compareAndSet(state, completing)) {
(state as? Finishing)?.transferExceptions(completing)
+ if (state !is Finishing) onFinishingInternal(proposedUpdate)
if (child != null && tryWaitForChild(child, proposedUpdate))
return COMPLETING_WAITING_CHILDREN
if (tryFinalizeState(completing, proposedUpdate, mode = MODE_ATOMIC_DEFAULT))
@@ -799,6 +801,17 @@
}
/**
+ * Whether job has [onFinishingInternal] handler for given [update]
+ * @suppress **This is unstable API and it is subject to change.**
+ */
+ internal open fun hasOnFinishingHandler(update: Any?) = false
+
+ /**
+ * @suppress **This is unstable API and it is subject to change.**
+ */
+ internal open fun onFinishingInternal(update: Any?) {}
+
+ /**
* Method which is invoked once Job becomes [Cancelled] or [CompletedExceptionally].
* It's guaranteed that at the moment of invocation the job and all its children are complete.
*/