1 /* 2 * replay-events.c 3 * 4 * Copyright (c) 2010-2015 Institute for System Programming 5 * of the Russian Academy of Sciences. 6 * 7 * This work is licensed under the terms of the GNU GPL, version 2 or later. 8 * See the COPYING file in the top-level directory. 9 * 10 */ 11 12 #include "qemu-common.h" 13 #include "qemu/error-report.h" 14 #include "sysemu/replay.h" 15 #include "replay-internal.h" 16 #include "block/aio.h" 17 #include "ui/input.h" 18 19 typedef struct Event { 20 ReplayAsyncEventKind event_kind; 21 void *opaque; 22 void *opaque2; 23 uint64_t id; 24 25 QTAILQ_ENTRY(Event) events; 26 } Event; 27 28 static QTAILQ_HEAD(, Event) events_list = QTAILQ_HEAD_INITIALIZER(events_list); 29 static unsigned int read_event_kind = -1; 30 static uint64_t read_id = -1; 31 static int read_checkpoint = -1; 32 33 static bool events_enabled; 34 35 /* Functions */ 36 37 static void replay_run_event(Event *event) 38 { 39 switch (event->event_kind) { 40 case REPLAY_ASYNC_EVENT_BH: 41 aio_bh_call(event->opaque); 42 break; 43 case REPLAY_ASYNC_EVENT_INPUT: 44 qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque); 45 qapi_free_InputEvent((InputEvent *)event->opaque); 46 break; 47 case REPLAY_ASYNC_EVENT_INPUT_SYNC: 48 qemu_input_event_sync_impl(); 49 break; 50 default: 51 error_report("Replay: invalid async event ID (%d) in the queue", 52 event->event_kind); 53 exit(1); 54 break; 55 } 56 } 57 58 void replay_enable_events(void) 59 { 60 events_enabled = true; 61 } 62 63 bool replay_has_events(void) 64 { 65 return !QTAILQ_EMPTY(&events_list); 66 } 67 68 void replay_flush_events(void) 69 { 70 replay_mutex_lock(); 71 while (!QTAILQ_EMPTY(&events_list)) { 72 Event *event = QTAILQ_FIRST(&events_list); 73 replay_mutex_unlock(); 74 replay_run_event(event); 75 replay_mutex_lock(); 76 QTAILQ_REMOVE(&events_list, event, events); 77 g_free(event); 78 } 79 replay_mutex_unlock(); 80 } 81 82 void replay_disable_events(void) 83 { 84 if (replay_mode != REPLAY_MODE_NONE) { 85 events_enabled = false; 86 /* Flush events queue before waiting of completion */ 87 replay_flush_events(); 88 } 89 } 90 91 void replay_clear_events(void) 92 { 93 replay_mutex_lock(); 94 while (!QTAILQ_EMPTY(&events_list)) { 95 Event *event = QTAILQ_FIRST(&events_list); 96 QTAILQ_REMOVE(&events_list, event, events); 97 98 g_free(event); 99 } 100 replay_mutex_unlock(); 101 } 102 103 /*! Adds specified async event to the queue */ 104 static void replay_add_event(ReplayAsyncEventKind event_kind, 105 void *opaque, 106 void *opaque2, uint64_t id) 107 { 108 assert(event_kind < REPLAY_ASYNC_COUNT); 109 110 if (!replay_file || replay_mode == REPLAY_MODE_NONE 111 || !events_enabled) { 112 Event e; 113 e.event_kind = event_kind; 114 e.opaque = opaque; 115 e.opaque2 = opaque2; 116 e.id = id; 117 replay_run_event(&e); 118 return; 119 } 120 121 Event *event = g_malloc0(sizeof(Event)); 122 event->event_kind = event_kind; 123 event->opaque = opaque; 124 event->opaque2 = opaque2; 125 event->id = id; 126 127 replay_mutex_lock(); 128 QTAILQ_INSERT_TAIL(&events_list, event, events); 129 replay_mutex_unlock(); 130 } 131 132 void replay_bh_schedule_event(QEMUBH *bh) 133 { 134 if (replay_mode != REPLAY_MODE_NONE) { 135 uint64_t id = replay_get_current_step(); 136 replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id); 137 } else { 138 qemu_bh_schedule(bh); 139 } 140 } 141 142 void replay_add_input_event(struct InputEvent *event) 143 { 144 replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0); 145 } 146 147 void replay_add_input_sync_event(void) 148 { 149 replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0); 150 } 151 152 static void replay_save_event(Event *event, int checkpoint) 153 { 154 if (replay_mode != REPLAY_MODE_PLAY) { 155 /* put the event into the file */ 156 replay_put_event(EVENT_ASYNC); 157 replay_put_byte(checkpoint); 158 replay_put_byte(event->event_kind); 159 160 /* save event-specific data */ 161 switch (event->event_kind) { 162 case REPLAY_ASYNC_EVENT_BH: 163 replay_put_qword(event->id); 164 break; 165 case REPLAY_ASYNC_EVENT_INPUT: 166 replay_save_input_event(event->opaque); 167 break; 168 case REPLAY_ASYNC_EVENT_INPUT_SYNC: 169 break; 170 default: 171 error_report("Unknown ID %d of replay event", read_event_kind); 172 exit(1); 173 } 174 } 175 } 176 177 /* Called with replay mutex locked */ 178 void replay_save_events(int checkpoint) 179 { 180 while (!QTAILQ_EMPTY(&events_list)) { 181 Event *event = QTAILQ_FIRST(&events_list); 182 replay_save_event(event, checkpoint); 183 184 replay_mutex_unlock(); 185 replay_run_event(event); 186 replay_mutex_lock(); 187 QTAILQ_REMOVE(&events_list, event, events); 188 g_free(event); 189 } 190 } 191 192 static Event *replay_read_event(int checkpoint) 193 { 194 Event *event; 195 if (read_event_kind == -1) { 196 read_checkpoint = replay_get_byte(); 197 read_event_kind = replay_get_byte(); 198 read_id = -1; 199 replay_check_error(); 200 } 201 202 if (checkpoint != read_checkpoint) { 203 return NULL; 204 } 205 206 /* Events that has not to be in the queue */ 207 switch (read_event_kind) { 208 case REPLAY_ASYNC_EVENT_BH: 209 if (read_id == -1) { 210 read_id = replay_get_qword(); 211 } 212 break; 213 case REPLAY_ASYNC_EVENT_INPUT: 214 event = g_malloc0(sizeof(Event)); 215 event->event_kind = read_event_kind; 216 event->opaque = replay_read_input_event(); 217 return event; 218 case REPLAY_ASYNC_EVENT_INPUT_SYNC: 219 event = g_malloc0(sizeof(Event)); 220 event->event_kind = read_event_kind; 221 event->opaque = 0; 222 return event; 223 default: 224 error_report("Unknown ID %d of replay event", read_event_kind); 225 exit(1); 226 break; 227 } 228 229 QTAILQ_FOREACH(event, &events_list, events) { 230 if (event->event_kind == read_event_kind 231 && (read_id == -1 || read_id == event->id)) { 232 break; 233 } 234 } 235 236 if (event) { 237 QTAILQ_REMOVE(&events_list, event, events); 238 } else { 239 return NULL; 240 } 241 242 /* Read event-specific data */ 243 244 return event; 245 } 246 247 /* Called with replay mutex locked */ 248 void replay_read_events(int checkpoint) 249 { 250 while (replay_data_kind == EVENT_ASYNC) { 251 Event *event = replay_read_event(checkpoint); 252 if (!event) { 253 break; 254 } 255 replay_mutex_unlock(); 256 replay_run_event(event); 257 replay_mutex_lock(); 258 259 g_free(event); 260 replay_finish_event(); 261 read_event_kind = -1; 262 } 263 } 264 265 void replay_init_events(void) 266 { 267 read_event_kind = -1; 268 } 269 270 void replay_finish_events(void) 271 { 272 events_enabled = false; 273 replay_clear_events(); 274 } 275 276 bool replay_events_enabled(void) 277 { 278 return events_enabled; 279 } 280