1c0c071d0SPavel Dovgalyuk /* 2c0c071d0SPavel Dovgalyuk * replay-events.c 3c0c071d0SPavel Dovgalyuk * 4c0c071d0SPavel Dovgalyuk * Copyright (c) 2010-2015 Institute for System Programming 5c0c071d0SPavel Dovgalyuk * of the Russian Academy of Sciences. 6c0c071d0SPavel Dovgalyuk * 7c0c071d0SPavel Dovgalyuk * This work is licensed under the terms of the GNU GPL, version 2 or later. 8c0c071d0SPavel Dovgalyuk * See the COPYING file in the top-level directory. 9c0c071d0SPavel Dovgalyuk * 10c0c071d0SPavel Dovgalyuk */ 11c0c071d0SPavel Dovgalyuk 12d38ea87aSPeter Maydell #include "qemu/osdep.h" 13c0c071d0SPavel Dovgalyuk #include "qemu/error-report.h" 14c0c071d0SPavel Dovgalyuk #include "sysemu/replay.h" 15c0c071d0SPavel Dovgalyuk #include "replay-internal.h" 168a354bd9SPavel Dovgalyuk #include "block/aio.h" 17ee312992SPavel Dovgalyuk #include "ui/input.h" 18c0c071d0SPavel Dovgalyuk 19c0c071d0SPavel Dovgalyuk typedef struct Event { 20c0c071d0SPavel Dovgalyuk ReplayAsyncEventKind event_kind; 21c0c071d0SPavel Dovgalyuk void *opaque; 22c0c071d0SPavel Dovgalyuk void *opaque2; 23c0c071d0SPavel Dovgalyuk uint64_t id; 24c0c071d0SPavel Dovgalyuk 25c0c071d0SPavel Dovgalyuk QTAILQ_ENTRY(Event) events; 26c0c071d0SPavel Dovgalyuk } Event; 27c0c071d0SPavel Dovgalyuk 28c0c071d0SPavel Dovgalyuk static QTAILQ_HEAD(, Event) events_list = QTAILQ_HEAD_INITIALIZER(events_list); 29c0c071d0SPavel Dovgalyuk static bool events_enabled; 30c0c071d0SPavel Dovgalyuk 31c0c071d0SPavel Dovgalyuk /* Functions */ 32c0c071d0SPavel Dovgalyuk 33c0c071d0SPavel Dovgalyuk static void replay_run_event(Event *event) 34c0c071d0SPavel Dovgalyuk { 35c0c071d0SPavel Dovgalyuk switch (event->event_kind) { 368a354bd9SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH: 378a354bd9SPavel Dovgalyuk aio_bh_call(event->opaque); 388a354bd9SPavel Dovgalyuk break; 39*e4ec5ad4SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH_ONESHOT: 40*e4ec5ad4SPavel Dovgalyuk ((QEMUBHFunc *)event->opaque)(event->opaque2); 41*e4ec5ad4SPavel Dovgalyuk break; 42ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT: 43ee312992SPavel Dovgalyuk qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque); 44ee312992SPavel Dovgalyuk qapi_free_InputEvent((InputEvent *)event->opaque); 45ee312992SPavel Dovgalyuk break; 46ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT_SYNC: 47ee312992SPavel Dovgalyuk qemu_input_event_sync_impl(); 48ee312992SPavel Dovgalyuk break; 4933577b47SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_CHAR_READ: 5033577b47SPavel Dovgalyuk replay_event_char_read_run(event->opaque); 5133577b47SPavel Dovgalyuk break; 5263785678SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BLOCK: 5363785678SPavel Dovgalyuk aio_bh_call(event->opaque); 5463785678SPavel Dovgalyuk break; 55646c5478SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_NET: 56646c5478SPavel Dovgalyuk replay_event_net_run(event->opaque); 57646c5478SPavel Dovgalyuk break; 58c0c071d0SPavel Dovgalyuk default: 59c0c071d0SPavel Dovgalyuk error_report("Replay: invalid async event ID (%d) in the queue", 60c0c071d0SPavel Dovgalyuk event->event_kind); 61c0c071d0SPavel Dovgalyuk exit(1); 62c0c071d0SPavel Dovgalyuk break; 63c0c071d0SPavel Dovgalyuk } 64c0c071d0SPavel Dovgalyuk } 65c0c071d0SPavel Dovgalyuk 66c0c071d0SPavel Dovgalyuk void replay_enable_events(void) 67c0c071d0SPavel Dovgalyuk { 681652e0c3SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_NONE) { 69c0c071d0SPavel Dovgalyuk events_enabled = true; 70c0c071d0SPavel Dovgalyuk } 711652e0c3SPavel Dovgalyuk } 72c0c071d0SPavel Dovgalyuk 73c0c071d0SPavel Dovgalyuk bool replay_has_events(void) 74c0c071d0SPavel Dovgalyuk { 75c0c071d0SPavel Dovgalyuk return !QTAILQ_EMPTY(&events_list); 76c0c071d0SPavel Dovgalyuk } 77c0c071d0SPavel Dovgalyuk 78c0c071d0SPavel Dovgalyuk void replay_flush_events(void) 79c0c071d0SPavel Dovgalyuk { 80d759c951SAlex Bennée g_assert(replay_mutex_locked()); 81d759c951SAlex Bennée 82c0c071d0SPavel Dovgalyuk while (!QTAILQ_EMPTY(&events_list)) { 83c0c071d0SPavel Dovgalyuk Event *event = QTAILQ_FIRST(&events_list); 84c0c071d0SPavel Dovgalyuk replay_run_event(event); 85c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events); 86c0c071d0SPavel Dovgalyuk g_free(event); 87c0c071d0SPavel Dovgalyuk } 88c0c071d0SPavel Dovgalyuk } 89c0c071d0SPavel Dovgalyuk 90c0c071d0SPavel Dovgalyuk void replay_disable_events(void) 91c0c071d0SPavel Dovgalyuk { 92c0c071d0SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_NONE) { 93c0c071d0SPavel Dovgalyuk events_enabled = false; 94c0c071d0SPavel Dovgalyuk /* Flush events queue before waiting of completion */ 95c0c071d0SPavel Dovgalyuk replay_flush_events(); 96c0c071d0SPavel Dovgalyuk } 97c0c071d0SPavel Dovgalyuk } 98c0c071d0SPavel Dovgalyuk 99c0c071d0SPavel Dovgalyuk /*! Adds specified async event to the queue */ 10033577b47SPavel Dovgalyuk void replay_add_event(ReplayAsyncEventKind event_kind, 101c0c071d0SPavel Dovgalyuk void *opaque, 102c0c071d0SPavel Dovgalyuk void *opaque2, uint64_t id) 103c0c071d0SPavel Dovgalyuk { 104c0c071d0SPavel Dovgalyuk assert(event_kind < REPLAY_ASYNC_COUNT); 105c0c071d0SPavel Dovgalyuk 106c0c071d0SPavel Dovgalyuk if (!replay_file || replay_mode == REPLAY_MODE_NONE 107c0c071d0SPavel Dovgalyuk || !events_enabled) { 108c0c071d0SPavel Dovgalyuk Event e; 109c0c071d0SPavel Dovgalyuk e.event_kind = event_kind; 110c0c071d0SPavel Dovgalyuk e.opaque = opaque; 111c0c071d0SPavel Dovgalyuk e.opaque2 = opaque2; 112c0c071d0SPavel Dovgalyuk e.id = id; 113c0c071d0SPavel Dovgalyuk replay_run_event(&e); 114c0c071d0SPavel Dovgalyuk return; 115c0c071d0SPavel Dovgalyuk } 116c0c071d0SPavel Dovgalyuk 117c0c071d0SPavel Dovgalyuk Event *event = g_malloc0(sizeof(Event)); 118c0c071d0SPavel Dovgalyuk event->event_kind = event_kind; 119c0c071d0SPavel Dovgalyuk event->opaque = opaque; 120c0c071d0SPavel Dovgalyuk event->opaque2 = opaque2; 121c0c071d0SPavel Dovgalyuk event->id = id; 122c0c071d0SPavel Dovgalyuk 123d759c951SAlex Bennée g_assert(replay_mutex_locked()); 124c0c071d0SPavel Dovgalyuk QTAILQ_INSERT_TAIL(&events_list, event, events); 125c0c071d0SPavel Dovgalyuk } 1268a354bd9SPavel Dovgalyuk 1278a354bd9SPavel Dovgalyuk void replay_bh_schedule_event(QEMUBH *bh) 1288a354bd9SPavel Dovgalyuk { 1291652e0c3SPavel Dovgalyuk if (events_enabled) { 13013f26713SPavel Dovgalyuk uint64_t id = replay_get_current_icount(); 1318a354bd9SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id); 1328a354bd9SPavel Dovgalyuk } else { 1338a354bd9SPavel Dovgalyuk qemu_bh_schedule(bh); 1348a354bd9SPavel Dovgalyuk } 1358a354bd9SPavel Dovgalyuk } 136c0c071d0SPavel Dovgalyuk 137*e4ec5ad4SPavel Dovgalyuk void replay_bh_schedule_oneshot_event(AioContext *ctx, 138*e4ec5ad4SPavel Dovgalyuk QEMUBHFunc *cb, void *opaque) 139*e4ec5ad4SPavel Dovgalyuk { 140*e4ec5ad4SPavel Dovgalyuk if (events_enabled) { 141*e4ec5ad4SPavel Dovgalyuk uint64_t id = replay_get_current_icount(); 142*e4ec5ad4SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_BH_ONESHOT, cb, opaque, id); 143*e4ec5ad4SPavel Dovgalyuk } else { 144*e4ec5ad4SPavel Dovgalyuk aio_bh_schedule_oneshot(ctx, cb, opaque); 145*e4ec5ad4SPavel Dovgalyuk } 146*e4ec5ad4SPavel Dovgalyuk } 147*e4ec5ad4SPavel Dovgalyuk 148ee312992SPavel Dovgalyuk void replay_add_input_event(struct InputEvent *event) 149ee312992SPavel Dovgalyuk { 150ee312992SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0); 151ee312992SPavel Dovgalyuk } 152ee312992SPavel Dovgalyuk 153ee312992SPavel Dovgalyuk void replay_add_input_sync_event(void) 154ee312992SPavel Dovgalyuk { 155ee312992SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0); 156ee312992SPavel Dovgalyuk } 157ee312992SPavel Dovgalyuk 15863785678SPavel Dovgalyuk void replay_block_event(QEMUBH *bh, uint64_t id) 15963785678SPavel Dovgalyuk { 1601652e0c3SPavel Dovgalyuk if (events_enabled) { 16163785678SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_BLOCK, bh, NULL, id); 16263785678SPavel Dovgalyuk } else { 16363785678SPavel Dovgalyuk qemu_bh_schedule(bh); 16463785678SPavel Dovgalyuk } 16563785678SPavel Dovgalyuk } 16663785678SPavel Dovgalyuk 167c0c071d0SPavel Dovgalyuk static void replay_save_event(Event *event, int checkpoint) 168c0c071d0SPavel Dovgalyuk { 169c0c071d0SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_PLAY) { 170c0c071d0SPavel Dovgalyuk /* put the event into the file */ 171c0c071d0SPavel Dovgalyuk replay_put_event(EVENT_ASYNC); 172c0c071d0SPavel Dovgalyuk replay_put_byte(checkpoint); 173c0c071d0SPavel Dovgalyuk replay_put_byte(event->event_kind); 174c0c071d0SPavel Dovgalyuk 175c0c071d0SPavel Dovgalyuk /* save event-specific data */ 176c0c071d0SPavel Dovgalyuk switch (event->event_kind) { 1778a354bd9SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH: 178*e4ec5ad4SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH_ONESHOT: 1798a354bd9SPavel Dovgalyuk replay_put_qword(event->id); 1808a354bd9SPavel Dovgalyuk break; 181ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT: 182ee312992SPavel Dovgalyuk replay_save_input_event(event->opaque); 183ee312992SPavel Dovgalyuk break; 184ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT_SYNC: 185ee312992SPavel Dovgalyuk break; 18633577b47SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_CHAR_READ: 18733577b47SPavel Dovgalyuk replay_event_char_read_save(event->opaque); 18833577b47SPavel Dovgalyuk break; 18963785678SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BLOCK: 19063785678SPavel Dovgalyuk replay_put_qword(event->id); 19163785678SPavel Dovgalyuk break; 192646c5478SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_NET: 193646c5478SPavel Dovgalyuk replay_event_net_save(event->opaque); 194646c5478SPavel Dovgalyuk break; 195c0c071d0SPavel Dovgalyuk default: 19695b4aed5SPavel Dovgalyuk error_report("Unknown ID %" PRId64 " of replay event", event->id); 197c0c071d0SPavel Dovgalyuk exit(1); 198c0c071d0SPavel Dovgalyuk } 199c0c071d0SPavel Dovgalyuk } 200c0c071d0SPavel Dovgalyuk } 201c0c071d0SPavel Dovgalyuk 202c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */ 203c0c071d0SPavel Dovgalyuk void replay_save_events(int checkpoint) 204c0c071d0SPavel Dovgalyuk { 205d759c951SAlex Bennée g_assert(replay_mutex_locked()); 20689e46eb4SPavel Dovgalyuk g_assert(checkpoint != CHECKPOINT_CLOCK_WARP_START); 207ca9759c2SPavel Dovgalyuk g_assert(checkpoint != CHECKPOINT_CLOCK_VIRTUAL); 208c0c071d0SPavel Dovgalyuk while (!QTAILQ_EMPTY(&events_list)) { 209c0c071d0SPavel Dovgalyuk Event *event = QTAILQ_FIRST(&events_list); 210c0c071d0SPavel Dovgalyuk replay_save_event(event, checkpoint); 211c0c071d0SPavel Dovgalyuk replay_run_event(event); 212c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events); 213c0c071d0SPavel Dovgalyuk g_free(event); 214c0c071d0SPavel Dovgalyuk } 215c0c071d0SPavel Dovgalyuk } 216c0c071d0SPavel Dovgalyuk 217c0c071d0SPavel Dovgalyuk static Event *replay_read_event(int checkpoint) 218c0c071d0SPavel Dovgalyuk { 219c0c071d0SPavel Dovgalyuk Event *event; 2200b30dc01SPavel Dovgalyuk if (replay_state.read_event_kind == -1) { 2210b30dc01SPavel Dovgalyuk replay_state.read_event_checkpoint = replay_get_byte(); 2220b30dc01SPavel Dovgalyuk replay_state.read_event_kind = replay_get_byte(); 2230b30dc01SPavel Dovgalyuk replay_state.read_event_id = -1; 224c0c071d0SPavel Dovgalyuk replay_check_error(); 225c0c071d0SPavel Dovgalyuk } 226c0c071d0SPavel Dovgalyuk 2270b30dc01SPavel Dovgalyuk if (checkpoint != replay_state.read_event_checkpoint) { 228c0c071d0SPavel Dovgalyuk return NULL; 229c0c071d0SPavel Dovgalyuk } 230c0c071d0SPavel Dovgalyuk 231c0c071d0SPavel Dovgalyuk /* Events that has not to be in the queue */ 2320b30dc01SPavel Dovgalyuk switch (replay_state.read_event_kind) { 2338a354bd9SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH: 234*e4ec5ad4SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH_ONESHOT: 2350b30dc01SPavel Dovgalyuk if (replay_state.read_event_id == -1) { 2360b30dc01SPavel Dovgalyuk replay_state.read_event_id = replay_get_qword(); 2378a354bd9SPavel Dovgalyuk } 2388a354bd9SPavel Dovgalyuk break; 239ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT: 240ee312992SPavel Dovgalyuk event = g_malloc0(sizeof(Event)); 2410b30dc01SPavel Dovgalyuk event->event_kind = replay_state.read_event_kind; 242ee312992SPavel Dovgalyuk event->opaque = replay_read_input_event(); 243ee312992SPavel Dovgalyuk return event; 244ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT_SYNC: 245ee312992SPavel Dovgalyuk event = g_malloc0(sizeof(Event)); 2460b30dc01SPavel Dovgalyuk event->event_kind = replay_state.read_event_kind; 247ee312992SPavel Dovgalyuk event->opaque = 0; 248ee312992SPavel Dovgalyuk return event; 24933577b47SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_CHAR_READ: 25033577b47SPavel Dovgalyuk event = g_malloc0(sizeof(Event)); 2510b30dc01SPavel Dovgalyuk event->event_kind = replay_state.read_event_kind; 25233577b47SPavel Dovgalyuk event->opaque = replay_event_char_read_load(); 25333577b47SPavel Dovgalyuk return event; 25463785678SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BLOCK: 2550b30dc01SPavel Dovgalyuk if (replay_state.read_event_id == -1) { 2560b30dc01SPavel Dovgalyuk replay_state.read_event_id = replay_get_qword(); 25763785678SPavel Dovgalyuk } 25863785678SPavel Dovgalyuk break; 259646c5478SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_NET: 260646c5478SPavel Dovgalyuk event = g_malloc0(sizeof(Event)); 2610b30dc01SPavel Dovgalyuk event->event_kind = replay_state.read_event_kind; 262646c5478SPavel Dovgalyuk event->opaque = replay_event_net_load(); 263646c5478SPavel Dovgalyuk return event; 264c0c071d0SPavel Dovgalyuk default: 2650b30dc01SPavel Dovgalyuk error_report("Unknown ID %d of replay event", 2660b30dc01SPavel Dovgalyuk replay_state.read_event_kind); 267c0c071d0SPavel Dovgalyuk exit(1); 268c0c071d0SPavel Dovgalyuk break; 269c0c071d0SPavel Dovgalyuk } 270c0c071d0SPavel Dovgalyuk 271c0c071d0SPavel Dovgalyuk QTAILQ_FOREACH(event, &events_list, events) { 2720b30dc01SPavel Dovgalyuk if (event->event_kind == replay_state.read_event_kind 2730b30dc01SPavel Dovgalyuk && (replay_state.read_event_id == -1 2740b30dc01SPavel Dovgalyuk || replay_state.read_event_id == event->id)) { 275c0c071d0SPavel Dovgalyuk break; 276c0c071d0SPavel Dovgalyuk } 277c0c071d0SPavel Dovgalyuk } 278c0c071d0SPavel Dovgalyuk 279c0c071d0SPavel Dovgalyuk if (event) { 280c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events); 281c0c071d0SPavel Dovgalyuk } else { 282c0c071d0SPavel Dovgalyuk return NULL; 283c0c071d0SPavel Dovgalyuk } 284c0c071d0SPavel Dovgalyuk 285c0c071d0SPavel Dovgalyuk /* Read event-specific data */ 286c0c071d0SPavel Dovgalyuk 287c0c071d0SPavel Dovgalyuk return event; 288c0c071d0SPavel Dovgalyuk } 289c0c071d0SPavel Dovgalyuk 290c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */ 291c0c071d0SPavel Dovgalyuk void replay_read_events(int checkpoint) 292c0c071d0SPavel Dovgalyuk { 293d759c951SAlex Bennée g_assert(replay_mutex_locked()); 294f186d64dSPavel Dovgalyuk while (replay_state.data_kind == EVENT_ASYNC) { 295c0c071d0SPavel Dovgalyuk Event *event = replay_read_event(checkpoint); 296c0c071d0SPavel Dovgalyuk if (!event) { 297c0c071d0SPavel Dovgalyuk break; 298c0c071d0SPavel Dovgalyuk } 2991a96e3c1SPavel Dovgalyuk replay_finish_event(); 3000b30dc01SPavel Dovgalyuk replay_state.read_event_kind = -1; 301c0c071d0SPavel Dovgalyuk replay_run_event(event); 302c0c071d0SPavel Dovgalyuk 303c0c071d0SPavel Dovgalyuk g_free(event); 304c0c071d0SPavel Dovgalyuk } 305c0c071d0SPavel Dovgalyuk } 306c0c071d0SPavel Dovgalyuk 307c0c071d0SPavel Dovgalyuk void replay_init_events(void) 308c0c071d0SPavel Dovgalyuk { 3090b30dc01SPavel Dovgalyuk replay_state.read_event_kind = -1; 310c0c071d0SPavel Dovgalyuk } 311c0c071d0SPavel Dovgalyuk 312c0c071d0SPavel Dovgalyuk void replay_finish_events(void) 313c0c071d0SPavel Dovgalyuk { 314c0c071d0SPavel Dovgalyuk events_enabled = false; 315d873fe03SPavel Dovgalyuk replay_flush_events(); 316c0c071d0SPavel Dovgalyuk } 317c0c071d0SPavel Dovgalyuk 318c0c071d0SPavel Dovgalyuk bool replay_events_enabled(void) 319c0c071d0SPavel Dovgalyuk { 320c0c071d0SPavel Dovgalyuk return events_enabled; 321c0c071d0SPavel Dovgalyuk } 3226d0ceb80SPavel Dovgalyuk 3236d0ceb80SPavel Dovgalyuk uint64_t blkreplay_next_id(void) 3246d0ceb80SPavel Dovgalyuk { 3256d0ceb80SPavel Dovgalyuk if (replay_events_enabled()) { 3266d0ceb80SPavel Dovgalyuk return replay_state.block_request_id++; 3276d0ceb80SPavel Dovgalyuk } 3286d0ceb80SPavel Dovgalyuk return 0; 3296d0ceb80SPavel Dovgalyuk } 330