From 0a6f0c76a030710780ce10d6347a70f098024d21 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 May 2021 12:05:48 +0200 Subject: [PATCH] coroutine-sleep: introduce qemu_co_sleep Allow using QemuCoSleep to sleep forever until woken by qemu_co_sleep_wake. This makes the logic of qemu_co_sleep_ns_wakeable easy to understand. In the future we will introduce an API that can work even if the sleep and wake happen from different threads. For now, initializing w->to_wake after timer_mod is fine because the timer can only fire in the same AioContext. Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Paolo Bonzini Message-id: 20210517100548.28806-7-pbonzini@redhat.com Signed-off-by: Stefan Hajnoczi --- include/qemu/coroutine.h | 5 +++++ util/qemu-coroutine-sleep.c | 26 +++++++++++++++++++------- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index 82c0671f80..292e61aef0 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -303,6 +303,11 @@ typedef struct QemuCoSleep { void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w, QEMUClockType type, int64_t ns); +/** + * Yield the coroutine until the next call to qemu_co_sleep_wake. + */ +void coroutine_fn qemu_co_sleep(QemuCoSleep *w); + static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns) { QemuCoSleep w = { 0 }; diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c index 89c3b758c5..571ab521ff 100644 --- a/util/qemu-coroutine-sleep.c +++ b/util/qemu-coroutine-sleep.c @@ -41,12 +41,9 @@ static void co_sleep_cb(void *opaque) qemu_co_sleep_wake(w); } -void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w, - QEMUClockType type, int64_t ns) +void coroutine_fn qemu_co_sleep(QemuCoSleep *w) { Coroutine *co = qemu_coroutine_self(); - AioContext *ctx = qemu_get_current_aio_context(); - QEMUTimer ts; const char *scheduled = qatomic_cmpxchg(&co->scheduled, NULL, qemu_co_sleep_ns__scheduled); @@ -58,11 +55,26 @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w, } w->to_wake = co; - aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, w), - timer_mod(&ts, qemu_clock_get_ns(type) + ns); qemu_coroutine_yield(); - timer_del(&ts); /* w->to_wake is cleared before resuming this coroutine. */ assert(w->to_wake == NULL); } + +void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w, + QEMUClockType type, int64_t ns) +{ + AioContext *ctx = qemu_get_current_aio_context(); + QEMUTimer ts; + + aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, w); + timer_mod(&ts, qemu_clock_get_ns(type) + ns); + + /* + * The timer will fire in the current AiOContext, so the callback + * must happen after qemu_co_sleep yields and there is no race + * between timer_mod and qemu_co_sleep. + */ + qemu_co_sleep(w); + timer_del(&ts); +}