From c40a2545700e9ad2ef67d5972484bbee4c83b2a6 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 22 Mar 2018 15:28:33 +0000 Subject: coroutine: avoid co_queue_wakeup recursion qemu_aio_coroutine_enter() is (indirectly) called recursively when processing co_queue_wakeup. This can lead to stack exhaustion. This patch rewrites co_queue_wakeup in an iterative fashion (instead of recursive) with bounded memory usage to prevent stack exhaustion. qemu_co_queue_run_restart() is inlined into qemu_aio_coroutine_enter() and the qemu_coroutine_enter() call is turned into a loop to avoid recursion. There is one change that is worth mentioning: Previously, when coroutine A queued coroutine B, qemu_co_queue_run_restart() entered coroutine B from coroutine A. If A was terminating then it would still stay alive until B yielded. After this patch B is entered by A's parent so that a A can be deleted immediately if it is terminating. It is safe to make this change since B could never interact with A if it was terminating anyway. Signed-off-by: Stefan Hajnoczi Reviewed-by: Paolo Bonzini Message-id: 20180322152834.12656-3-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- block/io.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'block') diff --git a/block/io.c b/block/io.c index 2b09c65..bd9a19a 100644 --- a/block/io.c +++ b/block/io.c @@ -249,8 +249,7 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, BdrvCoDrainData data; /* Calling bdrv_drain() from a BH ensures the current coroutine yields and - * other coroutines run if they were queued from - * qemu_co_queue_run_restart(). */ + * other coroutines run if they were queued by aio_co_enter(). */ assert(qemu_in_coroutine()); data = (BdrvCoDrainData) { -- cgit v1.1