qemu/replay/replay-events.c
<<
>>
Prefs
   1/*
   2 * replay-events.c
   3 *
   4 * Copyright (c) 2010-2015 Institute for System Programming
   5 *                         of the Russian Academy of Sciences.
   6 *
   7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   8 * See the COPYING file in the top-level directory.
   9 *
  10 */
  11
  12#include "qemu/osdep.h"
  13#include "qemu/error-report.h"
  14#include "sysemu/replay.h"
  15#include "replay-internal.h"
  16#include "block/aio.h"
  17#include "ui/input.h"
  18#include "hw/core/cpu.h"
  19
  20typedef struct Event {
  21    ReplayAsyncEventKind event_kind;
  22    void *opaque;
  23    void *opaque2;
  24    uint64_t id;
  25
  26    QTAILQ_ENTRY(Event) events;
  27} Event;
  28
  29static QTAILQ_HEAD(, Event) events_list = QTAILQ_HEAD_INITIALIZER(events_list);
  30static bool events_enabled;
  31
  32/* Functions */
  33
  34static void replay_run_event(Event *event)
  35{
  36    switch (event->event_kind) {
  37    case REPLAY_ASYNC_EVENT_BH:
  38        aio_bh_call(event->opaque);
  39        break;
  40    case REPLAY_ASYNC_EVENT_BH_ONESHOT:
  41        ((QEMUBHFunc *)event->opaque)(event->opaque2);
  42        break;
  43    case REPLAY_ASYNC_EVENT_INPUT:
  44        qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque);
  45        qapi_free_InputEvent((InputEvent *)event->opaque);
  46        break;
  47    case REPLAY_ASYNC_EVENT_INPUT_SYNC:
  48        qemu_input_event_sync_impl();
  49        break;
  50    case REPLAY_ASYNC_EVENT_CHAR_READ:
  51        replay_event_char_read_run(event->opaque);
  52        break;
  53    case REPLAY_ASYNC_EVENT_BLOCK:
  54        aio_bh_call(event->opaque);
  55        break;
  56    case REPLAY_ASYNC_EVENT_NET:
  57        replay_event_net_run(event->opaque);
  58        break;
  59    default:
  60        error_report("Replay: invalid async event ID (%d) in the queue",
  61                    event->event_kind);
  62        exit(1);
  63        break;
  64    }
  65}
  66
  67void replay_enable_events(void)
  68{
  69    if (replay_mode != REPLAY_MODE_NONE) {
  70        events_enabled = true;
  71    }
  72}
  73
  74bool replay_has_events(void)
  75{
  76    return !QTAILQ_EMPTY(&events_list);
  77}
  78
  79void replay_flush_events(void)
  80{
  81    if (replay_mode == REPLAY_MODE_NONE) {
  82        return;
  83    }
  84
  85    g_assert(replay_mutex_locked());
  86
  87    while (!QTAILQ_EMPTY(&events_list)) {
  88        Event *event = QTAILQ_FIRST(&events_list);
  89        replay_run_event(event);
  90        QTAILQ_REMOVE(&events_list, event, events);
  91        g_free(event);
  92    }
  93}
  94
  95void replay_disable_events(void)
  96{
  97    if (replay_mode != REPLAY_MODE_NONE) {
  98        events_enabled = false;
  99        /* Flush events queue before waiting of completion */
 100        replay_flush_events();
 101    }
 102}
 103
 104/*! Adds specified async event to the queue */
 105void replay_add_event(ReplayAsyncEventKind event_kind,
 106                      void *opaque,
 107                      void *opaque2, uint64_t id)
 108{
 109    assert(event_kind < REPLAY_ASYNC_COUNT);
 110
 111    if (!replay_file || replay_mode == REPLAY_MODE_NONE
 112        || !events_enabled) {
 113        Event e;
 114        e.event_kind = event_kind;
 115        e.opaque = opaque;
 116        e.opaque2 = opaque2;
 117        e.id = id;
 118        replay_run_event(&e);
 119        return;
 120    }
 121
 122    Event *event = g_new0(Event, 1);
 123    event->event_kind = event_kind;
 124    event->opaque = opaque;
 125    event->opaque2 = opaque2;
 126    event->id = id;
 127
 128    g_assert(replay_mutex_locked());
 129    QTAILQ_INSERT_TAIL(&events_list, event, events);
 130    qemu_cpu_kick(first_cpu);
 131}
 132
 133void replay_bh_schedule_event(QEMUBH *bh)
 134{
 135    if (events_enabled) {
 136        uint64_t id = replay_get_current_icount();
 137        replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id);
 138    } else {
 139        qemu_bh_schedule(bh);
 140    }
 141}
 142
 143void replay_bh_schedule_oneshot_event(AioContext *ctx,
 144    QEMUBHFunc *cb, void *opaque)
 145{
 146    if (events_enabled) {
 147        uint64_t id = replay_get_current_icount();
 148        replay_add_event(REPLAY_ASYNC_EVENT_BH_ONESHOT, cb, opaque, id);
 149    } else {
 150        aio_bh_schedule_oneshot(ctx, cb, opaque);
 151    }
 152}
 153
 154void replay_add_input_event(struct InputEvent *event)
 155{
 156    replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0);
 157}
 158
 159void replay_add_input_sync_event(void)
 160{
 161    replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0);
 162}
 163
 164void replay_block_event(QEMUBH *bh, uint64_t id)
 165{
 166    if (events_enabled) {
 167        replay_add_event(REPLAY_ASYNC_EVENT_BLOCK, bh, NULL, id);
 168    } else {
 169        qemu_bh_schedule(bh);
 170    }
 171}
 172
 173static void replay_save_event(Event *event)
 174{
 175    if (replay_mode != REPLAY_MODE_PLAY) {
 176        /* put the event into the file */
 177        g_assert(event->event_kind < REPLAY_ASYNC_COUNT);
 178        replay_put_event(EVENT_ASYNC + event->event_kind);
 179
 180        /* save event-specific data */
 181        switch (event->event_kind) {
 182        case REPLAY_ASYNC_EVENT_BH:
 183        case REPLAY_ASYNC_EVENT_BH_ONESHOT:
 184            replay_put_qword(event->id);
 185            break;
 186        case REPLAY_ASYNC_EVENT_INPUT:
 187            replay_save_input_event(event->opaque);
 188            break;
 189        case REPLAY_ASYNC_EVENT_INPUT_SYNC:
 190            break;
 191        case REPLAY_ASYNC_EVENT_CHAR_READ:
 192            replay_event_char_read_save(event->opaque);
 193            break;
 194        case REPLAY_ASYNC_EVENT_BLOCK:
 195            replay_put_qword(event->id);
 196            break;
 197        case REPLAY_ASYNC_EVENT_NET:
 198            replay_event_net_save(event->opaque);
 199            break;
 200        default:
 201            error_report("Unknown ID %" PRId64 " of replay event", event->id);
 202            exit(1);
 203        }
 204    }
 205}
 206
 207/* Called with replay mutex locked */
 208void replay_save_events(void)
 209{
 210    g_assert(replay_mutex_locked());
 211    while (!QTAILQ_EMPTY(&events_list)) {
 212        Event *event = QTAILQ_FIRST(&events_list);
 213        replay_save_event(event);
 214        replay_run_event(event);
 215        QTAILQ_REMOVE(&events_list, event, events);
 216        g_free(event);
 217    }
 218}
 219
 220static Event *replay_read_event(void)
 221{
 222    Event *event;
 223    ReplayAsyncEventKind event_kind = replay_state.data_kind - EVENT_ASYNC;
 224
 225    /* Events that has not to be in the queue */
 226    switch (event_kind) {
 227    case REPLAY_ASYNC_EVENT_BH:
 228    case REPLAY_ASYNC_EVENT_BH_ONESHOT:
 229        if (replay_state.read_event_id == -1) {
 230            replay_state.read_event_id = replay_get_qword();
 231        }
 232        break;
 233    case REPLAY_ASYNC_EVENT_INPUT:
 234        event = g_new0(Event, 1);
 235        event->event_kind = event_kind;
 236        event->opaque = replay_read_input_event();
 237        return event;
 238    case REPLAY_ASYNC_EVENT_INPUT_SYNC:
 239        event = g_new0(Event, 1);
 240        event->event_kind = event_kind;
 241        event->opaque = 0;
 242        return event;
 243    case REPLAY_ASYNC_EVENT_CHAR_READ:
 244        event = g_new0(Event, 1);
 245        event->event_kind = event_kind;
 246        event->opaque = replay_event_char_read_load();
 247        return event;
 248    case REPLAY_ASYNC_EVENT_BLOCK:
 249        if (replay_state.read_event_id == -1) {
 250            replay_state.read_event_id = replay_get_qword();
 251        }
 252        break;
 253    case REPLAY_ASYNC_EVENT_NET:
 254        event = g_new0(Event, 1);
 255        event->event_kind = event_kind;
 256        event->opaque = replay_event_net_load();
 257        return event;
 258    default:
 259        error_report("Unknown ID %d of replay event", event_kind);
 260        exit(1);
 261        break;
 262    }
 263
 264    QTAILQ_FOREACH(event, &events_list, events) {
 265        if (event->event_kind == event_kind
 266            && (replay_state.read_event_id == -1
 267                || replay_state.read_event_id == event->id)) {
 268            break;
 269        }
 270    }
 271
 272    if (event) {
 273        QTAILQ_REMOVE(&events_list, event, events);
 274    }
 275
 276    return event;
 277}
 278
 279/* Called with replay mutex locked */
 280void replay_read_events(void)
 281{
 282    g_assert(replay_mutex_locked());
 283    while (replay_state.data_kind >= EVENT_ASYNC
 284        && replay_state.data_kind <= EVENT_ASYNC_LAST) {
 285        Event *event = replay_read_event();
 286        if (!event) {
 287            break;
 288        }
 289        replay_finish_event();
 290        replay_state.read_event_id = -1;
 291        replay_run_event(event);
 292
 293        g_free(event);
 294    }
 295}
 296
 297void replay_init_events(void)
 298{
 299    replay_state.read_event_id = -1;
 300}
 301
 302void replay_finish_events(void)
 303{
 304    events_enabled = false;
 305    replay_flush_events();
 306}
 307
 308bool replay_events_enabled(void)
 309{
 310    return events_enabled;
 311}
 312
 313uint64_t blkreplay_next_id(void)
 314{
 315    if (replay_events_enabled()) {
 316        return replay_state.block_request_id++;
 317    }
 318    return 0;
 319}
 320