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/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 bool events_enabled; 30 31 /* Functions */ 32 33 static void replay_run_event(Event *event) 34 { 35 switch (event->event_kind) { 36 case REPLAY_ASYNC_EVENT_BH: 37 aio_bh_call(event->opaque); 38 break; 39 case REPLAY_ASYNC_EVENT_BH_ONESHOT: 40 ((QEMUBHFunc *)event->opaque)(event->opaque2); 41 break; 42 case REPLAY_ASYNC_EVENT_INPUT: 43 qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque); 44 qapi_free_InputEvent((InputEvent *)event->opaque); 45 break; 46 case REPLAY_ASYNC_EVENT_INPUT_SYNC: 47 qemu_input_event_sync_impl(); 48 break; 49 case REPLAY_ASYNC_EVENT_CHAR_READ: 50 replay_event_char_read_run(event->opaque); 51 break; 52 case REPLAY_ASYNC_EVENT_BLOCK: 53 aio_bh_call(event->opaque); 54 break; 55 case REPLAY_ASYNC_EVENT_NET: 56 replay_event_net_run(event->opaque); 57 break; 58 default: 59 error_report("Replay: invalid async event ID (%d) in the queue", 60 event->event_kind); 61 exit(1); 62 break; 63 } 64 } 65 66 void replay_enable_events(void) 67 { 68 if (replay_mode != REPLAY_MODE_NONE) { 69 events_enabled = true; 70 } 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 g_assert(replay_mutex_locked()); 81 82 while (!QTAILQ_EMPTY(&events_list)) { 83 Event *event = QTAILQ_FIRST(&events_list); 84 replay_run_event(event); 85 QTAILQ_REMOVE(&events_list, event, events); 86 g_free(event); 87 } 88 } 89 90 void replay_disable_events(void) 91 { 92 if (replay_mode != REPLAY_MODE_NONE) { 93 events_enabled = false; 94 /* Flush events queue before waiting of completion */ 95 replay_flush_events(); 96 } 97 } 98 99 /*! Adds specified async event to the queue */ 100 void replay_add_event(ReplayAsyncEventKind event_kind, 101 void *opaque, 102 void *opaque2, uint64_t id) 103 { 104 assert(event_kind < REPLAY_ASYNC_COUNT); 105 106 if (!replay_file || replay_mode == REPLAY_MODE_NONE 107 || !events_enabled) { 108 Event e; 109 e.event_kind = event_kind; 110 e.opaque = opaque; 111 e.opaque2 = opaque2; 112 e.id = id; 113 replay_run_event(&e); 114 return; 115 } 116 117 Event *event = g_malloc0(sizeof(Event)); 118 event->event_kind = event_kind; 119 event->opaque = opaque; 120 event->opaque2 = opaque2; 121 event->id = id; 122 123 g_assert(replay_mutex_locked()); 124 QTAILQ_INSERT_TAIL(&events_list, event, events); 125 } 126 127 void replay_bh_schedule_event(QEMUBH *bh) 128 { 129 if (events_enabled) { 130 uint64_t id = replay_get_current_icount(); 131 replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id); 132 } else { 133 qemu_bh_schedule(bh); 134 } 135 } 136 137 void replay_bh_schedule_oneshot_event(AioContext *ctx, 138 QEMUBHFunc *cb, void *opaque) 139 { 140 if (events_enabled) { 141 uint64_t id = replay_get_current_icount(); 142 replay_add_event(REPLAY_ASYNC_EVENT_BH_ONESHOT, cb, opaque, id); 143 } else { 144 aio_bh_schedule_oneshot(ctx, cb, opaque); 145 } 146 } 147 148 void replay_add_input_event(struct InputEvent *event) 149 { 150 replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0); 151 } 152 153 void replay_add_input_sync_event(void) 154 { 155 replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0); 156 } 157 158 void replay_block_event(QEMUBH *bh, uint64_t id) 159 { 160 if (events_enabled) { 161 replay_add_event(REPLAY_ASYNC_EVENT_BLOCK, bh, NULL, id); 162 } else { 163 qemu_bh_schedule(bh); 164 } 165 } 166 167 static void replay_save_event(Event *event, int checkpoint) 168 { 169 if (replay_mode != REPLAY_MODE_PLAY) { 170 /* put the event into the file */ 171 replay_put_event(EVENT_ASYNC); 172 replay_put_byte(checkpoint); 173 replay_put_byte(event->event_kind); 174 175 /* save event-specific data */ 176 switch (event->event_kind) { 177 case REPLAY_ASYNC_EVENT_BH: 178 case REPLAY_ASYNC_EVENT_BH_ONESHOT: 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 case REPLAY_ASYNC_EVENT_NET: 193 replay_event_net_save(event->opaque); 194 break; 195 default: 196 error_report("Unknown ID %" PRId64 " of replay event", event->id); 197 exit(1); 198 } 199 } 200 } 201 202 /* Called with replay mutex locked */ 203 void replay_save_events(int checkpoint) 204 { 205 g_assert(replay_mutex_locked()); 206 g_assert(checkpoint != CHECKPOINT_CLOCK_WARP_START); 207 g_assert(checkpoint != CHECKPOINT_CLOCK_VIRTUAL); 208 while (!QTAILQ_EMPTY(&events_list)) { 209 Event *event = QTAILQ_FIRST(&events_list); 210 replay_save_event(event, checkpoint); 211 replay_run_event(event); 212 QTAILQ_REMOVE(&events_list, event, events); 213 g_free(event); 214 } 215 } 216 217 static Event *replay_read_event(int checkpoint) 218 { 219 Event *event; 220 if (replay_state.read_event_kind == -1) { 221 replay_state.read_event_checkpoint = replay_get_byte(); 222 replay_state.read_event_kind = replay_get_byte(); 223 replay_state.read_event_id = -1; 224 replay_check_error(); 225 } 226 227 if (checkpoint != replay_state.read_event_checkpoint) { 228 return NULL; 229 } 230 231 /* Events that has not to be in the queue */ 232 switch (replay_state.read_event_kind) { 233 case REPLAY_ASYNC_EVENT_BH: 234 case REPLAY_ASYNC_EVENT_BH_ONESHOT: 235 if (replay_state.read_event_id == -1) { 236 replay_state.read_event_id = replay_get_qword(); 237 } 238 break; 239 case REPLAY_ASYNC_EVENT_INPUT: 240 event = g_malloc0(sizeof(Event)); 241 event->event_kind = replay_state.read_event_kind; 242 event->opaque = replay_read_input_event(); 243 return event; 244 case REPLAY_ASYNC_EVENT_INPUT_SYNC: 245 event = g_malloc0(sizeof(Event)); 246 event->event_kind = replay_state.read_event_kind; 247 event->opaque = 0; 248 return event; 249 case REPLAY_ASYNC_EVENT_CHAR_READ: 250 event = g_malloc0(sizeof(Event)); 251 event->event_kind = replay_state.read_event_kind; 252 event->opaque = replay_event_char_read_load(); 253 return event; 254 case REPLAY_ASYNC_EVENT_BLOCK: 255 if (replay_state.read_event_id == -1) { 256 replay_state.read_event_id = replay_get_qword(); 257 } 258 break; 259 case REPLAY_ASYNC_EVENT_NET: 260 event = g_malloc0(sizeof(Event)); 261 event->event_kind = replay_state.read_event_kind; 262 event->opaque = replay_event_net_load(); 263 return event; 264 default: 265 error_report("Unknown ID %d of replay event", 266 replay_state.read_event_kind); 267 exit(1); 268 break; 269 } 270 271 QTAILQ_FOREACH(event, &events_list, events) { 272 if (event->event_kind == replay_state.read_event_kind 273 && (replay_state.read_event_id == -1 274 || replay_state.read_event_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 g_assert(replay_mutex_locked()); 294 while (replay_state.data_kind == EVENT_ASYNC) { 295 Event *event = replay_read_event(checkpoint); 296 if (!event) { 297 break; 298 } 299 replay_finish_event(); 300 replay_state.read_event_kind = -1; 301 replay_run_event(event); 302 303 g_free(event); 304 } 305 } 306 307 void replay_init_events(void) 308 { 309 replay_state.read_event_kind = -1; 310 } 311 312 void replay_finish_events(void) 313 { 314 events_enabled = false; 315 replay_flush_events(); 316 } 317 318 bool replay_events_enabled(void) 319 { 320 return events_enabled; 321 } 322 323 uint64_t blkreplay_next_id(void) 324 { 325 if (replay_events_enabled()) { 326 return replay_state.block_request_id++; 327 } 328 return 0; 329 } 330