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