17
17
package kotlinx.coroutines.experimental
18
18
19
19
import kotlinx.coroutines.experimental.internal.LockFreeLinkedListNode
20
- import java.util.concurrent.atomic.AtomicIntegerFieldUpdater
21
20
import kotlin.coroutines.experimental.Continuation
22
21
import kotlin.coroutines.experimental.CoroutineContext
23
22
import kotlin.coroutines.experimental.intrinsics.COROUTINE_SUSPENDED
@@ -124,7 +123,7 @@ public inline suspend fun <T> suspendCancellableCoroutine(
124
123
crossinline block : (CancellableContinuation <T >) -> Unit
125
124
): T =
126
125
suspendCoroutineOrReturn { cont ->
127
- val cancellable = CancellableContinuationImpl (cont, defaultResumeMode = MODE_CANCELLABLE , active = true )
126
+ val cancellable = CancellableContinuationImpl (cont, defaultResumeMode = MODE_CANCELLABLE )
128
127
if (! holdCancellability) cancellable.initCancellability()
129
128
block(cancellable)
130
129
cancellable.getResult()
@@ -143,7 +142,7 @@ public inline suspend fun <T> suspendAtomicCancellableCoroutine(
143
142
crossinline block : (CancellableContinuation <T >) -> Unit
144
143
): T =
145
144
suspendCoroutineOrReturn { cont ->
146
- val cancellable = CancellableContinuationImpl (cont, defaultResumeMode = MODE_ATOMIC_DEFAULT , active = true )
145
+ val cancellable = CancellableContinuationImpl (cont, defaultResumeMode = MODE_ATOMIC_DEFAULT )
147
146
if (! holdCancellability) cancellable.initCancellability()
148
147
block(cancellable)
149
148
cancellable.getResult()
@@ -169,51 +168,36 @@ private class RemoveOnCancel(
169
168
override fun toString () = " RemoveOnCancel[$node ]"
170
169
}
171
170
172
- @PublishedApi internal const val MODE_ATOMIC_DEFAULT = 0 // schedule non-cancellable dispatch for suspendCoroutine
173
- @PublishedApi internal const val MODE_CANCELLABLE = 1 // schedule cancellable dispatch for suspendCancellableCoroutine
174
- @PublishedApi internal const val MODE_DIRECT = 2 // when the context is right just invoke the delegate continuation direct
175
- @PublishedApi internal const val MODE_UNDISPATCHED = 3 // when the thread is right, but need to mark it with current coroutine
176
-
177
171
@PublishedApi
178
- internal open class CancellableContinuationImpl <in T >(
179
- @JvmField
180
- protected val delegate : Continuation <T >,
181
- override val defaultResumeMode : Int ,
182
- active : Boolean
183
- ) : AbstractCoroutine<T>(active), CancellableContinuation<T> {
184
- @Volatile
185
- private var decision = UNDECIDED
186
-
187
- override val parentContext: CoroutineContext
188
- get() = delegate.context
189
-
190
- protected companion object {
191
- @JvmField
192
- val DECISION : AtomicIntegerFieldUpdater <CancellableContinuationImpl <* >> =
193
- AtomicIntegerFieldUpdater .newUpdater(CancellableContinuationImpl ::class .java, " decision" )
194
-
195
- const val UNDECIDED = 0
196
- const val SUSPENDED = 1
197
- const val RESUMED = 2
198
-
199
- @Suppress(" UNCHECKED_CAST" )
200
- fun <T > getSuccessfulResult (state : Any? ): T = if (state is CompletedIdempotentResult ) state.result as T else state as T
201
- }
172
+ internal class CancellableContinuationImpl <in T >(
173
+ private val delegate : Continuation <T >,
174
+ override val defaultResumeMode : Int
175
+ ) : AbstractCoroutineWithDecision<T>(active = true ), CancellableContinuation<T> {
176
+ override val parentContext: CoroutineContext get() = delegate.context
202
177
203
178
override fun initCancellability () {
204
179
initParentJob(parentContext[Job ])
205
180
}
206
181
207
182
@PublishedApi
208
183
internal fun getResult (): Any? {
209
- val decision = this .decision // volatile read
210
- if (decision == UNDECIDED && DECISION .compareAndSet(this , UNDECIDED , SUSPENDED )) return COROUTINE_SUSPENDED
211
- // otherwise, afterCompletion was already invoked, and the result is in the state
184
+ if (trySuspend()) return COROUTINE_SUSPENDED
185
+ // otherwise, afterCompletion was already invoked & invoked tryResume, and the result is in the state
212
186
val state = this .state
213
187
if (state is CompletedExceptionally ) throw state.exception
214
188
return getSuccessfulResult(state)
215
189
}
216
190
191
+ override fun afterCompletion (state : Any? , mode : Int ) {
192
+ if (tryResume()) return // completed before getResult invocation -- bail out
193
+ // otherwise, getResult has already commenced, i.e. completed later or in other thread
194
+ if (state is CompletedExceptionally ) {
195
+ delegate.resumeWithExceptionMode(mode, state.exception)
196
+ } else {
197
+ delegate.resumeMode(mode, getSuccessfulResult<T >(state))
198
+ }
199
+ }
200
+
217
201
override fun tryResume (value : T , idempotent : Any? ): Any? {
218
202
while (true ) { // lock-free loop on state
219
203
val state = this .state // atomic read
@@ -251,31 +235,6 @@ internal open class CancellableContinuationImpl<in T>(
251
235
completeUpdateState(token, state, defaultResumeMode)
252
236
}
253
237
254
- override fun afterCompletion (state : Any? , mode : Int ) {
255
- val decision = this .decision // volatile read
256
- if (decision == UNDECIDED && DECISION .compareAndSet(this , UNDECIDED , RESUMED )) return // will get result in getResult
257
- // otherwise, getResult has already commenced, i.e. it was resumed later or in other thread
258
- if (state is CompletedExceptionally ) {
259
- val exception = state.exception
260
- when (mode) {
261
- MODE_ATOMIC_DEFAULT -> delegate.resumeWithException(exception)
262
- MODE_CANCELLABLE -> delegate.resumeCancellableWithException(exception)
263
- MODE_DIRECT -> delegate.resumeDirectWithException(exception)
264
- MODE_UNDISPATCHED -> (delegate as DispatchedContinuation ).resumeUndispatchedWithException(exception)
265
- else -> error(" Invalid mode $mode " )
266
- }
267
- } else {
268
- val value = getSuccessfulResult<T >(state)
269
- when (mode) {
270
- MODE_ATOMIC_DEFAULT -> delegate.resume(value)
271
- MODE_CANCELLABLE -> delegate.resumeCancellable(value)
272
- MODE_DIRECT -> delegate.resumeDirect(value)
273
- MODE_UNDISPATCHED -> (delegate as DispatchedContinuation ).resumeUndispatched(value)
274
- else -> error(" Invalid mode $mode " )
275
- }
276
- }
277
- }
278
-
279
238
override fun CoroutineDispatcher.resumeUndispatched (value : T ) {
280
239
val dc = delegate as ? DispatchedContinuation ? : throw IllegalArgumentException (" Must be used with DispatchedContinuation" )
281
240
check(dc.dispatcher == = this ) { " Must be invoked from the context CoroutineDispatcher" }
@@ -287,12 +246,16 @@ internal open class CancellableContinuationImpl<in T>(
287
246
check(dc.dispatcher == = this ) { " Must be invoked from the context CoroutineDispatcher" }
288
247
resumeWithException(exception, MODE_UNDISPATCHED )
289
248
}
249
+ }
290
250
291
- private class CompletedIdempotentResult (
292
- @JvmField val idempotentResume : Any? ,
293
- @JvmField val result : Any? ,
294
- @JvmField val token : Incomplete
295
- ) {
296
- override fun toString (): String = " CompletedIdempotentResult[$result ]"
297
- }
251
+ private class CompletedIdempotentResult (
252
+ @JvmField val idempotentResume : Any? ,
253
+ @JvmField val result : Any? ,
254
+ @JvmField val token : JobSupport .Incomplete
255
+ ) {
256
+ override fun toString (): String = " CompletedIdempotentResult[$result ]"
298
257
}
258
+
259
+ @Suppress(" UNCHECKED_CAST" )
260
+ private fun <T > getSuccessfulResult (state : Any? ): T =
261
+ if (state is CompletedIdempotentResult ) state.result as T else state as T
0 commit comments