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