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