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