qemu-block
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 09/35] convert qemu-coroutine-sleep.c to stackless coroutines


From: Paolo Bonzini
Subject: [PATCH 09/35] convert qemu-coroutine-sleep.c to stackless coroutines
Date: Thu, 10 Mar 2022 13:43:47 +0100

The main change is to qemu_co_sleep_ns_wakeable, which gets the full
conversion treatment.  It's important to note that variables that escape
(have their address taken), such as "QEMUTimer ts" in this case, move
entirely to the frame structure and do not have local variables anymore.
For the others, always using the frame structure would be inefficient,
so they need to be saved and restored.  Perhaps "restrict" would be
an idea too, I haven't investigated it.

qemu_co_sleep almost has a tail call to qemu_coroutine_yield(), except for
an assertion after qemu_coroutine_yield() returns.  For simplicity and
to demonstrate the optimization I'm removing the assertion.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 util/qemu-coroutine-sleep.c | 59 ++++++++++++++++++++++++++++---------
 1 file changed, 45 insertions(+), 14 deletions(-)

diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
index b5bfb4ad18..3d0b1579b3 100644
--- a/util/qemu-coroutine-sleep.c
+++ b/util/qemu-coroutine-sleep.c
@@ -17,7 +17,6 @@
 #include "qemu/timer.h"
 #include "block/aio.h"
 
-#if 0
 static const char *qemu_co_sleep_ns__scheduled = "qemu_co_sleep_ns";
 
 void qemu_co_sleep_wake(QemuCoSleep *w)
@@ -42,7 +41,7 @@ static void co_sleep_cb(void *opaque)
     qemu_co_sleep_wake(w);
 }
 
-void coroutine_fn qemu_co_sleep(QemuCoSleep *w)
+CoroutineAction qemu_co_sleep(QemuCoSleep *w)
 {
     Coroutine *co = qemu_coroutine_self();
 
@@ -56,27 +55,59 @@ void coroutine_fn qemu_co_sleep(QemuCoSleep *w)
     }
 
     w->to_wake = co;
-    qemu_coroutine_yield();
+    return qemu_coroutine_yield();
 
     /* w->to_wake is cleared before resuming this coroutine.  */
-    assert(w->to_wake == NULL);
+    // 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;
+struct FRAME__qemu_co_sleep_ns_wakeable {
+       CoroutineFrame common;
+       uint32_t _step;
+        QemuCoSleep *w;
+        QEMUClockType type;
+        int64_t ns;
+       QEMUTimer ts;
+};
 
-    aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, w);
-    timer_mod(&ts, qemu_clock_get_ns(type) + ns);
+static CoroutineAction co__qemu_co_sleep_ns_wakeable(void *_frame)
+{
+    struct FRAME__qemu_co_sleep_ns_wakeable *_f = _frame;
+    AioContext *ctx = qemu_get_current_aio_context();
+
+switch(_f->_step) {
+case 0: {
+    QemuCoSleep *w = _f->w;
+    QEMUClockType type = _f->type;
+    int64_t ns = _f->ns;
+    aio_timer_init(ctx, &_f->ts, type, SCALE_NS, co_sleep_cb, w);
+    timer_mod(&_f->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);
+_f->_step = 1;
+    return qemu_co_sleep(w);
+}
+case 1:
+    timer_del(&_f->ts);
+    goto _out;
+}
+_out:
+stack_free(&_f->common);
+return COROUTINE_CONTINUE;
+}
+
+CoroutineAction qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
+                                          QEMUClockType type, int64_t ns)
+{
+    struct FRAME__qemu_co_sleep_ns_wakeable *f;
+    f = stack_alloc(co__qemu_co_sleep_ns_wakeable, sizeof(*f));
+    f->w = w;
+    f->type = type;
+    f->ns = ns;
+    f->_step = 0;
+    return co__qemu_co_sleep_ns_wakeable(f);
 }
-#endif
-- 
2.35.1





reply via email to

[Prev in Thread] Current Thread [Next in Thread]