aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/qemu/coroutine.h5
-rw-r--r--util/qemu-coroutine-sleep.c26
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);
+}