Skip to content

Commit 65ef6ea

Browse files
authored
Simplify code around JobSupport (#4079)
This change simplifies some code used in for `JobSupport`: there are fewer wrapper classes, the information is passed between functions with less duplication, and some API was either removed due to being unused, or moved to reduce its visibility.
1 parent 09ddc06 commit 65ef6ea

File tree

15 files changed

+140
-238
lines changed

15 files changed

+140
-238
lines changed

kotlinx-coroutines-core/common/src/Await.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,5 +114,7 @@ private class AwaitAll<T>(private val deferreds: Array<out Deferred<T>>) {
114114
// Note that all deferreds are complete here, so we don't need to dispose their nodes
115115
}
116116
}
117+
118+
override val onCancelling = false
117119
}
118120
}

kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -234,13 +234,6 @@ internal open class CancellableContinuationImpl<in T>(
234234
}
235235
}
236236

237-
private fun callCancelHandler(handler: InternalCompletionHandler, cause: Throwable?) =
238-
/*
239-
* :KLUDGE: We have to invoke a handler in platform-specific way via `invokeIt` extension,
240-
* because we play type tricks on Kotlin/JS and handler is not necessarily a function there
241-
*/
242-
callCancelHandlerSafely { handler.invoke(cause) }
243-
244237
fun callCancelHandler(handler: CancelHandler, cause: Throwable?) =
245238
callCancelHandlerSafely { handler.invoke(cause) }
246239

@@ -341,10 +334,7 @@ internal open class CancellableContinuationImpl<in T>(
341334
private fun installParentHandle(): DisposableHandle? {
342335
val parent = context[Job] ?: return null // don't do anything without a parent
343336
// Install the handle
344-
val handle = parent.invokeOnCompletion(
345-
onCancelling = true,
346-
handler = ChildContinuation(this)
347-
)
337+
val handle = parent.invokeOnCompletion(handler = ChildContinuation(this))
348338
_parentHandle.compareAndSet(null, handle)
349339
return handle
350340
}
@@ -627,8 +617,6 @@ private object Active : NotCompleted {
627617
* as seen from the debugger.
628618
* Use [UserSupplied] to create an instance from a lambda.
629619
* We can't avoid defining a separate type, because on JS, you can't inherit from a function type.
630-
*
631-
* @see InternalCompletionHandler for a very similar interface, but used for handling completion and not cancellation.
632620
*/
633621
internal interface CancelHandler : NotCompleted {
634622
/**
@@ -682,8 +670,10 @@ private data class CompletedContinuation(
682670
// Same as ChildHandleNode, but for cancellable continuation
683671
private class ChildContinuation(
684672
@JvmField val child: CancellableContinuationImpl<*>
685-
) : JobCancellingNode() {
673+
) : JobNode() {
686674
override fun invoke(cause: Throwable?) {
687675
child.parentCancelled(child.getContinuationCancellationCause(job))
688676
}
677+
678+
override val onCancelling = true
689679
}

kotlinx-coroutines-core/common/src/CompletionHandler.common.kt

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -25,47 +25,3 @@ package kotlinx.coroutines
2525
*/
2626
// TODO: deprecate. This doesn't seem better than a simple function type.
2727
public typealias CompletionHandler = (cause: Throwable?) -> Unit
28-
29-
/**
30-
* Essentially the same as just a function from `Throwable?` to `Unit`.
31-
* The only thing implementors can do is call [invoke].
32-
* The reason this abstraction exists is to allow providing a readable [toString] in the list of completion handlers
33-
* as seen from the debugger.
34-
* Use [UserSupplied] to create an instance from a lambda.
35-
* We can't avoid defining a separate type, because on JS, you can't inherit from a function type.
36-
*
37-
* @see CancelHandler for a very similar interface, but used for handling cancellation and not completion.
38-
*/
39-
internal interface InternalCompletionHandler {
40-
/**
41-
* Signals completion.
42-
*
43-
* This function:
44-
* - Does not throw any exceptions.
45-
* For [Job] instances that are coroutines, exceptions thrown by this function will be caught, wrapped into
46-
* [CompletionHandlerException], and passed to [handleCoroutineException], but for those that are not coroutines,
47-
* they will just be rethrown, potentially crashing unrelated code.
48-
* - Is fast, non-blocking, and thread-safe.
49-
* - Can be invoked concurrently with the surrounding code.
50-
* - Can be invoked from any context.
51-
*
52-
* The meaning of `cause` that is passed to the handler is:
53-
* - It is `null` if the job has completed normally.
54-
* - It is an instance of [CancellationException] if the job was cancelled _normally_.
55-
* **It should not be treated as an error**. In particular, it should not be reported to error logs.
56-
* - Otherwise, the job had _failed_.
57-
*/
58-
fun invoke(cause: Throwable?)
59-
60-
/**
61-
* A lambda passed from outside the coroutine machinery.
62-
*
63-
* See the requirements for [InternalCompletionHandler.invoke] when implementing this function.
64-
*/
65-
class UserSupplied(private val handler: (cause: Throwable?) -> Unit) : InternalCompletionHandler {
66-
/** @suppress */
67-
override fun invoke(cause: Throwable?) { handler(cause) }
68-
69-
override fun toString() = "InternalCompletionHandler.UserSupplied[${handler.classSimpleName}@$hexAddress]"
70-
}
71-
}

kotlinx-coroutines-core/common/src/Exceptions.common.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package kotlinx.coroutines
22

33
/**
4-
* This exception gets thrown if an exception is caught while processing [InternalCompletionHandler] invocation for [Job].
4+
* This exception gets thrown if an exception is caught while processing [CompletionHandler] invocation for [Job].
55
*
66
* @suppress **This an internal API and should not be used from general code.**
77
*/

kotlinx-coroutines-core/common/src/Job.kt

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -340,10 +340,6 @@ public interface Job : CoroutineContext.Element {
340340
* If the handler would have been invoked earlier if it was registered at that time, then it is invoked immediately,
341341
* unless [invokeImmediately] is set to `false`.
342342
*
343-
* The handler is scheduled to be invoked once the job is cancelled or is complete.
344-
* This behavior can be changed by setting the [onCancelling] parameter to `true`.
345-
* In this case, the handler is invoked as soon as the job becomes _cancelling_ instead.
346-
*
347343
* The meaning of `cause` that is passed to the handler is:
348344
* - It is `null` if the job has completed normally.
349345
* - It is an instance of [CancellationException] if the job was cancelled _normally_.
@@ -356,12 +352,11 @@ public interface Job : CoroutineContext.Element {
356352
* all the handlers are released when this job completes.
357353
*/
358354
internal fun Job.invokeOnCompletion(
359-
onCancelling: Boolean = false,
360355
invokeImmediately: Boolean = true,
361-
handler: InternalCompletionHandler
356+
handler: JobNode,
362357
): DisposableHandle = when (this) {
363-
is JobSupport -> invokeOnCompletionInternal(onCancelling, invokeImmediately, handler)
364-
else -> invokeOnCompletion(onCancelling, invokeImmediately, handler::invoke)
358+
is JobSupport -> invokeOnCompletionInternal(invokeImmediately, handler)
359+
else -> invokeOnCompletion(handler.onCancelling, invokeImmediately, handler::invoke)
365360
}
366361

367362
/**
@@ -672,3 +667,11 @@ public object NonDisposableHandle : DisposableHandle, ChildHandle {
672667
*/
673668
override fun toString(): String = "NonDisposableHandle"
674669
}
670+
671+
private class DisposeOnCompletion(
672+
private val handle: DisposableHandle
673+
) : JobNode() {
674+
override fun invoke(cause: Throwable?) = handle.dispose()
675+
676+
override val onCancelling = false
677+
}

0 commit comments

Comments
 (0)