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