This is rather hard to explain fully in just a few sentences, but it works like this:
- Before the code suspends, continuation is created. Continuation is an object that knows how to resume the code from the point where it stopped. It keeps a reference to the current function, to the previous functions on the call stack (technically: to previous continuations), it stores local variables, code offset/location inside the function, etc.
- Continuation is passed to the component that controls when to resume - continuation is stored there. For example, when we invoke
delay()
then delay()
gets our continuation and keeps it for later.
- Execution returns through the whole call stack, making the thread free to do something else.
- When conditions for resuming are met, continuation is scheduled on dispatcher to be executed.
- Function where we previously suspended is invoked again, local variables are restored from the continuation and the execution jumps to the offset where it stopped. This effectively resumes a coroutine.