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