All block I/O functions are coroutines...
... as well as some QMP commands (e.g. Block Jobs)
Coroutine *qemu_coroutine_new(void)
{
/* [...] */
arg.p = co;
makecontext(&uc, (void (*)(void))coroutine_trampoline,
2, arg.i[0], arg.i[1]);
/* swapcontext() in, siglongjmp() back out */
if (!sigsetjmp(old_env, 0)) {
swapcontext(&old_uc, &uc);
}
return &co->base;
}
/*
* we want to use bottom half because we want to make sure the below
* sequence of events.
*
* 1. Yield the coroutine in the QEMU thread.
* 2. Submit the coroutine to a worker thread.
* 3. Enter the coroutine in the worker thread.
* we cannot swap step 1 and 2, because that would imply worker thread
* can enter coroutine while step1 is still running
*/
#define v9fs_co_run_in_worker(code_block) \
do { \
QEMUBH *co_bh; \
co_bh = qemu_bh_new(co_run_in_worker_bh, \
qemu_coroutine_self()); \
qemu_bh_schedule(co_bh); \
/* \
* yield in qemu thread and re-enter back \
* in worker thread \
*/ \
qemu_coroutine_yield(); \
qemu_bh_delete(co_bh); \
code_block; \
/* re-enter back to qemu thread */ \
qemu_coroutine_yield(); \
} while (0)