Fundamentals 16 min read

Source Code Analysis – Suspension and Resumption of Kotlin Coroutines

This article dissects the Kotlin coroutine implementation by decompiling a simple coroutine, explaining how the compiler transforms suspend functions into state‑machine classes, how launch creates an AbstractCoroutine, how the dispatcher intercepts and schedules execution, and how the coroutine is suspended and later resumed through Continuation mechanisms.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Source Code Analysis – Suspension and Resumption of Kotlin Coroutines

Kotlin coroutines have matured over several versions, but their core concept remains: a function or code block can be suspended and later resumed at the same point. This article analyses the creation‑>suspend‑>resume flow by examining the generated bytecode and runtime classes.

Coroutine Creation

Coroutines in Kotlin are wrapped APIs that compile into a class extending SuspendLambda . By decompiling a simple activity, we see a generated class MainActivity$startCoroutine$coroutine$1 that extends SuspendLambda and implements Function2 . The class contains two crucial methods:

invokeSuspend() – controls execution flow via a label state machine.

create() – receives a Continuation and returns a new coroutine body instance.

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        startCoroutine()
    }

    private fun startCoroutine() {
        val coroutine: suspend CoroutineScope.() -> Unit = {
            cumpute1()
            cumpute2()
        }
        GlobalScope.launch(block = coroutine)
    }

    suspend fun cumpute1() {
        print("cupmpute1")
    }

    suspend fun cumpute2() {
        print("cupmpute1")
    }
}

After decompilation, the coroutine property becomes a class extending SuspendLambda . The inheritance chain is:

SuspendLambda → ContinuationImpl → BaseContinuationImpl → Continuation

Launching a Coroutine

The launch() extension on CoroutineScope merges the provided CoroutineContext with the scope’s context, creates a concrete AbstractCoroutine (either StandaloneCoroutine or LazyStandaloneCoroutine ), and starts it:

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy) LazyStandaloneCoroutine(newContext, block) else StandaloneCoroutine(newContext, true)
    coroutine.start(start, coroutine, block)
    return coroutine
}

CoroutineStart determines how the coroutine is scheduled (DEFAULT, LAZY, ATOMIC, UNDISPATCHED). The start() call eventually invokes startCoroutineCancellable , which creates a Continuation for the suspend lambda and passes it to the dispatcher.

Dispatcher Interception

The created continuation is intercepted by the ContinuationInterceptor stored in the context (defaulting to Dispatchers.Default ). Interception wraps the original continuation in a DispatchedContinuation that holds a reference to the dispatcher.

public final override fun
interceptContinuation(continuation: Continuation
): Continuation
=
    DispatchedContinuation(this, continuation)

When resumeCancellableWith is called, the dispatcher decides whether to dispatch the continuation to another thread or resume it immediately.

public fun
Continuation
.resumeCancellableWith(
    result: Result
,
    onCancellation: ((cause: Throwable) -> Unit)? = null
) {
    if (dispatcher.isDispatchNeeded(context)) {
        _state = state
        resumeMode = MODE_CANCELLABLE
        dispatcher.dispatch(context, this)
    } else {
        // direct resume
    }
}

Suspension

Inside invokeSuspend , the coroutine checks the label to decide which part of the code to execute. When a suspend function is called, it returns the special marker COROUTINE_SUSPENDED . The runtime then returns this marker to the caller, effectively pausing the coroutine without blocking the thread.

Resumption

Resumption happens when the dispatcher later executes the DispatchedContinuation . Its run() method retrieves the stored state, restores the original continuation, and calls continuation.resume() , which ultimately invokes resumeWith on BaseContinuationImpl . This method loops, calling invokeSuspend again with the new result, advancing the state machine until the coroutine completes.

public final override fun resumeWith(result: Result
) {
    var current = this
    var param = result
    while (true) {
        probeCoroutineResumed(current)
        with(current) {
            val completion = completion!!
            val outcome = try {
                val outcome = invokeSuspend(param)
                if (outcome === COROUTINE_SUSPENDED) return
                Result.success(outcome)
            } catch (e: Throwable) {
                Result.failure(e)
            }
            releaseIntercepted()
            if (completion is BaseContinuationImpl) {
                current = completion
                param = outcome
            } else {
                completion.resumeWith(outcome)
                return
            }
        }
    }
}

Summary

The coroutine body is compiled into a SuspendLambda subclass, launch creates an AbstractCoroutine to manage results, the continuation is intercepted and wrapped by a dispatcher, suspension returns COROUTINE_SUSPENDED , and resumption is performed by the dispatcher invoking resumeWith which drives the state‑machine until completion.

Concurrencysource code analysisKotlincoroutinessuspendresume
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.