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