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-common.h" 14c0c071d0SPavel Dovgalyuk #include "qemu/error-report.h" 15c0c071d0SPavel Dovgalyuk #include "sysemu/replay.h" 16c0c071d0SPavel Dovgalyuk #include "replay-internal.h" 178a354bd9SPavel Dovgalyuk #include "block/aio.h" 18ee312992SPavel Dovgalyuk #include "ui/input.h" 19c0c071d0SPavel Dovgalyuk 20c0c071d0SPavel Dovgalyuk typedef struct Event { 21c0c071d0SPavel Dovgalyuk ReplayAsyncEventKind event_kind; 22c0c071d0SPavel Dovgalyuk void *opaque; 23c0c071d0SPavel Dovgalyuk void *opaque2; 24c0c071d0SPavel Dovgalyuk uint64_t id; 25c0c071d0SPavel Dovgalyuk 26c0c071d0SPavel Dovgalyuk QTAILQ_ENTRY(Event) events; 27c0c071d0SPavel Dovgalyuk } Event; 28c0c071d0SPavel Dovgalyuk 29c0c071d0SPavel Dovgalyuk static QTAILQ_HEAD(, Event) events_list = QTAILQ_HEAD_INITIALIZER(events_list); 30c0c071d0SPavel Dovgalyuk static unsigned int read_event_kind = -1; 31c0c071d0SPavel Dovgalyuk static uint64_t read_id = -1; 32c0c071d0SPavel Dovgalyuk static int read_checkpoint = -1; 33c0c071d0SPavel Dovgalyuk 34c0c071d0SPavel Dovgalyuk static bool events_enabled; 35c0c071d0SPavel Dovgalyuk 36c0c071d0SPavel Dovgalyuk /* Functions */ 37c0c071d0SPavel Dovgalyuk 38c0c071d0SPavel Dovgalyuk static void replay_run_event(Event *event) 39c0c071d0SPavel Dovgalyuk { 40c0c071d0SPavel Dovgalyuk switch (event->event_kind) { 418a354bd9SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH: 428a354bd9SPavel Dovgalyuk aio_bh_call(event->opaque); 438a354bd9SPavel Dovgalyuk break; 44ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT: 45ee312992SPavel Dovgalyuk qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque); 46ee312992SPavel Dovgalyuk qapi_free_InputEvent((InputEvent *)event->opaque); 47ee312992SPavel Dovgalyuk break; 48ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT_SYNC: 49ee312992SPavel Dovgalyuk qemu_input_event_sync_impl(); 50ee312992SPavel Dovgalyuk break; 5133577b47SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_CHAR_READ: 5233577b47SPavel Dovgalyuk replay_event_char_read_run(event->opaque); 5333577b47SPavel Dovgalyuk break; 54*63785678SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BLOCK: 55*63785678SPavel Dovgalyuk aio_bh_call(event->opaque); 56*63785678SPavel Dovgalyuk break; 57c0c071d0SPavel Dovgalyuk default: 58c0c071d0SPavel Dovgalyuk error_report("Replay: invalid async event ID (%d) in the queue", 59c0c071d0SPavel Dovgalyuk event->event_kind); 60c0c071d0SPavel Dovgalyuk exit(1); 61c0c071d0SPavel Dovgalyuk break; 62c0c071d0SPavel Dovgalyuk } 63c0c071d0SPavel Dovgalyuk } 64c0c071d0SPavel Dovgalyuk 65c0c071d0SPavel Dovgalyuk void replay_enable_events(void) 66c0c071d0SPavel Dovgalyuk { 67c0c071d0SPavel Dovgalyuk events_enabled = true; 68c0c071d0SPavel Dovgalyuk } 69c0c071d0SPavel Dovgalyuk 70c0c071d0SPavel Dovgalyuk bool replay_has_events(void) 71c0c071d0SPavel Dovgalyuk { 72c0c071d0SPavel Dovgalyuk return !QTAILQ_EMPTY(&events_list); 73c0c071d0SPavel Dovgalyuk } 74c0c071d0SPavel Dovgalyuk 75c0c071d0SPavel Dovgalyuk void replay_flush_events(void) 76c0c071d0SPavel Dovgalyuk { 77c0c071d0SPavel Dovgalyuk replay_mutex_lock(); 78c0c071d0SPavel Dovgalyuk while (!QTAILQ_EMPTY(&events_list)) { 79c0c071d0SPavel Dovgalyuk Event *event = QTAILQ_FIRST(&events_list); 80c0c071d0SPavel Dovgalyuk replay_mutex_unlock(); 81c0c071d0SPavel Dovgalyuk replay_run_event(event); 82c0c071d0SPavel Dovgalyuk replay_mutex_lock(); 83c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events); 84c0c071d0SPavel Dovgalyuk g_free(event); 85c0c071d0SPavel Dovgalyuk } 86c0c071d0SPavel Dovgalyuk replay_mutex_unlock(); 87c0c071d0SPavel Dovgalyuk } 88c0c071d0SPavel Dovgalyuk 89c0c071d0SPavel Dovgalyuk void replay_disable_events(void) 90c0c071d0SPavel Dovgalyuk { 91c0c071d0SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_NONE) { 92c0c071d0SPavel Dovgalyuk events_enabled = false; 93c0c071d0SPavel Dovgalyuk /* Flush events queue before waiting of completion */ 94c0c071d0SPavel Dovgalyuk replay_flush_events(); 95c0c071d0SPavel Dovgalyuk } 96c0c071d0SPavel Dovgalyuk } 97c0c071d0SPavel Dovgalyuk 98c0c071d0SPavel Dovgalyuk void replay_clear_events(void) 99c0c071d0SPavel Dovgalyuk { 100c0c071d0SPavel Dovgalyuk replay_mutex_lock(); 101c0c071d0SPavel Dovgalyuk while (!QTAILQ_EMPTY(&events_list)) { 102c0c071d0SPavel Dovgalyuk Event *event = QTAILQ_FIRST(&events_list); 103c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events); 104c0c071d0SPavel Dovgalyuk 105c0c071d0SPavel Dovgalyuk g_free(event); 106c0c071d0SPavel Dovgalyuk } 107c0c071d0SPavel Dovgalyuk replay_mutex_unlock(); 108c0c071d0SPavel Dovgalyuk } 109c0c071d0SPavel Dovgalyuk 110c0c071d0SPavel Dovgalyuk /*! Adds specified async event to the queue */ 11133577b47SPavel Dovgalyuk void replay_add_event(ReplayAsyncEventKind event_kind, 112c0c071d0SPavel Dovgalyuk void *opaque, 113c0c071d0SPavel Dovgalyuk void *opaque2, uint64_t id) 114c0c071d0SPavel Dovgalyuk { 115c0c071d0SPavel Dovgalyuk assert(event_kind < REPLAY_ASYNC_COUNT); 116c0c071d0SPavel Dovgalyuk 117c0c071d0SPavel Dovgalyuk if (!replay_file || replay_mode == REPLAY_MODE_NONE 118c0c071d0SPavel Dovgalyuk || !events_enabled) { 119c0c071d0SPavel Dovgalyuk Event e; 120c0c071d0SPavel Dovgalyuk e.event_kind = event_kind; 121c0c071d0SPavel Dovgalyuk e.opaque = opaque; 122c0c071d0SPavel Dovgalyuk e.opaque2 = opaque2; 123c0c071d0SPavel Dovgalyuk e.id = id; 124c0c071d0SPavel Dovgalyuk replay_run_event(&e); 125c0c071d0SPavel Dovgalyuk return; 126c0c071d0SPavel Dovgalyuk } 127c0c071d0SPavel Dovgalyuk 128c0c071d0SPavel Dovgalyuk Event *event = g_malloc0(sizeof(Event)); 129c0c071d0SPavel Dovgalyuk event->event_kind = event_kind; 130c0c071d0SPavel Dovgalyuk event->opaque = opaque; 131c0c071d0SPavel Dovgalyuk event->opaque2 = opaque2; 132c0c071d0SPavel Dovgalyuk event->id = id; 133c0c071d0SPavel Dovgalyuk 134c0c071d0SPavel Dovgalyuk replay_mutex_lock(); 135c0c071d0SPavel Dovgalyuk QTAILQ_INSERT_TAIL(&events_list, event, events); 136c0c071d0SPavel Dovgalyuk replay_mutex_unlock(); 137c0c071d0SPavel Dovgalyuk } 1388a354bd9SPavel Dovgalyuk 1398a354bd9SPavel Dovgalyuk void replay_bh_schedule_event(QEMUBH *bh) 1408a354bd9SPavel Dovgalyuk { 14158a0067aSPavel Dovgalyuk if (replay_mode != REPLAY_MODE_NONE && events_enabled) { 1428a354bd9SPavel Dovgalyuk uint64_t id = replay_get_current_step(); 1438a354bd9SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id); 1448a354bd9SPavel Dovgalyuk } else { 1458a354bd9SPavel Dovgalyuk qemu_bh_schedule(bh); 1468a354bd9SPavel Dovgalyuk } 1478a354bd9SPavel Dovgalyuk } 148c0c071d0SPavel Dovgalyuk 149ee312992SPavel Dovgalyuk void replay_add_input_event(struct InputEvent *event) 150ee312992SPavel Dovgalyuk { 151ee312992SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0); 152ee312992SPavel Dovgalyuk } 153ee312992SPavel Dovgalyuk 154ee312992SPavel Dovgalyuk void replay_add_input_sync_event(void) 155ee312992SPavel Dovgalyuk { 156ee312992SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0); 157ee312992SPavel Dovgalyuk } 158ee312992SPavel Dovgalyuk 159*63785678SPavel Dovgalyuk void replay_block_event(QEMUBH *bh, uint64_t id) 160*63785678SPavel Dovgalyuk { 161*63785678SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_NONE && events_enabled) { 162*63785678SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_BLOCK, bh, NULL, id); 163*63785678SPavel Dovgalyuk } else { 164*63785678SPavel Dovgalyuk qemu_bh_schedule(bh); 165*63785678SPavel Dovgalyuk } 166*63785678SPavel Dovgalyuk } 167*63785678SPavel Dovgalyuk 168c0c071d0SPavel Dovgalyuk static void replay_save_event(Event *event, int checkpoint) 169c0c071d0SPavel Dovgalyuk { 170c0c071d0SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_PLAY) { 171c0c071d0SPavel Dovgalyuk /* put the event into the file */ 172c0c071d0SPavel Dovgalyuk replay_put_event(EVENT_ASYNC); 173c0c071d0SPavel Dovgalyuk replay_put_byte(checkpoint); 174c0c071d0SPavel Dovgalyuk replay_put_byte(event->event_kind); 175c0c071d0SPavel Dovgalyuk 176c0c071d0SPavel Dovgalyuk /* save event-specific data */ 177c0c071d0SPavel Dovgalyuk switch (event->event_kind) { 1788a354bd9SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH: 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; 189*63785678SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BLOCK: 190*63785678SPavel Dovgalyuk replay_put_qword(event->id); 191*63785678SPavel Dovgalyuk break; 192c0c071d0SPavel Dovgalyuk default: 19395b4aed5SPavel Dovgalyuk error_report("Unknown ID %" PRId64 " of replay event", event->id); 194c0c071d0SPavel Dovgalyuk exit(1); 195c0c071d0SPavel Dovgalyuk } 196c0c071d0SPavel Dovgalyuk } 197c0c071d0SPavel Dovgalyuk } 198c0c071d0SPavel Dovgalyuk 199c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */ 200c0c071d0SPavel Dovgalyuk void replay_save_events(int checkpoint) 201c0c071d0SPavel Dovgalyuk { 202c0c071d0SPavel Dovgalyuk while (!QTAILQ_EMPTY(&events_list)) { 203c0c071d0SPavel Dovgalyuk Event *event = QTAILQ_FIRST(&events_list); 204c0c071d0SPavel Dovgalyuk replay_save_event(event, checkpoint); 205c0c071d0SPavel Dovgalyuk 206c0c071d0SPavel Dovgalyuk replay_mutex_unlock(); 207c0c071d0SPavel Dovgalyuk replay_run_event(event); 208c0c071d0SPavel Dovgalyuk replay_mutex_lock(); 209c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events); 210c0c071d0SPavel Dovgalyuk g_free(event); 211c0c071d0SPavel Dovgalyuk } 212c0c071d0SPavel Dovgalyuk } 213c0c071d0SPavel Dovgalyuk 214c0c071d0SPavel Dovgalyuk static Event *replay_read_event(int checkpoint) 215c0c071d0SPavel Dovgalyuk { 216c0c071d0SPavel Dovgalyuk Event *event; 217c0c071d0SPavel Dovgalyuk if (read_event_kind == -1) { 218c0c071d0SPavel Dovgalyuk read_checkpoint = replay_get_byte(); 219c0c071d0SPavel Dovgalyuk read_event_kind = replay_get_byte(); 220c0c071d0SPavel Dovgalyuk read_id = -1; 221c0c071d0SPavel Dovgalyuk replay_check_error(); 222c0c071d0SPavel Dovgalyuk } 223c0c071d0SPavel Dovgalyuk 224c0c071d0SPavel Dovgalyuk if (checkpoint != read_checkpoint) { 225c0c071d0SPavel Dovgalyuk return NULL; 226c0c071d0SPavel Dovgalyuk } 227c0c071d0SPavel Dovgalyuk 228c0c071d0SPavel Dovgalyuk /* Events that has not to be in the queue */ 229c0c071d0SPavel Dovgalyuk switch (read_event_kind) { 2308a354bd9SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH: 2318a354bd9SPavel Dovgalyuk if (read_id == -1) { 2328a354bd9SPavel Dovgalyuk read_id = replay_get_qword(); 2338a354bd9SPavel Dovgalyuk } 2348a354bd9SPavel Dovgalyuk break; 235ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT: 236ee312992SPavel Dovgalyuk event = g_malloc0(sizeof(Event)); 237ee312992SPavel Dovgalyuk event->event_kind = read_event_kind; 238ee312992SPavel Dovgalyuk event->opaque = replay_read_input_event(); 239ee312992SPavel Dovgalyuk return event; 240ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT_SYNC: 241ee312992SPavel Dovgalyuk event = g_malloc0(sizeof(Event)); 242ee312992SPavel Dovgalyuk event->event_kind = read_event_kind; 243ee312992SPavel Dovgalyuk event->opaque = 0; 244ee312992SPavel Dovgalyuk return event; 24533577b47SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_CHAR_READ: 24633577b47SPavel Dovgalyuk event = g_malloc0(sizeof(Event)); 24733577b47SPavel Dovgalyuk event->event_kind = read_event_kind; 24833577b47SPavel Dovgalyuk event->opaque = replay_event_char_read_load(); 24933577b47SPavel Dovgalyuk return event; 250*63785678SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BLOCK: 251*63785678SPavel Dovgalyuk if (read_id == -1) { 252*63785678SPavel Dovgalyuk read_id = replay_get_qword(); 253*63785678SPavel Dovgalyuk } 254*63785678SPavel Dovgalyuk break; 255c0c071d0SPavel Dovgalyuk default: 256c0c071d0SPavel Dovgalyuk error_report("Unknown ID %d of replay event", read_event_kind); 257c0c071d0SPavel Dovgalyuk exit(1); 258c0c071d0SPavel Dovgalyuk break; 259c0c071d0SPavel Dovgalyuk } 260c0c071d0SPavel Dovgalyuk 261c0c071d0SPavel Dovgalyuk QTAILQ_FOREACH(event, &events_list, events) { 262c0c071d0SPavel Dovgalyuk if (event->event_kind == read_event_kind 263c0c071d0SPavel Dovgalyuk && (read_id == -1 || read_id == event->id)) { 264c0c071d0SPavel Dovgalyuk break; 265c0c071d0SPavel Dovgalyuk } 266c0c071d0SPavel Dovgalyuk } 267c0c071d0SPavel Dovgalyuk 268c0c071d0SPavel Dovgalyuk if (event) { 269c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events); 270c0c071d0SPavel Dovgalyuk } else { 271c0c071d0SPavel Dovgalyuk return NULL; 272c0c071d0SPavel Dovgalyuk } 273c0c071d0SPavel Dovgalyuk 274c0c071d0SPavel Dovgalyuk /* Read event-specific data */ 275c0c071d0SPavel Dovgalyuk 276c0c071d0SPavel Dovgalyuk return event; 277c0c071d0SPavel Dovgalyuk } 278c0c071d0SPavel Dovgalyuk 279c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */ 280c0c071d0SPavel Dovgalyuk void replay_read_events(int checkpoint) 281c0c071d0SPavel Dovgalyuk { 282c0c071d0SPavel Dovgalyuk while (replay_data_kind == EVENT_ASYNC) { 283c0c071d0SPavel Dovgalyuk Event *event = replay_read_event(checkpoint); 284c0c071d0SPavel Dovgalyuk if (!event) { 285c0c071d0SPavel Dovgalyuk break; 286c0c071d0SPavel Dovgalyuk } 287c0c071d0SPavel Dovgalyuk replay_mutex_unlock(); 288c0c071d0SPavel Dovgalyuk replay_run_event(event); 289c0c071d0SPavel Dovgalyuk replay_mutex_lock(); 290c0c071d0SPavel Dovgalyuk 291c0c071d0SPavel Dovgalyuk g_free(event); 292c0c071d0SPavel Dovgalyuk replay_finish_event(); 293c0c071d0SPavel Dovgalyuk read_event_kind = -1; 294c0c071d0SPavel Dovgalyuk } 295c0c071d0SPavel Dovgalyuk } 296c0c071d0SPavel Dovgalyuk 297c0c071d0SPavel Dovgalyuk void replay_init_events(void) 298c0c071d0SPavel Dovgalyuk { 299c0c071d0SPavel Dovgalyuk read_event_kind = -1; 300c0c071d0SPavel Dovgalyuk } 301c0c071d0SPavel Dovgalyuk 302c0c071d0SPavel Dovgalyuk void replay_finish_events(void) 303c0c071d0SPavel Dovgalyuk { 304c0c071d0SPavel Dovgalyuk events_enabled = false; 305c0c071d0SPavel Dovgalyuk replay_clear_events(); 306c0c071d0SPavel Dovgalyuk } 307c0c071d0SPavel Dovgalyuk 308c0c071d0SPavel Dovgalyuk bool replay_events_enabled(void) 309c0c071d0SPavel Dovgalyuk { 310c0c071d0SPavel Dovgalyuk return events_enabled; 311c0c071d0SPavel Dovgalyuk } 312