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 12c0c071d0SPavel Dovgalyuk #include "qemu-common.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" 17*ee312992SPavel 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 unsigned int read_event_kind = -1; 30c0c071d0SPavel Dovgalyuk static uint64_t read_id = -1; 31c0c071d0SPavel Dovgalyuk static int read_checkpoint = -1; 32c0c071d0SPavel Dovgalyuk 33c0c071d0SPavel Dovgalyuk static bool events_enabled; 34c0c071d0SPavel Dovgalyuk 35c0c071d0SPavel Dovgalyuk /* Functions */ 36c0c071d0SPavel Dovgalyuk 37c0c071d0SPavel Dovgalyuk static void replay_run_event(Event *event) 38c0c071d0SPavel Dovgalyuk { 39c0c071d0SPavel Dovgalyuk switch (event->event_kind) { 408a354bd9SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH: 418a354bd9SPavel Dovgalyuk aio_bh_call(event->opaque); 428a354bd9SPavel Dovgalyuk break; 43*ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT: 44*ee312992SPavel Dovgalyuk qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque); 45*ee312992SPavel Dovgalyuk qapi_free_InputEvent((InputEvent *)event->opaque); 46*ee312992SPavel Dovgalyuk break; 47*ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT_SYNC: 48*ee312992SPavel Dovgalyuk qemu_input_event_sync_impl(); 49*ee312992SPavel Dovgalyuk break; 50c0c071d0SPavel Dovgalyuk default: 51c0c071d0SPavel Dovgalyuk error_report("Replay: invalid async event ID (%d) in the queue", 52c0c071d0SPavel Dovgalyuk event->event_kind); 53c0c071d0SPavel Dovgalyuk exit(1); 54c0c071d0SPavel Dovgalyuk break; 55c0c071d0SPavel Dovgalyuk } 56c0c071d0SPavel Dovgalyuk } 57c0c071d0SPavel Dovgalyuk 58c0c071d0SPavel Dovgalyuk void replay_enable_events(void) 59c0c071d0SPavel Dovgalyuk { 60c0c071d0SPavel Dovgalyuk events_enabled = true; 61c0c071d0SPavel Dovgalyuk } 62c0c071d0SPavel Dovgalyuk 63c0c071d0SPavel Dovgalyuk bool replay_has_events(void) 64c0c071d0SPavel Dovgalyuk { 65c0c071d0SPavel Dovgalyuk return !QTAILQ_EMPTY(&events_list); 66c0c071d0SPavel Dovgalyuk } 67c0c071d0SPavel Dovgalyuk 68c0c071d0SPavel Dovgalyuk void replay_flush_events(void) 69c0c071d0SPavel Dovgalyuk { 70c0c071d0SPavel Dovgalyuk replay_mutex_lock(); 71c0c071d0SPavel Dovgalyuk while (!QTAILQ_EMPTY(&events_list)) { 72c0c071d0SPavel Dovgalyuk Event *event = QTAILQ_FIRST(&events_list); 73c0c071d0SPavel Dovgalyuk replay_mutex_unlock(); 74c0c071d0SPavel Dovgalyuk replay_run_event(event); 75c0c071d0SPavel Dovgalyuk replay_mutex_lock(); 76c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events); 77c0c071d0SPavel Dovgalyuk g_free(event); 78c0c071d0SPavel Dovgalyuk } 79c0c071d0SPavel Dovgalyuk replay_mutex_unlock(); 80c0c071d0SPavel Dovgalyuk } 81c0c071d0SPavel Dovgalyuk 82c0c071d0SPavel Dovgalyuk void replay_disable_events(void) 83c0c071d0SPavel Dovgalyuk { 84c0c071d0SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_NONE) { 85c0c071d0SPavel Dovgalyuk events_enabled = false; 86c0c071d0SPavel Dovgalyuk /* Flush events queue before waiting of completion */ 87c0c071d0SPavel Dovgalyuk replay_flush_events(); 88c0c071d0SPavel Dovgalyuk } 89c0c071d0SPavel Dovgalyuk } 90c0c071d0SPavel Dovgalyuk 91c0c071d0SPavel Dovgalyuk void replay_clear_events(void) 92c0c071d0SPavel Dovgalyuk { 93c0c071d0SPavel Dovgalyuk replay_mutex_lock(); 94c0c071d0SPavel Dovgalyuk while (!QTAILQ_EMPTY(&events_list)) { 95c0c071d0SPavel Dovgalyuk Event *event = QTAILQ_FIRST(&events_list); 96c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events); 97c0c071d0SPavel Dovgalyuk 98c0c071d0SPavel Dovgalyuk g_free(event); 99c0c071d0SPavel Dovgalyuk } 100c0c071d0SPavel Dovgalyuk replay_mutex_unlock(); 101c0c071d0SPavel Dovgalyuk } 102c0c071d0SPavel Dovgalyuk 103c0c071d0SPavel Dovgalyuk /*! Adds specified async event to the queue */ 104c0c071d0SPavel Dovgalyuk static void replay_add_event(ReplayAsyncEventKind event_kind, 105c0c071d0SPavel Dovgalyuk void *opaque, 106c0c071d0SPavel Dovgalyuk void *opaque2, uint64_t id) 107c0c071d0SPavel Dovgalyuk { 108c0c071d0SPavel Dovgalyuk assert(event_kind < REPLAY_ASYNC_COUNT); 109c0c071d0SPavel Dovgalyuk 110c0c071d0SPavel Dovgalyuk if (!replay_file || replay_mode == REPLAY_MODE_NONE 111c0c071d0SPavel Dovgalyuk || !events_enabled) { 112c0c071d0SPavel Dovgalyuk Event e; 113c0c071d0SPavel Dovgalyuk e.event_kind = event_kind; 114c0c071d0SPavel Dovgalyuk e.opaque = opaque; 115c0c071d0SPavel Dovgalyuk e.opaque2 = opaque2; 116c0c071d0SPavel Dovgalyuk e.id = id; 117c0c071d0SPavel Dovgalyuk replay_run_event(&e); 118c0c071d0SPavel Dovgalyuk return; 119c0c071d0SPavel Dovgalyuk } 120c0c071d0SPavel Dovgalyuk 121c0c071d0SPavel Dovgalyuk Event *event = g_malloc0(sizeof(Event)); 122c0c071d0SPavel Dovgalyuk event->event_kind = event_kind; 123c0c071d0SPavel Dovgalyuk event->opaque = opaque; 124c0c071d0SPavel Dovgalyuk event->opaque2 = opaque2; 125c0c071d0SPavel Dovgalyuk event->id = id; 126c0c071d0SPavel Dovgalyuk 127c0c071d0SPavel Dovgalyuk replay_mutex_lock(); 128c0c071d0SPavel Dovgalyuk QTAILQ_INSERT_TAIL(&events_list, event, events); 129c0c071d0SPavel Dovgalyuk replay_mutex_unlock(); 130c0c071d0SPavel Dovgalyuk } 1318a354bd9SPavel Dovgalyuk 1328a354bd9SPavel Dovgalyuk void replay_bh_schedule_event(QEMUBH *bh) 1338a354bd9SPavel Dovgalyuk { 1348a354bd9SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_NONE) { 1358a354bd9SPavel Dovgalyuk uint64_t id = replay_get_current_step(); 1368a354bd9SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id); 1378a354bd9SPavel Dovgalyuk } else { 1388a354bd9SPavel Dovgalyuk qemu_bh_schedule(bh); 1398a354bd9SPavel Dovgalyuk } 1408a354bd9SPavel Dovgalyuk } 141c0c071d0SPavel Dovgalyuk 142*ee312992SPavel Dovgalyuk void replay_add_input_event(struct InputEvent *event) 143*ee312992SPavel Dovgalyuk { 144*ee312992SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0); 145*ee312992SPavel Dovgalyuk } 146*ee312992SPavel Dovgalyuk 147*ee312992SPavel Dovgalyuk void replay_add_input_sync_event(void) 148*ee312992SPavel Dovgalyuk { 149*ee312992SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0); 150*ee312992SPavel Dovgalyuk } 151*ee312992SPavel Dovgalyuk 152c0c071d0SPavel Dovgalyuk static void replay_save_event(Event *event, int checkpoint) 153c0c071d0SPavel Dovgalyuk { 154c0c071d0SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_PLAY) { 155c0c071d0SPavel Dovgalyuk /* put the event into the file */ 156c0c071d0SPavel Dovgalyuk replay_put_event(EVENT_ASYNC); 157c0c071d0SPavel Dovgalyuk replay_put_byte(checkpoint); 158c0c071d0SPavel Dovgalyuk replay_put_byte(event->event_kind); 159c0c071d0SPavel Dovgalyuk 160c0c071d0SPavel Dovgalyuk /* save event-specific data */ 161c0c071d0SPavel Dovgalyuk switch (event->event_kind) { 1628a354bd9SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH: 1638a354bd9SPavel Dovgalyuk replay_put_qword(event->id); 1648a354bd9SPavel Dovgalyuk break; 165*ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT: 166*ee312992SPavel Dovgalyuk replay_save_input_event(event->opaque); 167*ee312992SPavel Dovgalyuk break; 168*ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT_SYNC: 169*ee312992SPavel Dovgalyuk break; 170c0c071d0SPavel Dovgalyuk default: 171c0c071d0SPavel Dovgalyuk error_report("Unknown ID %d of replay event", read_event_kind); 172c0c071d0SPavel Dovgalyuk exit(1); 173c0c071d0SPavel Dovgalyuk } 174c0c071d0SPavel Dovgalyuk } 175c0c071d0SPavel Dovgalyuk } 176c0c071d0SPavel Dovgalyuk 177c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */ 178c0c071d0SPavel Dovgalyuk void replay_save_events(int checkpoint) 179c0c071d0SPavel Dovgalyuk { 180c0c071d0SPavel Dovgalyuk while (!QTAILQ_EMPTY(&events_list)) { 181c0c071d0SPavel Dovgalyuk Event *event = QTAILQ_FIRST(&events_list); 182c0c071d0SPavel Dovgalyuk replay_save_event(event, checkpoint); 183c0c071d0SPavel Dovgalyuk 184c0c071d0SPavel Dovgalyuk replay_mutex_unlock(); 185c0c071d0SPavel Dovgalyuk replay_run_event(event); 186c0c071d0SPavel Dovgalyuk replay_mutex_lock(); 187c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events); 188c0c071d0SPavel Dovgalyuk g_free(event); 189c0c071d0SPavel Dovgalyuk } 190c0c071d0SPavel Dovgalyuk } 191c0c071d0SPavel Dovgalyuk 192c0c071d0SPavel Dovgalyuk static Event *replay_read_event(int checkpoint) 193c0c071d0SPavel Dovgalyuk { 194c0c071d0SPavel Dovgalyuk Event *event; 195c0c071d0SPavel Dovgalyuk if (read_event_kind == -1) { 196c0c071d0SPavel Dovgalyuk read_checkpoint = replay_get_byte(); 197c0c071d0SPavel Dovgalyuk read_event_kind = replay_get_byte(); 198c0c071d0SPavel Dovgalyuk read_id = -1; 199c0c071d0SPavel Dovgalyuk replay_check_error(); 200c0c071d0SPavel Dovgalyuk } 201c0c071d0SPavel Dovgalyuk 202c0c071d0SPavel Dovgalyuk if (checkpoint != read_checkpoint) { 203c0c071d0SPavel Dovgalyuk return NULL; 204c0c071d0SPavel Dovgalyuk } 205c0c071d0SPavel Dovgalyuk 206c0c071d0SPavel Dovgalyuk /* Events that has not to be in the queue */ 207c0c071d0SPavel Dovgalyuk switch (read_event_kind) { 2088a354bd9SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH: 2098a354bd9SPavel Dovgalyuk if (read_id == -1) { 2108a354bd9SPavel Dovgalyuk read_id = replay_get_qword(); 2118a354bd9SPavel Dovgalyuk } 2128a354bd9SPavel Dovgalyuk break; 213*ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT: 214*ee312992SPavel Dovgalyuk event = g_malloc0(sizeof(Event)); 215*ee312992SPavel Dovgalyuk event->event_kind = read_event_kind; 216*ee312992SPavel Dovgalyuk event->opaque = replay_read_input_event(); 217*ee312992SPavel Dovgalyuk return event; 218*ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT_SYNC: 219*ee312992SPavel Dovgalyuk event = g_malloc0(sizeof(Event)); 220*ee312992SPavel Dovgalyuk event->event_kind = read_event_kind; 221*ee312992SPavel Dovgalyuk event->opaque = 0; 222*ee312992SPavel Dovgalyuk return event; 223c0c071d0SPavel Dovgalyuk default: 224c0c071d0SPavel Dovgalyuk error_report("Unknown ID %d of replay event", read_event_kind); 225c0c071d0SPavel Dovgalyuk exit(1); 226c0c071d0SPavel Dovgalyuk break; 227c0c071d0SPavel Dovgalyuk } 228c0c071d0SPavel Dovgalyuk 229c0c071d0SPavel Dovgalyuk QTAILQ_FOREACH(event, &events_list, events) { 230c0c071d0SPavel Dovgalyuk if (event->event_kind == read_event_kind 231c0c071d0SPavel Dovgalyuk && (read_id == -1 || read_id == event->id)) { 232c0c071d0SPavel Dovgalyuk break; 233c0c071d0SPavel Dovgalyuk } 234c0c071d0SPavel Dovgalyuk } 235c0c071d0SPavel Dovgalyuk 236c0c071d0SPavel Dovgalyuk if (event) { 237c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events); 238c0c071d0SPavel Dovgalyuk } else { 239c0c071d0SPavel Dovgalyuk return NULL; 240c0c071d0SPavel Dovgalyuk } 241c0c071d0SPavel Dovgalyuk 242c0c071d0SPavel Dovgalyuk /* Read event-specific data */ 243c0c071d0SPavel Dovgalyuk 244c0c071d0SPavel Dovgalyuk return event; 245c0c071d0SPavel Dovgalyuk } 246c0c071d0SPavel Dovgalyuk 247c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */ 248c0c071d0SPavel Dovgalyuk void replay_read_events(int checkpoint) 249c0c071d0SPavel Dovgalyuk { 250c0c071d0SPavel Dovgalyuk while (replay_data_kind == EVENT_ASYNC) { 251c0c071d0SPavel Dovgalyuk Event *event = replay_read_event(checkpoint); 252c0c071d0SPavel Dovgalyuk if (!event) { 253c0c071d0SPavel Dovgalyuk break; 254c0c071d0SPavel Dovgalyuk } 255c0c071d0SPavel Dovgalyuk replay_mutex_unlock(); 256c0c071d0SPavel Dovgalyuk replay_run_event(event); 257c0c071d0SPavel Dovgalyuk replay_mutex_lock(); 258c0c071d0SPavel Dovgalyuk 259c0c071d0SPavel Dovgalyuk g_free(event); 260c0c071d0SPavel Dovgalyuk replay_finish_event(); 261c0c071d0SPavel Dovgalyuk read_event_kind = -1; 262c0c071d0SPavel Dovgalyuk } 263c0c071d0SPavel Dovgalyuk } 264c0c071d0SPavel Dovgalyuk 265c0c071d0SPavel Dovgalyuk void replay_init_events(void) 266c0c071d0SPavel Dovgalyuk { 267c0c071d0SPavel Dovgalyuk read_event_kind = -1; 268c0c071d0SPavel Dovgalyuk } 269c0c071d0SPavel Dovgalyuk 270c0c071d0SPavel Dovgalyuk void replay_finish_events(void) 271c0c071d0SPavel Dovgalyuk { 272c0c071d0SPavel Dovgalyuk events_enabled = false; 273c0c071d0SPavel Dovgalyuk replay_clear_events(); 274c0c071d0SPavel Dovgalyuk } 275c0c071d0SPavel Dovgalyuk 276c0c071d0SPavel Dovgalyuk bool replay_events_enabled(void) 277c0c071d0SPavel Dovgalyuk { 278c0c071d0SPavel Dovgalyuk return events_enabled; 279c0c071d0SPavel Dovgalyuk } 280