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