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" 1846967b1aSPavel Dovgalyuk #include "hw/core/cpu.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; 40e4ec5ad4SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH_ONESHOT: 41e4ec5ad4SPavel Dovgalyuk ((QEMUBHFunc *)event->opaque)(event->opaque2); 42e4ec5ad4SPavel Dovgalyuk break; 43ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT: 44ee312992SPavel Dovgalyuk qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque); 45ee312992SPavel Dovgalyuk qapi_free_InputEvent((InputEvent *)event->opaque); 46ee312992SPavel Dovgalyuk break; 47ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT_SYNC: 48ee312992SPavel Dovgalyuk qemu_input_event_sync_impl(); 49ee312992SPavel Dovgalyuk break; 5033577b47SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_CHAR_READ: 5133577b47SPavel Dovgalyuk replay_event_char_read_run(event->opaque); 5233577b47SPavel Dovgalyuk break; 5363785678SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BLOCK: 5463785678SPavel Dovgalyuk aio_bh_call(event->opaque); 5563785678SPavel Dovgalyuk break; 56646c5478SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_NET: 57646c5478SPavel Dovgalyuk replay_event_net_run(event->opaque); 58646c5478SPavel Dovgalyuk break; 59c0c071d0SPavel Dovgalyuk default: 60c0c071d0SPavel Dovgalyuk error_report("Replay: invalid async event ID (%d) in the queue", 61c0c071d0SPavel Dovgalyuk event->event_kind); 62c0c071d0SPavel Dovgalyuk exit(1); 63c0c071d0SPavel Dovgalyuk break; 64c0c071d0SPavel Dovgalyuk } 65c0c071d0SPavel Dovgalyuk } 66c0c071d0SPavel Dovgalyuk 67c0c071d0SPavel Dovgalyuk void replay_enable_events(void) 68c0c071d0SPavel Dovgalyuk { 691652e0c3SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_NONE) { 70c0c071d0SPavel Dovgalyuk events_enabled = true; 71c0c071d0SPavel Dovgalyuk } 721652e0c3SPavel Dovgalyuk } 73c0c071d0SPavel Dovgalyuk 74c0c071d0SPavel Dovgalyuk bool replay_has_events(void) 75c0c071d0SPavel Dovgalyuk { 76c0c071d0SPavel Dovgalyuk return !QTAILQ_EMPTY(&events_list); 77c0c071d0SPavel Dovgalyuk } 78c0c071d0SPavel Dovgalyuk 79c0c071d0SPavel Dovgalyuk void replay_flush_events(void) 80c0c071d0SPavel Dovgalyuk { 81f9a9fb65SPavel Dovgalyuk if (replay_mode == REPLAY_MODE_NONE) { 82f9a9fb65SPavel Dovgalyuk return; 83f9a9fb65SPavel Dovgalyuk } 84f9a9fb65SPavel Dovgalyuk 85d759c951SAlex Bennée g_assert(replay_mutex_locked()); 86d759c951SAlex Bennée 87c0c071d0SPavel Dovgalyuk while (!QTAILQ_EMPTY(&events_list)) { 88c0c071d0SPavel Dovgalyuk Event *event = QTAILQ_FIRST(&events_list); 89c0c071d0SPavel Dovgalyuk replay_run_event(event); 90c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events); 91c0c071d0SPavel Dovgalyuk g_free(event); 92c0c071d0SPavel Dovgalyuk } 93c0c071d0SPavel Dovgalyuk } 94c0c071d0SPavel Dovgalyuk 95c0c071d0SPavel Dovgalyuk void replay_disable_events(void) 96c0c071d0SPavel Dovgalyuk { 97c0c071d0SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_NONE) { 98c0c071d0SPavel Dovgalyuk events_enabled = false; 99c0c071d0SPavel Dovgalyuk /* Flush events queue before waiting of completion */ 100c0c071d0SPavel Dovgalyuk replay_flush_events(); 101c0c071d0SPavel Dovgalyuk } 102c0c071d0SPavel Dovgalyuk } 103c0c071d0SPavel Dovgalyuk 104c0c071d0SPavel Dovgalyuk /*! Adds specified async event to the queue */ 10533577b47SPavel Dovgalyuk void replay_add_event(ReplayAsyncEventKind event_kind, 106c0c071d0SPavel Dovgalyuk void *opaque, 107c0c071d0SPavel Dovgalyuk void *opaque2, uint64_t id) 108c0c071d0SPavel Dovgalyuk { 109c0c071d0SPavel Dovgalyuk assert(event_kind < REPLAY_ASYNC_COUNT); 110c0c071d0SPavel Dovgalyuk 111c0c071d0SPavel Dovgalyuk if (!replay_file || replay_mode == REPLAY_MODE_NONE 112c0c071d0SPavel Dovgalyuk || !events_enabled) { 113c0c071d0SPavel Dovgalyuk Event e; 114c0c071d0SPavel Dovgalyuk e.event_kind = event_kind; 115c0c071d0SPavel Dovgalyuk e.opaque = opaque; 116c0c071d0SPavel Dovgalyuk e.opaque2 = opaque2; 117c0c071d0SPavel Dovgalyuk e.id = id; 118c0c071d0SPavel Dovgalyuk replay_run_event(&e); 119c0c071d0SPavel Dovgalyuk return; 120c0c071d0SPavel Dovgalyuk } 121c0c071d0SPavel Dovgalyuk 122b21e2380SMarkus Armbruster Event *event = g_new0(Event, 1); 123c0c071d0SPavel Dovgalyuk event->event_kind = event_kind; 124c0c071d0SPavel Dovgalyuk event->opaque = opaque; 125c0c071d0SPavel Dovgalyuk event->opaque2 = opaque2; 126c0c071d0SPavel Dovgalyuk event->id = id; 127c0c071d0SPavel Dovgalyuk 128d759c951SAlex Bennée g_assert(replay_mutex_locked()); 129c0c071d0SPavel Dovgalyuk QTAILQ_INSERT_TAIL(&events_list, event, events); 13046967b1aSPavel Dovgalyuk qemu_cpu_kick(first_cpu); 131c0c071d0SPavel Dovgalyuk } 1328a354bd9SPavel Dovgalyuk 1338a354bd9SPavel Dovgalyuk void replay_bh_schedule_event(QEMUBH *bh) 1348a354bd9SPavel Dovgalyuk { 1351652e0c3SPavel Dovgalyuk if (events_enabled) { 13613f26713SPavel Dovgalyuk uint64_t id = replay_get_current_icount(); 1378a354bd9SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id); 1388a354bd9SPavel Dovgalyuk } else { 1398a354bd9SPavel Dovgalyuk qemu_bh_schedule(bh); 1408a354bd9SPavel Dovgalyuk } 1418a354bd9SPavel Dovgalyuk } 142c0c071d0SPavel Dovgalyuk 143e4ec5ad4SPavel Dovgalyuk void replay_bh_schedule_oneshot_event(AioContext *ctx, 144e4ec5ad4SPavel Dovgalyuk QEMUBHFunc *cb, void *opaque) 145e4ec5ad4SPavel Dovgalyuk { 146e4ec5ad4SPavel Dovgalyuk if (events_enabled) { 147e4ec5ad4SPavel Dovgalyuk uint64_t id = replay_get_current_icount(); 148e4ec5ad4SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_BH_ONESHOT, cb, opaque, id); 149e4ec5ad4SPavel Dovgalyuk } else { 150e4ec5ad4SPavel Dovgalyuk aio_bh_schedule_oneshot(ctx, cb, opaque); 151e4ec5ad4SPavel Dovgalyuk } 152e4ec5ad4SPavel Dovgalyuk } 153e4ec5ad4SPavel Dovgalyuk 154ee312992SPavel Dovgalyuk void replay_add_input_event(struct InputEvent *event) 155ee312992SPavel Dovgalyuk { 156ee312992SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0); 157ee312992SPavel Dovgalyuk } 158ee312992SPavel Dovgalyuk 159ee312992SPavel Dovgalyuk void replay_add_input_sync_event(void) 160ee312992SPavel Dovgalyuk { 161ee312992SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0); 162ee312992SPavel Dovgalyuk } 163ee312992SPavel Dovgalyuk 16463785678SPavel Dovgalyuk void replay_block_event(QEMUBH *bh, uint64_t id) 16563785678SPavel Dovgalyuk { 1661652e0c3SPavel Dovgalyuk if (events_enabled) { 16763785678SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_BLOCK, bh, NULL, id); 16863785678SPavel Dovgalyuk } else { 16963785678SPavel Dovgalyuk qemu_bh_schedule(bh); 17063785678SPavel Dovgalyuk } 17163785678SPavel Dovgalyuk } 17263785678SPavel Dovgalyuk 17360618e2dSPavel Dovgalyuk static void replay_save_event(Event *event) 174c0c071d0SPavel Dovgalyuk { 175c0c071d0SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_PLAY) { 176c0c071d0SPavel Dovgalyuk /* put the event into the file */ 177*3e21408bSPavel Dovgalyuk g_assert(event->event_kind < REPLAY_ASYNC_COUNT); 178*3e21408bSPavel Dovgalyuk replay_put_event(EVENT_ASYNC + event->event_kind); 179c0c071d0SPavel Dovgalyuk 180c0c071d0SPavel Dovgalyuk /* save event-specific data */ 181c0c071d0SPavel Dovgalyuk switch (event->event_kind) { 1828a354bd9SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH: 183e4ec5ad4SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH_ONESHOT: 1848a354bd9SPavel Dovgalyuk replay_put_qword(event->id); 1858a354bd9SPavel Dovgalyuk break; 186ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT: 187ee312992SPavel Dovgalyuk replay_save_input_event(event->opaque); 188ee312992SPavel Dovgalyuk break; 189ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT_SYNC: 190ee312992SPavel Dovgalyuk break; 19133577b47SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_CHAR_READ: 19233577b47SPavel Dovgalyuk replay_event_char_read_save(event->opaque); 19333577b47SPavel Dovgalyuk break; 19463785678SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BLOCK: 19563785678SPavel Dovgalyuk replay_put_qword(event->id); 19663785678SPavel Dovgalyuk break; 197646c5478SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_NET: 198646c5478SPavel Dovgalyuk replay_event_net_save(event->opaque); 199646c5478SPavel Dovgalyuk break; 200c0c071d0SPavel Dovgalyuk default: 20195b4aed5SPavel Dovgalyuk error_report("Unknown ID %" PRId64 " of replay event", event->id); 202c0c071d0SPavel Dovgalyuk exit(1); 203c0c071d0SPavel Dovgalyuk } 204c0c071d0SPavel Dovgalyuk } 205c0c071d0SPavel Dovgalyuk } 206c0c071d0SPavel Dovgalyuk 207c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */ 20860618e2dSPavel Dovgalyuk void replay_save_events(void) 209c0c071d0SPavel Dovgalyuk { 210d759c951SAlex Bennée g_assert(replay_mutex_locked()); 211c0c071d0SPavel Dovgalyuk while (!QTAILQ_EMPTY(&events_list)) { 212c0c071d0SPavel Dovgalyuk Event *event = QTAILQ_FIRST(&events_list); 21360618e2dSPavel Dovgalyuk replay_save_event(event); 214c0c071d0SPavel Dovgalyuk replay_run_event(event); 215c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events); 216c0c071d0SPavel Dovgalyuk g_free(event); 217c0c071d0SPavel Dovgalyuk } 218c0c071d0SPavel Dovgalyuk } 219c0c071d0SPavel Dovgalyuk 22060618e2dSPavel Dovgalyuk static Event *replay_read_event(void) 221c0c071d0SPavel Dovgalyuk { 222c0c071d0SPavel Dovgalyuk Event *event; 223*3e21408bSPavel Dovgalyuk ReplayAsyncEventKind event_kind = replay_state.data_kind - EVENT_ASYNC; 224c0c071d0SPavel Dovgalyuk 225c0c071d0SPavel Dovgalyuk /* Events that has not to be in the queue */ 226*3e21408bSPavel Dovgalyuk switch (event_kind) { 2278a354bd9SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH: 228e4ec5ad4SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH_ONESHOT: 2290b30dc01SPavel Dovgalyuk if (replay_state.read_event_id == -1) { 2300b30dc01SPavel Dovgalyuk replay_state.read_event_id = replay_get_qword(); 2318a354bd9SPavel Dovgalyuk } 2328a354bd9SPavel Dovgalyuk break; 233ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT: 234b21e2380SMarkus Armbruster event = g_new0(Event, 1); 235*3e21408bSPavel Dovgalyuk event->event_kind = event_kind; 236ee312992SPavel Dovgalyuk event->opaque = replay_read_input_event(); 237ee312992SPavel Dovgalyuk return event; 238ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT_SYNC: 239b21e2380SMarkus Armbruster event = g_new0(Event, 1); 240*3e21408bSPavel Dovgalyuk event->event_kind = event_kind; 241ee312992SPavel Dovgalyuk event->opaque = 0; 242ee312992SPavel Dovgalyuk return event; 24333577b47SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_CHAR_READ: 244b21e2380SMarkus Armbruster event = g_new0(Event, 1); 245*3e21408bSPavel Dovgalyuk event->event_kind = event_kind; 24633577b47SPavel Dovgalyuk event->opaque = replay_event_char_read_load(); 24733577b47SPavel Dovgalyuk return event; 24863785678SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BLOCK: 2490b30dc01SPavel Dovgalyuk if (replay_state.read_event_id == -1) { 2500b30dc01SPavel Dovgalyuk replay_state.read_event_id = replay_get_qword(); 25163785678SPavel Dovgalyuk } 25263785678SPavel Dovgalyuk break; 253646c5478SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_NET: 254b21e2380SMarkus Armbruster event = g_new0(Event, 1); 255*3e21408bSPavel Dovgalyuk event->event_kind = event_kind; 256646c5478SPavel Dovgalyuk event->opaque = replay_event_net_load(); 257646c5478SPavel Dovgalyuk return event; 258c0c071d0SPavel Dovgalyuk default: 259*3e21408bSPavel Dovgalyuk error_report("Unknown ID %d of replay event", event_kind); 260c0c071d0SPavel Dovgalyuk exit(1); 261c0c071d0SPavel Dovgalyuk break; 262c0c071d0SPavel Dovgalyuk } 263c0c071d0SPavel Dovgalyuk 264c0c071d0SPavel Dovgalyuk QTAILQ_FOREACH(event, &events_list, events) { 265*3e21408bSPavel Dovgalyuk if (event->event_kind == event_kind 2660b30dc01SPavel Dovgalyuk && (replay_state.read_event_id == -1 2670b30dc01SPavel Dovgalyuk || replay_state.read_event_id == event->id)) { 268c0c071d0SPavel Dovgalyuk break; 269c0c071d0SPavel Dovgalyuk } 270c0c071d0SPavel Dovgalyuk } 271c0c071d0SPavel Dovgalyuk 272c0c071d0SPavel Dovgalyuk if (event) { 273c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events); 274c0c071d0SPavel Dovgalyuk } 275c0c071d0SPavel Dovgalyuk 276c0c071d0SPavel Dovgalyuk return event; 277c0c071d0SPavel Dovgalyuk } 278c0c071d0SPavel Dovgalyuk 279c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */ 28060618e2dSPavel Dovgalyuk void replay_read_events(void) 281c0c071d0SPavel Dovgalyuk { 282d759c951SAlex Bennée g_assert(replay_mutex_locked()); 283*3e21408bSPavel Dovgalyuk while (replay_state.data_kind >= EVENT_ASYNC 284*3e21408bSPavel Dovgalyuk && replay_state.data_kind <= EVENT_ASYNC_LAST) { 28560618e2dSPavel Dovgalyuk Event *event = replay_read_event(); 286c0c071d0SPavel Dovgalyuk if (!event) { 287c0c071d0SPavel Dovgalyuk break; 288c0c071d0SPavel Dovgalyuk } 2891a96e3c1SPavel Dovgalyuk replay_finish_event(); 290*3e21408bSPavel Dovgalyuk replay_state.read_event_id = -1; 291c0c071d0SPavel Dovgalyuk replay_run_event(event); 292c0c071d0SPavel Dovgalyuk 293c0c071d0SPavel Dovgalyuk g_free(event); 294c0c071d0SPavel Dovgalyuk } 295c0c071d0SPavel Dovgalyuk } 296c0c071d0SPavel Dovgalyuk 297c0c071d0SPavel Dovgalyuk void replay_init_events(void) 298c0c071d0SPavel Dovgalyuk { 299*3e21408bSPavel Dovgalyuk replay_state.read_event_id = -1; 300c0c071d0SPavel Dovgalyuk } 301c0c071d0SPavel Dovgalyuk 302c0c071d0SPavel Dovgalyuk void replay_finish_events(void) 303c0c071d0SPavel Dovgalyuk { 304c0c071d0SPavel Dovgalyuk events_enabled = false; 305d873fe03SPavel Dovgalyuk replay_flush_events(); 306c0c071d0SPavel Dovgalyuk } 307c0c071d0SPavel Dovgalyuk 308c0c071d0SPavel Dovgalyuk bool replay_events_enabled(void) 309c0c071d0SPavel Dovgalyuk { 310c0c071d0SPavel Dovgalyuk return events_enabled; 311c0c071d0SPavel Dovgalyuk } 3126d0ceb80SPavel Dovgalyuk 3136d0ceb80SPavel Dovgalyuk uint64_t blkreplay_next_id(void) 3146d0ceb80SPavel Dovgalyuk { 3156d0ceb80SPavel Dovgalyuk if (replay_events_enabled()) { 3166d0ceb80SPavel Dovgalyuk return replay_state.block_request_id++; 3176d0ceb80SPavel Dovgalyuk } 3186d0ceb80SPavel Dovgalyuk return 0; 3196d0ceb80SPavel Dovgalyuk } 320