From 80888afef813c9534576f3c1ff94c970e01a1e02 Mon Sep 17 00:00:00 2001 From: Vsevolod Tolstopyatov Date: Mon, 11 Oct 2021 19:52:08 +0300 Subject: [PATCH] Use Dispatchers.Main as default delay source where applicable It reduces the number of redundant threads in the system and makes time source predictable across Android/JavaFx applications Fixes #2972 --- .../jvm/src/DefaultExecutor.kt | 17 ++++++++++++++++- .../src/JavaFxDispatcher.kt | 12 ++++-------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/kotlinx-coroutines-core/jvm/src/DefaultExecutor.kt b/kotlinx-coroutines-core/jvm/src/DefaultExecutor.kt index 6457d26e0a..7b0810c2a1 100644 --- a/kotlinx-coroutines-core/jvm/src/DefaultExecutor.kt +++ b/kotlinx-coroutines-core/jvm/src/DefaultExecutor.kt @@ -4,10 +4,25 @@ package kotlinx.coroutines +import kotlinx.coroutines.internal.* import java.util.concurrent.* import kotlin.coroutines.* -internal actual val DefaultDelay: Delay = DefaultExecutor +internal actual val DefaultDelay: Delay = initializeDefaultDelay() + +private val defaultMainDelayOptIn = systemProp("kotlinx.coroutines.main.delay", true) + +private fun initializeDefaultDelay(): Delay { + // Opt-out flag + if (!defaultMainDelayOptIn) return DefaultExecutor + val main = Dispatchers.Main + /* + * When we already are working with UI and Main threads, it makes + * no sense to create a separate thread with timer that cannot be controller + * by the UI runtime. + */ + return if (main.isMissing() || main !is Delay) DefaultExecutor else main +} @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") internal actual object DefaultExecutor : EventLoopImplBase(), Runnable { diff --git a/ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt b/ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt index 6915c53972..d158fb745a 100644 --- a/ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt +++ b/ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt @@ -34,22 +34,18 @@ public sealed class JavaFxDispatcher : MainCoroutineDispatcher(), Delay { /** @suppress */ override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation) { - val timeline = schedule(timeMillis, TimeUnit.MILLISECONDS, EventHandler { + val timeline = schedule(timeMillis, TimeUnit.MILLISECONDS) { with(continuation) { resumeUndispatched(Unit) } - }) + } continuation.invokeOnCancellation { timeline.stop() } } /** @suppress */ override fun invokeOnTimeout(timeMillis: Long, block: Runnable, context: CoroutineContext): DisposableHandle { - val timeline = schedule(timeMillis, TimeUnit.MILLISECONDS, EventHandler { + val timeline = schedule(timeMillis, TimeUnit.MILLISECONDS) { block.run() - }) - return object : DisposableHandle { - override fun dispose() { - timeline.stop() - } } + return DisposableHandle { timeline.stop() } } private fun schedule(time: Long, unit: TimeUnit, handler: EventHandler): Timeline =