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