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 if (replay_mode == REPLAY_MODE_NONE) { 81 return; 82 } 83 84 g_assert(replay_mutex_locked()); 85 86 while (!QTAILQ_EMPTY(&events_list)) { 87 Event *event = QTAILQ_FIRST(&events_list); 88 replay_run_event(event); 89 QTAILQ_REMOVE(&events_list, event, events); 90 g_free(event); 91 } 92 } 93 94 void replay_disable_events(void) 95 { 96 if (replay_mode != REPLAY_MODE_NONE) { 97 events_enabled = false; 98 /* Flush events queue before waiting of completion */ 99 replay_flush_events(); 100 } 101 } 102 103 /*! Adds specified async event to the queue */ 104 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 g_assert(replay_mutex_locked()); 128 QTAILQ_INSERT_TAIL(&events_list, event, events); 129 } 130 131 void replay_bh_schedule_event(QEMUBH *bh) 132 { 133 if (events_enabled) { 134 uint64_t id = replay_get_current_icount(); 135 replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id); 136 } else { 137 qemu_bh_schedule(bh); 138 } 139 } 140 141 void replay_bh_schedule_oneshot_event(AioContext *ctx, 142 QEMUBHFunc *cb, void *opaque) 143 { 144 if (events_enabled) { 145 uint64_t id = replay_get_current_icount(); 146 replay_add_event(REPLAY_ASYNC_EVENT_BH_ONESHOT, cb, opaque, id); 147 } else { 148 aio_bh_schedule_oneshot(ctx, cb, opaque); 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 (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 case REPLAY_ASYNC_EVENT_BH_ONESHOT: 183 replay_put_qword(event->id); 184 break; 185 case REPLAY_ASYNC_EVENT_INPUT: 186 replay_save_input_event(event->opaque); 187 break; 188 case REPLAY_ASYNC_EVENT_INPUT_SYNC: 189 break; 190 case REPLAY_ASYNC_EVENT_CHAR_READ: 191 replay_event_char_read_save(event->opaque); 192 break; 193 case REPLAY_ASYNC_EVENT_BLOCK: 194 replay_put_qword(event->id); 195 break; 196 case REPLAY_ASYNC_EVENT_NET: 197 replay_event_net_save(event->opaque); 198 break; 199 default: 200 error_report("Unknown ID %" PRId64 " of replay event", event->id); 201 exit(1); 202 } 203 } 204 } 205 206 /* Called with replay mutex locked */ 207 void replay_save_events(int checkpoint) 208 { 209 g_assert(replay_mutex_locked()); 210 g_assert(checkpoint != CHECKPOINT_CLOCK_WARP_START); 211 g_assert(checkpoint != CHECKPOINT_CLOCK_VIRTUAL); 212 while (!QTAILQ_EMPTY(&events_list)) { 213 Event *event = QTAILQ_FIRST(&events_list); 214 replay_save_event(event, checkpoint); 215 replay_run_event(event); 216 QTAILQ_REMOVE(&events_list, event, events); 217 g_free(event); 218 } 219 } 220 221 static Event *replay_read_event(int checkpoint) 222 { 223 Event *event; 224 if (replay_state.read_event_kind == -1) { 225 replay_state.read_event_checkpoint = replay_get_byte(); 226 replay_state.read_event_kind = replay_get_byte(); 227 replay_state.read_event_id = -1; 228 replay_check_error(); 229 } 230 231 if (checkpoint != replay_state.read_event_checkpoint) { 232 return NULL; 233 } 234 235 /* Events that has not to be in the queue */ 236 switch (replay_state.read_event_kind) { 237 case REPLAY_ASYNC_EVENT_BH: 238 case REPLAY_ASYNC_EVENT_BH_ONESHOT: 239 if (replay_state.read_event_id == -1) { 240 replay_state.read_event_id = replay_get_qword(); 241 } 242 break; 243 case REPLAY_ASYNC_EVENT_INPUT: 244 event = g_malloc0(sizeof(Event)); 245 event->event_kind = replay_state.read_event_kind; 246 event->opaque = replay_read_input_event(); 247 return event; 248 case REPLAY_ASYNC_EVENT_INPUT_SYNC: 249 event = g_malloc0(sizeof(Event)); 250 event->event_kind = replay_state.read_event_kind; 251 event->opaque = 0; 252 return event; 253 case REPLAY_ASYNC_EVENT_CHAR_READ: 254 event = g_malloc0(sizeof(Event)); 255 event->event_kind = replay_state.read_event_kind; 256 event->opaque = replay_event_char_read_load(); 257 return event; 258 case REPLAY_ASYNC_EVENT_BLOCK: 259 if (replay_state.read_event_id == -1) { 260 replay_state.read_event_id = replay_get_qword(); 261 } 262 break; 263 case REPLAY_ASYNC_EVENT_NET: 264 event = g_malloc0(sizeof(Event)); 265 event->event_kind = replay_state.read_event_kind; 266 event->opaque = replay_event_net_load(); 267 return event; 268 default: 269 error_report("Unknown ID %d of replay event", 270 replay_state.read_event_kind); 271 exit(1); 272 break; 273 } 274 275 QTAILQ_FOREACH(event, &events_list, events) { 276 if (event->event_kind == replay_state.read_event_kind 277 && (replay_state.read_event_id == -1 278 || replay_state.read_event_id == event->id)) { 279 break; 280 } 281 } 282 283 if (event) { 284 QTAILQ_REMOVE(&events_list, event, events); 285 } else { 286 return NULL; 287 } 288 289 /* Read event-specific data */ 290 291 return event; 292 } 293 294 /* Called with replay mutex locked */ 295 void replay_read_events(int checkpoint) 296 { 297 g_assert(replay_mutex_locked()); 298 while (replay_state.data_kind == EVENT_ASYNC) { 299 Event *event = replay_read_event(checkpoint); 300 if (!event) { 301 break; 302 } 303 replay_finish_event(); 304 replay_state.read_event_kind = -1; 305 replay_run_event(event); 306 307 g_free(event); 308 } 309 } 310 311 void replay_init_events(void) 312 { 313 replay_state.read_event_kind = -1; 314 } 315 316 void replay_finish_events(void) 317 { 318 events_enabled = false; 319 replay_flush_events(); 320 } 321 322 bool replay_events_enabled(void) 323 { 324 return events_enabled; 325 } 326 327 uint64_t blkreplay_next_id(void) 328 { 329 if (replay_events_enabled()) { 330 return replay_state.block_request_id++; 331 } 332 return 0; 333 } 334