@SinceKotlin("1.3") public actual fun <T> Continuation<T>.intercepted(): Continuation<T> = (this as? ContinuationImpl)?.intercepted() ?: this public fun intercepted(): Continuation<Any?> = intercepted ?: (context[ContinuationInterceptor]?.interceptContinuation(this) ?: this) .also { intercepted = it }
// We inline it to save an entry on the stack in cases where it shows (unconfined dispatcher) // It is used only in Continuation<T>.resumeCancellableWith @Suppress("NOTHING_TO_INLINE") inline fun resumeCancellableWith( result: Result<T>, noinline onCancellation: ((cause: Throwable) -> Unit)? ) { valstate= result.toState(onCancellation) if (dispatcher.isDispatchNeeded(context)) { _state = state resumeMode= MODE_CANCELLABLE //【1】核心:把自己丢到 dispatchers.io 的线程池中执行; dispatcher.dispatch(context, this) } else { executeUnconfined(state, MODE_CANCELLABLE) { if (!resumeCancelled(state)) { resumeUndispatchedWith(result) } } } }
publicfinal override fun run() { assert { resumeMode != MODE_UNINITIALIZED } // should have been set before dispatching valtaskContext=this.taskContext var fatalException: Throwable? = null try { valdelegate= delegate as DispatchedContinuation<T> valcontinuation= delegate.continuation withContinuationContext(continuation, delegate.countOrElement) { valcontext= continuation.context valstate= takeState() // NOTE: Must take state in any case, even if cancelled valexception= getExceptionalResult(state) /* * Check whether continuation was originally resumed with an exception. * If so, it dominates cancellation, otherwise the original exception * will be silently lost. */ valjob=if (exception == null && resumeMode.isCancellableMode) context[Job] elsenull if(job != null && !job.isActive) { valcause= job.getCancellationException() cancelCompletedResult(state, cause) //【1】核心逻辑:执行协程体,在特定的线程池中; continuation.resumeWithStackTrace(cause) } else { if (exception != null) { continuation.resumeWithException(exception) } else { continuation.resume(getSuccessfulResult(state)) } } } } catch (e: Throwable) { // This instead of runCatching to have nicer stacktrace and debug experience fatalException = e } finally { valresult= runCatching { taskContext.afterTask() } handleFatalException(fatalException, result.exceptionOrNull()) } }