qemu/util/qemu-coroutine-sleep.c
<<
>>
Prefs
   1/*
   2 * QEMU coroutine sleep
   3 *
   4 * Copyright IBM, Corp. 2011
   5 *
   6 * Authors:
   7 *  Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
   8 *
   9 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
  10 * See the COPYING.LIB file in the top-level directory.
  11 *
  12 */
  13
  14#include "qemu/osdep.h"
  15#include "qemu/coroutine.h"
  16#include "qemu/coroutine_int.h"
  17#include "qemu/timer.h"
  18#include "block/aio.h"
  19
  20static const char *qemu_co_sleep_ns__scheduled = "qemu_co_sleep_ns";
  21
  22struct QemuCoSleepState {
  23    Coroutine *co;
  24    QEMUTimer *ts;
  25    QemuCoSleepState **user_state_pointer;
  26};
  27
  28void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
  29{
  30    /* Write of schedule protected by barrier write in aio_co_schedule */
  31    const char *scheduled = atomic_cmpxchg(&sleep_state->co->scheduled,
  32                                           qemu_co_sleep_ns__scheduled, NULL);
  33
  34    assert(scheduled == qemu_co_sleep_ns__scheduled);
  35    if (sleep_state->user_state_pointer) {
  36        *sleep_state->user_state_pointer = NULL;
  37    }
  38    timer_del(sleep_state->ts);
  39    aio_co_wake(sleep_state->co);
  40}
  41
  42static void co_sleep_cb(void *opaque)
  43{
  44    qemu_co_sleep_wake(opaque);
  45}
  46
  47void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
  48                                            QemuCoSleepState **sleep_state)
  49{
  50    AioContext *ctx = qemu_get_current_aio_context();
  51    QemuCoSleepState state = {
  52        .co = qemu_coroutine_self(),
  53        .ts = aio_timer_new(ctx, type, SCALE_NS, co_sleep_cb, &state),
  54        .user_state_pointer = sleep_state,
  55    };
  56
  57    const char *scheduled = atomic_cmpxchg(&state.co->scheduled, NULL,
  58                                           qemu_co_sleep_ns__scheduled);
  59    if (scheduled) {
  60        fprintf(stderr,
  61                "%s: Co-routine was already scheduled in '%s'\n",
  62                __func__, scheduled);
  63        abort();
  64    }
  65
  66    if (sleep_state) {
  67        *sleep_state = &state;
  68    }
  69    timer_mod(state.ts, qemu_clock_get_ns(type) + ns);
  70    qemu_coroutine_yield();
  71    if (sleep_state) {
  72        /*
  73         * Note that *sleep_state is cleared during qemu_co_sleep_wake
  74         * before resuming this coroutine.
  75         */
  76        assert(*sleep_state == NULL);
  77    }
  78    timer_free(state.ts);
  79}
  80