xref: /openbmc/qemu/util/qemu-coroutine-sleep.c (revision 3d692649)
110817bf0SDaniel P. Berrange /*
210817bf0SDaniel P. Berrange  * QEMU coroutine sleep
310817bf0SDaniel P. Berrange  *
410817bf0SDaniel P. Berrange  * Copyright IBM, Corp. 2011
510817bf0SDaniel P. Berrange  *
610817bf0SDaniel P. Berrange  * Authors:
710817bf0SDaniel P. Berrange  *  Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
810817bf0SDaniel P. Berrange  *
910817bf0SDaniel P. Berrange  * This work is licensed under the terms of the GNU LGPL, version 2 or later.
1010817bf0SDaniel P. Berrange  * See the COPYING.LIB file in the top-level directory.
1110817bf0SDaniel P. Berrange  *
1210817bf0SDaniel P. Berrange  */
1310817bf0SDaniel P. Berrange 
14aafd7584SPeter Maydell #include "qemu/osdep.h"
1510817bf0SDaniel P. Berrange #include "qemu/coroutine.h"
166133b39fSJeff Cody #include "qemu/coroutine_int.h"
1710817bf0SDaniel P. Berrange #include "qemu/timer.h"
1810817bf0SDaniel P. Berrange #include "block/aio.h"
1910817bf0SDaniel P. Berrange 
20*3d692649SVladimir Sementsov-Ogievskiy static const char *qemu_co_sleep_ns__scheduled = "qemu_co_sleep_ns";
2110817bf0SDaniel P. Berrange 
22*3d692649SVladimir Sementsov-Ogievskiy struct QemuCoSleepState {
23*3d692649SVladimir Sementsov-Ogievskiy     Coroutine *co;
24*3d692649SVladimir Sementsov-Ogievskiy     QEMUTimer *ts;
25*3d692649SVladimir Sementsov-Ogievskiy     QemuCoSleepState **user_state_pointer;
26*3d692649SVladimir Sementsov-Ogievskiy };
27*3d692649SVladimir Sementsov-Ogievskiy 
28*3d692649SVladimir Sementsov-Ogievskiy void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
29*3d692649SVladimir Sementsov-Ogievskiy {
306133b39fSJeff Cody     /* Write of schedule protected by barrier write in aio_co_schedule */
31*3d692649SVladimir Sementsov-Ogievskiy     const char *scheduled = atomic_cmpxchg(&sleep_state->co->scheduled,
32*3d692649SVladimir Sementsov-Ogievskiy                                            qemu_co_sleep_ns__scheduled, NULL);
33*3d692649SVladimir Sementsov-Ogievskiy 
34*3d692649SVladimir Sementsov-Ogievskiy     assert(scheduled == qemu_co_sleep_ns__scheduled);
35*3d692649SVladimir Sementsov-Ogievskiy     if (sleep_state->user_state_pointer) {
36*3d692649SVladimir Sementsov-Ogievskiy         *sleep_state->user_state_pointer = NULL;
37*3d692649SVladimir Sementsov-Ogievskiy     }
38*3d692649SVladimir Sementsov-Ogievskiy     timer_del(sleep_state->ts);
39*3d692649SVladimir Sementsov-Ogievskiy     aio_co_wake(sleep_state->co);
4010817bf0SDaniel P. Berrange }
4110817bf0SDaniel P. Berrange 
42*3d692649SVladimir Sementsov-Ogievskiy static void co_sleep_cb(void *opaque)
43*3d692649SVladimir Sementsov-Ogievskiy {
44*3d692649SVladimir Sementsov-Ogievskiy     qemu_co_sleep_wake(opaque);
45*3d692649SVladimir Sementsov-Ogievskiy }
46*3d692649SVladimir Sementsov-Ogievskiy 
47*3d692649SVladimir Sementsov-Ogievskiy void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
48*3d692649SVladimir Sementsov-Ogievskiy                                             QemuCoSleepState **sleep_state)
4910817bf0SDaniel P. Berrange {
5078f1d3d6SStefan Hajnoczi     AioContext *ctx = qemu_get_current_aio_context();
51*3d692649SVladimir Sementsov-Ogievskiy     QemuCoSleepState state = {
52*3d692649SVladimir Sementsov-Ogievskiy         .co = qemu_coroutine_self(),
53*3d692649SVladimir Sementsov-Ogievskiy         .ts = aio_timer_new(ctx, type, SCALE_NS, co_sleep_cb, &state),
54*3d692649SVladimir Sementsov-Ogievskiy         .user_state_pointer = sleep_state,
55*3d692649SVladimir Sementsov-Ogievskiy     };
566133b39fSJeff Cody 
57*3d692649SVladimir Sementsov-Ogievskiy     const char *scheduled = atomic_cmpxchg(&state.co->scheduled, NULL,
58*3d692649SVladimir Sementsov-Ogievskiy                                            qemu_co_sleep_ns__scheduled);
596133b39fSJeff Cody     if (scheduled) {
606133b39fSJeff Cody         fprintf(stderr,
616133b39fSJeff Cody                 "%s: Co-routine was already scheduled in '%s'\n",
626133b39fSJeff Cody                 __func__, scheduled);
636133b39fSJeff Cody         abort();
646133b39fSJeff Cody     }
65*3d692649SVladimir Sementsov-Ogievskiy 
66*3d692649SVladimir Sementsov-Ogievskiy     if (sleep_state) {
67*3d692649SVladimir Sementsov-Ogievskiy         *sleep_state = &state;
68*3d692649SVladimir Sementsov-Ogievskiy     }
69*3d692649SVladimir Sementsov-Ogievskiy     timer_mod(state.ts, qemu_clock_get_ns(type) + ns);
7010817bf0SDaniel P. Berrange     qemu_coroutine_yield();
71*3d692649SVladimir Sementsov-Ogievskiy     timer_free(state.ts);
7210817bf0SDaniel P. Berrange }
73