Current implementation of qemu_co_queue_do_restart does not releases the lock before calling aio_co_wake. Most of the time this is fine, but if the coroutine acquires the lock again then we have a deadlock.
Instead of duplicating code, use qemu_co_enter_next_impl, since it implements exactly the same functionality that we want. Signed-off-by: Emanuele Giuseppe Esposito <eespo...@redhat.com> --- include/qemu/coroutine.h | 10 ++++++++++ util/qemu-coroutine-lock.c | 26 ++++++++++---------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index c828a95ee0..c49cdc21b4 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -220,6 +220,16 @@ bool qemu_co_queue_next(CoQueue *queue); */ void qemu_co_queue_restart_all(CoQueue *queue); +/** + * Empties the CoQueue; all coroutines are woken up. + * OK to run from coroutine and non-coroutine context. + * Unlocks lock before waking up each coroutine takes it again + * when done. + */ +#define qemu_co_queue_restart_all_lockable(queue, lock) \ + qemu_co_queue_restart_all_impl(queue, QEMU_MAKE_LOCKABLE(lock)) +void qemu_co_queue_restart_all_impl(CoQueue *queue, QemuLockable *lock); + /** * Removes the next coroutine from the CoQueue, and wake it up. Unlike * qemu_co_queue_next, this function releases the lock during aio_co_wake diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c index 2669403839..17bb0d0c95 100644 --- a/util/qemu-coroutine-lock.c +++ b/util/qemu-coroutine-lock.c @@ -67,32 +67,26 @@ void coroutine_fn qemu_co_queue_wait_impl(CoQueue *queue, QemuLockable *lock) } } -static bool qemu_co_queue_do_restart(CoQueue *queue, bool single) +static void qemu_co_queue_do_restart(CoQueue *queue, QemuLockable *lock) { - Coroutine *next; - - if (QSIMPLEQ_EMPTY(&queue->entries)) { - return false; + while (qemu_co_enter_next_impl(queue, lock)) { + /* nop */ } - - while ((next = QSIMPLEQ_FIRST(&queue->entries)) != NULL) { - QSIMPLEQ_REMOVE_HEAD(&queue->entries, co_queue_next); - aio_co_wake(next); - if (single) { - break; - } - } - return true; } bool qemu_co_queue_next(CoQueue *queue) { - return qemu_co_queue_do_restart(queue, true); + return qemu_co_enter_next_impl(queue, NULL); } void qemu_co_queue_restart_all(CoQueue *queue) { - qemu_co_queue_do_restart(queue, false); + qemu_co_queue_do_restart(queue, NULL); +} + +void qemu_co_queue_restart_all_impl(CoQueue *queue, QemuLockable *lock) +{ + qemu_co_queue_do_restart(queue, lock); } bool qemu_co_enter_next_impl(CoQueue *queue, QemuLockable *lock) -- 2.31.1