[K/N] Make SafeContinuation thread-safe

This commit is contained in:
Pavel Kunyavskiy
2021-07-08 12:13:24 +03:00
committed by Space
parent 07cb3a5ff8
commit 92789984e0
@@ -6,6 +6,7 @@
package kotlin.coroutines package kotlin.coroutines
import kotlin.* import kotlin.*
import kotlin.native.concurrent.*
import kotlin.coroutines.intrinsics.CoroutineSingletons.* import kotlin.coroutines.intrinsics.CoroutineSingletons.*
import kotlin.coroutines.intrinsics.* import kotlin.coroutines.intrinsics.*
@@ -22,26 +23,28 @@ internal actual constructor(
public actual override val context: CoroutineContext public actual override val context: CoroutineContext
get() = delegate.context get() = delegate.context
private var result: Any? = initialResult private var resultRef = FreezableAtomicReference<Any?>(initialResult)
public actual override fun resumeWith(result: Result<T>) { public actual override fun resumeWith(result: Result<T>) {
val cur = this.result while (true) {
when { val cur = resultRef.value
cur === UNDECIDED -> this.result = result.value when {
cur === COROUTINE_SUSPENDED -> { cur === UNDECIDED -> if (resultRef.compareAndSet(UNDECIDED, result.value)) return
this.result = RESUMED cur === COROUTINE_SUSPENDED -> if (resultRef.compareAndSet(COROUTINE_SUSPENDED, RESUMED)) {
delegate.resumeWith(result) delegate.resumeWith(result)
return
}
else -> throw IllegalStateException("Already resumed")
} }
else -> throw IllegalStateException("Already resumed")
} }
} }
@PublishedApi @PublishedApi
internal actual fun getOrThrow(): Any? { internal actual fun getOrThrow(): Any? {
val result = this.result var result = resultRef.value
if (result === UNDECIDED) { if (result === UNDECIDED) {
this.result = COROUTINE_SUSPENDED if (resultRef.compareAndSet(UNDECIDED, COROUTINE_SUSPENDED)) return COROUTINE_SUSPENDED
return COROUTINE_SUSPENDED result = resultRef.value
} }
return when { return when {
result === RESUMED -> COROUTINE_SUSPENDED // already called continuation, indicate COROUTINE_SUSPENDED upstream result === RESUMED -> COROUTINE_SUSPENDED // already called continuation, indicate COROUTINE_SUSPENDED upstream