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