@@ -18,6 +18,8 @@ package kotlinx.coroutines.experimental
18
18
19
19
import java.util.concurrent.locks.LockSupport
20
20
import kotlin.coroutines.experimental.*
21
+ import kotlin.coroutines.experimental.intrinsics.startCoroutineUninterceptedOrReturn
22
+ import kotlin.coroutines.experimental.intrinsics.suspendCoroutineOrReturn
21
23
22
24
// --------------- basic coroutine builders ---------------
23
25
@@ -58,10 +60,28 @@ fun launch(context: CoroutineContext, start: Boolean = true, block: suspend Coro
58
60
* different thread inside the block, and back when it completes.
59
61
* The specified [context] is added onto the current coroutine context for the execution of the block.
60
62
*/
61
- public suspend fun <T > run (context : CoroutineContext , block : suspend CoroutineScope .() -> T ): T =
62
- suspendCoroutine { cont ->
63
- // new don't invoke `newCoroutineContext`, but consider this being the same coroutine in the new context
64
- InnerCoroutine (cont.context + context, cont).also { block.startCoroutine(it, it) }
63
+ public suspend fun <T > run (context : CoroutineContext , block : suspend () -> T ): T =
64
+ suspendCoroutineOrReturn sc@ { cont ->
65
+ val oldContext = cont.context
66
+ // fast path #1 if there is no change in the actual context:
67
+ if (context == = oldContext || context is CoroutineContext .Element && oldContext[context.key] == = context)
68
+ return @sc block.startCoroutineUninterceptedOrReturn(cont)
69
+ // compute new context
70
+ val newContext = oldContext + context
71
+ // fast path #2 if the result is actually the same
72
+ if (newContext == = oldContext)
73
+ return @sc block.startCoroutineUninterceptedOrReturn(cont)
74
+ // fast path #3 if the new dispatcher is the same as the old one
75
+ if (newContext[ContinuationInterceptor ] == = oldContext[ContinuationInterceptor ]) {
76
+ val newContinuation = RunContinuationDirect (newContext, cont)
77
+ return @sc block.startCoroutineUninterceptedOrReturn(newContinuation)
78
+ }
79
+ // slowest path otherwise -- use new interceptor, sync to its result via a
80
+ // full-blown instance of CancellableContinuation
81
+ val newContinuation = RunContinuationCoroutine (newContext, cont)
82
+ newContinuation.initCancellability()
83
+ block.startCoroutine(newContinuation)
84
+ newContinuation.getResult()
65
85
}
66
86
67
87
/* *
@@ -111,12 +131,15 @@ private class LazyStandaloneCoroutine(
111
131
}
112
132
}
113
133
114
- private class InnerCoroutine <in T >(
134
+ private class RunContinuationDirect <in T >(
115
135
override val context : CoroutineContext ,
116
136
continuation : Continuation <T >
117
- ) : Continuation<T> by continuation, CoroutineScope {
118
- override val isActive: Boolean = context[Job ]?.isActive ? : true
119
- }
137
+ ) : Continuation<T> by continuation
138
+
139
+ private class RunContinuationCoroutine <in T >(
140
+ override val parentContext : CoroutineContext ,
141
+ continuation : Continuation <T >
142
+ ) : CancellableContinuationImpl<T>(continuation, active = true )
120
143
121
144
private class BlockingCoroutine <T >(
122
145
override val parentContext : CoroutineContext ,
0 commit comments