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 bool events_enabled; 31c0c071d0SPavel Dovgalyuk 32c0c071d0SPavel Dovgalyuk /* Functions */ 33c0c071d0SPavel Dovgalyuk 34c0c071d0SPavel Dovgalyuk static void replay_run_event(Event *event) 35c0c071d0SPavel Dovgalyuk { 36c0c071d0SPavel Dovgalyuk switch (event->event_kind) { 378a354bd9SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH: 388a354bd9SPavel Dovgalyuk aio_bh_call(event->opaque); 398a354bd9SPavel Dovgalyuk break; 40ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT: 41ee312992SPavel Dovgalyuk qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque); 42ee312992SPavel Dovgalyuk qapi_free_InputEvent((InputEvent *)event->opaque); 43ee312992SPavel Dovgalyuk break; 44ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT_SYNC: 45ee312992SPavel Dovgalyuk qemu_input_event_sync_impl(); 46ee312992SPavel Dovgalyuk break; 4733577b47SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_CHAR_READ: 4833577b47SPavel Dovgalyuk replay_event_char_read_run(event->opaque); 4933577b47SPavel Dovgalyuk break; 5063785678SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BLOCK: 5163785678SPavel Dovgalyuk aio_bh_call(event->opaque); 5263785678SPavel Dovgalyuk break; 53646c5478SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_NET: 54646c5478SPavel Dovgalyuk replay_event_net_run(event->opaque); 55646c5478SPavel Dovgalyuk break; 56c0c071d0SPavel Dovgalyuk default: 57c0c071d0SPavel Dovgalyuk error_report("Replay: invalid async event ID (%d) in the queue", 58c0c071d0SPavel Dovgalyuk event->event_kind); 59c0c071d0SPavel Dovgalyuk exit(1); 60c0c071d0SPavel Dovgalyuk break; 61c0c071d0SPavel Dovgalyuk } 62c0c071d0SPavel Dovgalyuk } 63c0c071d0SPavel Dovgalyuk 64c0c071d0SPavel Dovgalyuk void replay_enable_events(void) 65c0c071d0SPavel Dovgalyuk { 661652e0c3SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_NONE) { 67c0c071d0SPavel Dovgalyuk events_enabled = true; 68c0c071d0SPavel Dovgalyuk } 691652e0c3SPavel Dovgalyuk } 70c0c071d0SPavel Dovgalyuk 71c0c071d0SPavel Dovgalyuk bool replay_has_events(void) 72c0c071d0SPavel Dovgalyuk { 73c0c071d0SPavel Dovgalyuk return !QTAILQ_EMPTY(&events_list); 74c0c071d0SPavel Dovgalyuk } 75c0c071d0SPavel Dovgalyuk 76c0c071d0SPavel Dovgalyuk void replay_flush_events(void) 77c0c071d0SPavel Dovgalyuk { 78d759c951SAlex Bennée g_assert(replay_mutex_locked()); 79d759c951SAlex Bennée 80c0c071d0SPavel Dovgalyuk while (!QTAILQ_EMPTY(&events_list)) { 81c0c071d0SPavel Dovgalyuk Event *event = QTAILQ_FIRST(&events_list); 82c0c071d0SPavel Dovgalyuk replay_run_event(event); 83c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events); 84c0c071d0SPavel Dovgalyuk g_free(event); 85c0c071d0SPavel Dovgalyuk } 86c0c071d0SPavel Dovgalyuk } 87c0c071d0SPavel Dovgalyuk 88c0c071d0SPavel Dovgalyuk void replay_disable_events(void) 89c0c071d0SPavel Dovgalyuk { 90c0c071d0SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_NONE) { 91c0c071d0SPavel Dovgalyuk events_enabled = false; 92c0c071d0SPavel Dovgalyuk /* Flush events queue before waiting of completion */ 93c0c071d0SPavel Dovgalyuk replay_flush_events(); 94c0c071d0SPavel Dovgalyuk } 95c0c071d0SPavel Dovgalyuk } 96c0c071d0SPavel Dovgalyuk 97c0c071d0SPavel Dovgalyuk /*! Adds specified async event to the queue */ 9833577b47SPavel Dovgalyuk void replay_add_event(ReplayAsyncEventKind event_kind, 99c0c071d0SPavel Dovgalyuk void *opaque, 100c0c071d0SPavel Dovgalyuk void *opaque2, uint64_t id) 101c0c071d0SPavel Dovgalyuk { 102c0c071d0SPavel Dovgalyuk assert(event_kind < REPLAY_ASYNC_COUNT); 103c0c071d0SPavel Dovgalyuk 104c0c071d0SPavel Dovgalyuk if (!replay_file || replay_mode == REPLAY_MODE_NONE 105c0c071d0SPavel Dovgalyuk || !events_enabled) { 106c0c071d0SPavel Dovgalyuk Event e; 107c0c071d0SPavel Dovgalyuk e.event_kind = event_kind; 108c0c071d0SPavel Dovgalyuk e.opaque = opaque; 109c0c071d0SPavel Dovgalyuk e.opaque2 = opaque2; 110c0c071d0SPavel Dovgalyuk e.id = id; 111c0c071d0SPavel Dovgalyuk replay_run_event(&e); 112c0c071d0SPavel Dovgalyuk return; 113c0c071d0SPavel Dovgalyuk } 114c0c071d0SPavel Dovgalyuk 115c0c071d0SPavel Dovgalyuk Event *event = g_malloc0(sizeof(Event)); 116c0c071d0SPavel Dovgalyuk event->event_kind = event_kind; 117c0c071d0SPavel Dovgalyuk event->opaque = opaque; 118c0c071d0SPavel Dovgalyuk event->opaque2 = opaque2; 119c0c071d0SPavel Dovgalyuk event->id = id; 120c0c071d0SPavel Dovgalyuk 121d759c951SAlex Bennée g_assert(replay_mutex_locked()); 122c0c071d0SPavel Dovgalyuk QTAILQ_INSERT_TAIL(&events_list, event, events); 123c0c071d0SPavel Dovgalyuk } 1248a354bd9SPavel Dovgalyuk 1258a354bd9SPavel Dovgalyuk void replay_bh_schedule_event(QEMUBH *bh) 1268a354bd9SPavel Dovgalyuk { 1271652e0c3SPavel Dovgalyuk if (events_enabled) { 1288a354bd9SPavel Dovgalyuk uint64_t id = replay_get_current_step(); 1298a354bd9SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id); 1308a354bd9SPavel Dovgalyuk } else { 1318a354bd9SPavel Dovgalyuk qemu_bh_schedule(bh); 1328a354bd9SPavel Dovgalyuk } 1338a354bd9SPavel Dovgalyuk } 134c0c071d0SPavel Dovgalyuk 135ee312992SPavel Dovgalyuk void replay_add_input_event(struct InputEvent *event) 136ee312992SPavel Dovgalyuk { 137ee312992SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0); 138ee312992SPavel Dovgalyuk } 139ee312992SPavel Dovgalyuk 140ee312992SPavel Dovgalyuk void replay_add_input_sync_event(void) 141ee312992SPavel Dovgalyuk { 142ee312992SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0); 143ee312992SPavel Dovgalyuk } 144ee312992SPavel Dovgalyuk 14563785678SPavel Dovgalyuk void replay_block_event(QEMUBH *bh, uint64_t id) 14663785678SPavel Dovgalyuk { 1471652e0c3SPavel Dovgalyuk if (events_enabled) { 14863785678SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_BLOCK, bh, NULL, id); 14963785678SPavel Dovgalyuk } else { 15063785678SPavel Dovgalyuk qemu_bh_schedule(bh); 15163785678SPavel Dovgalyuk } 15263785678SPavel Dovgalyuk } 15363785678SPavel Dovgalyuk 154c0c071d0SPavel Dovgalyuk static void replay_save_event(Event *event, int checkpoint) 155c0c071d0SPavel Dovgalyuk { 156c0c071d0SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_PLAY) { 157c0c071d0SPavel Dovgalyuk /* put the event into the file */ 158c0c071d0SPavel Dovgalyuk replay_put_event(EVENT_ASYNC); 159c0c071d0SPavel Dovgalyuk replay_put_byte(checkpoint); 160c0c071d0SPavel Dovgalyuk replay_put_byte(event->event_kind); 161c0c071d0SPavel Dovgalyuk 162c0c071d0SPavel Dovgalyuk /* save event-specific data */ 163c0c071d0SPavel Dovgalyuk switch (event->event_kind) { 1648a354bd9SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH: 1658a354bd9SPavel Dovgalyuk replay_put_qword(event->id); 1668a354bd9SPavel Dovgalyuk break; 167ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT: 168ee312992SPavel Dovgalyuk replay_save_input_event(event->opaque); 169ee312992SPavel Dovgalyuk break; 170ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT_SYNC: 171ee312992SPavel Dovgalyuk break; 17233577b47SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_CHAR_READ: 17333577b47SPavel Dovgalyuk replay_event_char_read_save(event->opaque); 17433577b47SPavel Dovgalyuk break; 17563785678SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BLOCK: 17663785678SPavel Dovgalyuk replay_put_qword(event->id); 17763785678SPavel Dovgalyuk break; 178646c5478SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_NET: 179646c5478SPavel Dovgalyuk replay_event_net_save(event->opaque); 180646c5478SPavel Dovgalyuk break; 181c0c071d0SPavel Dovgalyuk default: 18295b4aed5SPavel Dovgalyuk error_report("Unknown ID %" PRId64 " of replay event", event->id); 183c0c071d0SPavel Dovgalyuk exit(1); 184c0c071d0SPavel Dovgalyuk } 185c0c071d0SPavel Dovgalyuk } 186c0c071d0SPavel Dovgalyuk } 187c0c071d0SPavel Dovgalyuk 188c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */ 189c0c071d0SPavel Dovgalyuk void replay_save_events(int checkpoint) 190c0c071d0SPavel Dovgalyuk { 191d759c951SAlex Bennée g_assert(replay_mutex_locked()); 19289e46eb4SPavel Dovgalyuk g_assert(checkpoint != CHECKPOINT_CLOCK_WARP_START); 193c0c071d0SPavel Dovgalyuk while (!QTAILQ_EMPTY(&events_list)) { 194c0c071d0SPavel Dovgalyuk Event *event = QTAILQ_FIRST(&events_list); 195c0c071d0SPavel Dovgalyuk replay_save_event(event, checkpoint); 196c0c071d0SPavel Dovgalyuk replay_run_event(event); 197c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events); 198c0c071d0SPavel Dovgalyuk g_free(event); 199c0c071d0SPavel Dovgalyuk } 200c0c071d0SPavel Dovgalyuk } 201c0c071d0SPavel Dovgalyuk 202c0c071d0SPavel Dovgalyuk static Event *replay_read_event(int checkpoint) 203c0c071d0SPavel Dovgalyuk { 204c0c071d0SPavel Dovgalyuk Event *event; 2050b30dc01SPavel Dovgalyuk if (replay_state.read_event_kind == -1) { 2060b30dc01SPavel Dovgalyuk replay_state.read_event_checkpoint = replay_get_byte(); 2070b30dc01SPavel Dovgalyuk replay_state.read_event_kind = replay_get_byte(); 2080b30dc01SPavel Dovgalyuk replay_state.read_event_id = -1; 209c0c071d0SPavel Dovgalyuk replay_check_error(); 210c0c071d0SPavel Dovgalyuk } 211c0c071d0SPavel Dovgalyuk 2120b30dc01SPavel Dovgalyuk if (checkpoint != replay_state.read_event_checkpoint) { 213c0c071d0SPavel Dovgalyuk return NULL; 214c0c071d0SPavel Dovgalyuk } 215c0c071d0SPavel Dovgalyuk 216c0c071d0SPavel Dovgalyuk /* Events that has not to be in the queue */ 2170b30dc01SPavel Dovgalyuk switch (replay_state.read_event_kind) { 2188a354bd9SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH: 2190b30dc01SPavel Dovgalyuk if (replay_state.read_event_id == -1) { 2200b30dc01SPavel Dovgalyuk replay_state.read_event_id = replay_get_qword(); 2218a354bd9SPavel Dovgalyuk } 2228a354bd9SPavel Dovgalyuk break; 223ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT: 224ee312992SPavel Dovgalyuk event = g_malloc0(sizeof(Event)); 2250b30dc01SPavel Dovgalyuk event->event_kind = replay_state.read_event_kind; 226ee312992SPavel Dovgalyuk event->opaque = replay_read_input_event(); 227ee312992SPavel Dovgalyuk return event; 228ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT_SYNC: 229ee312992SPavel Dovgalyuk event = g_malloc0(sizeof(Event)); 2300b30dc01SPavel Dovgalyuk event->event_kind = replay_state.read_event_kind; 231ee312992SPavel Dovgalyuk event->opaque = 0; 232ee312992SPavel Dovgalyuk return event; 23333577b47SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_CHAR_READ: 23433577b47SPavel Dovgalyuk event = g_malloc0(sizeof(Event)); 2350b30dc01SPavel Dovgalyuk event->event_kind = replay_state.read_event_kind; 23633577b47SPavel Dovgalyuk event->opaque = replay_event_char_read_load(); 23733577b47SPavel Dovgalyuk return event; 23863785678SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BLOCK: 2390b30dc01SPavel Dovgalyuk if (replay_state.read_event_id == -1) { 2400b30dc01SPavel Dovgalyuk replay_state.read_event_id = replay_get_qword(); 24163785678SPavel Dovgalyuk } 24263785678SPavel Dovgalyuk break; 243646c5478SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_NET: 244646c5478SPavel Dovgalyuk event = g_malloc0(sizeof(Event)); 2450b30dc01SPavel Dovgalyuk event->event_kind = replay_state.read_event_kind; 246646c5478SPavel Dovgalyuk event->opaque = replay_event_net_load(); 247646c5478SPavel Dovgalyuk return event; 248c0c071d0SPavel Dovgalyuk default: 2490b30dc01SPavel Dovgalyuk error_report("Unknown ID %d of replay event", 2500b30dc01SPavel Dovgalyuk replay_state.read_event_kind); 251c0c071d0SPavel Dovgalyuk exit(1); 252c0c071d0SPavel Dovgalyuk break; 253c0c071d0SPavel Dovgalyuk } 254c0c071d0SPavel Dovgalyuk 255c0c071d0SPavel Dovgalyuk QTAILQ_FOREACH(event, &events_list, events) { 2560b30dc01SPavel Dovgalyuk if (event->event_kind == replay_state.read_event_kind 2570b30dc01SPavel Dovgalyuk && (replay_state.read_event_id == -1 2580b30dc01SPavel Dovgalyuk || replay_state.read_event_id == event->id)) { 259c0c071d0SPavel Dovgalyuk break; 260c0c071d0SPavel Dovgalyuk } 261c0c071d0SPavel Dovgalyuk } 262c0c071d0SPavel Dovgalyuk 263c0c071d0SPavel Dovgalyuk if (event) { 264c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events); 265c0c071d0SPavel Dovgalyuk } else { 266c0c071d0SPavel Dovgalyuk return NULL; 267c0c071d0SPavel Dovgalyuk } 268c0c071d0SPavel Dovgalyuk 269c0c071d0SPavel Dovgalyuk /* Read event-specific data */ 270c0c071d0SPavel Dovgalyuk 271c0c071d0SPavel Dovgalyuk return event; 272c0c071d0SPavel Dovgalyuk } 273c0c071d0SPavel Dovgalyuk 274c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */ 275c0c071d0SPavel Dovgalyuk void replay_read_events(int checkpoint) 276c0c071d0SPavel Dovgalyuk { 277d759c951SAlex Bennée g_assert(replay_mutex_locked()); 278f186d64dSPavel Dovgalyuk while (replay_state.data_kind == EVENT_ASYNC) { 279c0c071d0SPavel Dovgalyuk Event *event = replay_read_event(checkpoint); 280c0c071d0SPavel Dovgalyuk if (!event) { 281c0c071d0SPavel Dovgalyuk break; 282c0c071d0SPavel Dovgalyuk } 2831a96e3c1SPavel Dovgalyuk replay_finish_event(); 2840b30dc01SPavel Dovgalyuk replay_state.read_event_kind = -1; 285c0c071d0SPavel Dovgalyuk replay_run_event(event); 286c0c071d0SPavel Dovgalyuk 287c0c071d0SPavel Dovgalyuk g_free(event); 288c0c071d0SPavel Dovgalyuk } 289c0c071d0SPavel Dovgalyuk } 290c0c071d0SPavel Dovgalyuk 291c0c071d0SPavel Dovgalyuk void replay_init_events(void) 292c0c071d0SPavel Dovgalyuk { 2930b30dc01SPavel Dovgalyuk replay_state.read_event_kind = -1; 294c0c071d0SPavel Dovgalyuk } 295c0c071d0SPavel Dovgalyuk 296c0c071d0SPavel Dovgalyuk void replay_finish_events(void) 297c0c071d0SPavel Dovgalyuk { 298c0c071d0SPavel Dovgalyuk events_enabled = false; 299*d873fe03SPavel Dovgalyuk replay_flush_events(); 300c0c071d0SPavel Dovgalyuk } 301c0c071d0SPavel Dovgalyuk 302c0c071d0SPavel Dovgalyuk bool replay_events_enabled(void) 303c0c071d0SPavel Dovgalyuk { 304c0c071d0SPavel Dovgalyuk return events_enabled; 305c0c071d0SPavel Dovgalyuk } 3066d0ceb80SPavel Dovgalyuk 3076d0ceb80SPavel Dovgalyuk uint64_t blkreplay_next_id(void) 3086d0ceb80SPavel Dovgalyuk { 3096d0ceb80SPavel Dovgalyuk if (replay_events_enabled()) { 3106d0ceb80SPavel Dovgalyuk return replay_state.block_request_id++; 3116d0ceb80SPavel Dovgalyuk } 3126d0ceb80SPavel Dovgalyuk return 0; 3136d0ceb80SPavel Dovgalyuk } 314