Skip to content

Commit f7f65dc

Browse files
committed
Fix implementations of resumeUndispatched and resumeUndispatchedWithException to be immediate-dispatcher friendly
1 parent 95892c2 commit f7f65dc

File tree

2 files changed

+13
-7
lines changed

2 files changed

+13
-7
lines changed

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

+10-2
Original file line numberDiff line numberDiff line change
@@ -534,12 +534,20 @@ internal open class CancellableContinuationImpl<in T>(
534534

535535
override fun CoroutineDispatcher.resumeUndispatched(value: T) {
536536
val dc = delegate as? DispatchedContinuation
537-
resumeImpl(value, if (dc?.dispatcher === this) MODE_UNDISPATCHED else resumeMode)
537+
val dispatcher = dc?.dispatcher
538+
resumeImpl(
539+
value,
540+
if (dispatcher === this || dispatcher?.isDispatchNeeded(delegate.context) == false) MODE_UNDISPATCHED else resumeMode
541+
)
538542
}
539543

540544
override fun CoroutineDispatcher.resumeUndispatchedWithException(exception: Throwable) {
541545
val dc = delegate as? DispatchedContinuation
542-
resumeImpl(CompletedExceptionally(exception), if (dc?.dispatcher === this) MODE_UNDISPATCHED else resumeMode)
546+
val dispatcher = dc?.dispatcher
547+
resumeImpl(
548+
CompletedExceptionally(exception),
549+
if (dispatcher === this || dispatcher?.isDispatchNeeded(delegate.context) == false) MODE_UNDISPATCHED else resumeMode
550+
)
543551
}
544552

545553
@Suppress("UNCHECKED_CAST")

kotlinx-coroutines-core/common/src/internal/DispatchedTask.kt

+3-5
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ internal val Int.isCancellableMode get() = this == MODE_CANCELLABLE || this == M
4848
internal val Int.isReusableMode get() = this == MODE_CANCELLABLE_REUSABLE
4949

5050
internal abstract class DispatchedTask<in T>(
51-
@JvmField public var resumeMode: Int
51+
@JvmField var resumeMode: Int
5252
) : SchedulerTask() {
5353
internal abstract val delegate: Continuation<T>
5454

@@ -151,11 +151,11 @@ internal fun <T> DispatchedTask<T>.dispatch(mode: Int) {
151151
assert { mode != MODE_UNINITIALIZED } // invalid mode value for this method
152152
val delegate = this.delegate
153153
val undispatched = mode == MODE_UNDISPATCHED
154-
if (!undispatched && delegate is DispatchedContinuation<*> && mode.isCancellableMode == resumeMode.isCancellableMode) {
154+
if (delegate is DispatchedContinuation<*>) {
155155
// dispatch directly using this instance's Runnable implementation
156156
val dispatcher = delegate.dispatcher
157157
val context = delegate.context
158-
if (dispatcher.isDispatchNeeded(context)) {
158+
if (!undispatched && dispatcher.isDispatchNeeded(context)) {
159159
dispatcher.dispatch(context, this)
160160
} else {
161161
resumeUnconfined()
@@ -167,7 +167,6 @@ internal fun <T> DispatchedTask<T>.dispatch(mode: Int) {
167167
}
168168
}
169169

170-
@Suppress("UNCHECKED_CAST")
171170
internal fun <T> DispatchedTask<T>.resume(delegate: Continuation<T>, undispatched: Boolean) {
172171
// This resume is never cancellable. The result is always delivered to delegate continuation.
173172
val state = takeState()
@@ -214,7 +213,6 @@ internal inline fun DispatchedTask<*>.runUnconfinedEventLoop(
214213
}
215214
}
216215

217-
@Suppress("NOTHING_TO_INLINE")
218216
internal inline fun Continuation<*>.resumeWithStackTrace(exception: Throwable) {
219217
resumeWith(Result.failure(recoverStackTrace(exception, this)))
220218
}

0 commit comments

Comments
 (0)