blob: 78d810c0fafabe3eff72cf5bc092bd173ffa41b9 [file] [log] [blame]
Roman Elizarov3754f952017-01-18 20:47:54 +03001package kotlinx.coroutines.experimental
2
3import kotlin.coroutines.AbstractCoroutineContextElement
4import kotlin.coroutines.Continuation
5import kotlin.coroutines.ContinuationInterceptor
Roman Elizarov67891d82017-01-23 16:47:20 +03006import kotlin.coroutines.CoroutineContext
Roman Elizarov3754f952017-01-18 20:47:54 +03007
8/**
Roman Elizaroved7b8642017-01-19 11:22:28 +03009 * Base class that shall be extended by all coroutine dispatcher implementations.
10 *
11 * The following standard implementations are provided by `kotlinx.coroutines`:
12 * * [Here] -- starts coroutine execution _right here_ in the current call-frame until the first suspension. On first
13 * suspension the coroutine builder function returns. The coroutine will resume in whatever thread that is used by the
14 * corresponding suspending function, without mandating any specific threading policy.
15 * This in an appropriate choice for IO-intensive coroutines that do not consume CPU resources.
16 * * [CommonPool] -- immediately returns from the coroutine builder and schedules coroutine execution to
17 * a common pool of shared background threads.
18 * This is an appropriate choice for compute-intensive coroutines that consume a lot of CPU resources.
19 * * Private thread pools can be created with [newSingleThreadContext] and [newFixedThreadPoolContext].
20 * * [currentCoroutineContext] -- inherits the context of the parent coroutine,
21 * but throws [IllegalStateException] if used outside of coroutine. Use [currentCoroutineContextOrDefault]
22 * if a default is needed when outside of coroutine.
23 * This is an appropriate choice for libraries that need to inherit parent coroutine context.
24 * * There are context implementations for UI libraries like `Swing` and `JavaFx` in separate modules.
25 *
26 * This class ensures that [currentCoroutineContext] is correctly transferred to a new thread and that
27 * debugging facilities in [newCoroutineContext] function work properly.
Roman Elizarov3754f952017-01-18 20:47:54 +030028 */
29public abstract class CoroutineDispatcher :
30 AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
31 /**
32 * Return `true` if execution shall be dispatched onto another thread.
33 */
Roman Elizarov67891d82017-01-23 16:47:20 +030034 public abstract fun isDispatchNeeded(context: CoroutineContext): Boolean
Roman Elizarov3754f952017-01-18 20:47:54 +030035
36 /**
Roman Elizarov67891d82017-01-23 16:47:20 +030037 * Dispatches execution of a runnable [block] onto another thread in the given [context].
Roman Elizarov3754f952017-01-18 20:47:54 +030038 */
Roman Elizarov67891d82017-01-23 16:47:20 +030039 public abstract fun dispatch(context: CoroutineContext, block: Runnable)
Roman Elizarov3754f952017-01-18 20:47:54 +030040
41 override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> =
42 DispatchedContinuation<T>(this, continuation)
43}
44
45private class DispatchedContinuation<T>(
46 val dispatcher: CoroutineDispatcher,
47 val continuation: Continuation<T>
48): Continuation<T> by continuation {
49 override fun resume(value: T) {
Roman Elizarov67891d82017-01-23 16:47:20 +030050 val context = continuation.context
51 if (dispatcher.isDispatchNeeded(context))
52 dispatcher.dispatch(context, Runnable {
53 withDefaultCoroutineContext(context) {
Roman Elizarov3754f952017-01-18 20:47:54 +030054 continuation.resume(value)
55 }
56 })
57 else
Roman Elizarov67891d82017-01-23 16:47:20 +030058 withDefaultCoroutineContext(context) {
Roman Elizarov3754f952017-01-18 20:47:54 +030059 continuation.resume(value)
60 }
61 }
62
63 override fun resumeWithException(exception: Throwable) {
Roman Elizarov67891d82017-01-23 16:47:20 +030064 val context = continuation.context
65 if (dispatcher.isDispatchNeeded(context))
66 dispatcher.dispatch(context, Runnable {
67 withDefaultCoroutineContext(context) {
Roman Elizarov3754f952017-01-18 20:47:54 +030068 continuation.resumeWithException(exception)
69 }
70 })
71 else
Roman Elizarov67891d82017-01-23 16:47:20 +030072 withDefaultCoroutineContext(context) {
Roman Elizarov3754f952017-01-18 20:47:54 +030073 continuation.resumeWithException(exception)
74 }
75 }
76}