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 /*! Adds specified async event to the queue */ 98 void replay_add_event(ReplayAsyncEventKind event_kind, 99 void *opaque, 100 void *opaque2, uint64_t id) 101 { 102 assert(event_kind < REPLAY_ASYNC_COUNT); 103 104 if (!replay_file || replay_mode == REPLAY_MODE_NONE 105 || !events_enabled) { 106 Event e; 107 e.event_kind = event_kind; 108 e.opaque = opaque; 109 e.opaque2 = opaque2; 110 e.id = id; 111 replay_run_event(&e); 112 return; 113 } 114 115 Event *event = g_malloc0(sizeof(Event)); 116 event->event_kind = event_kind; 117 event->opaque = opaque; 118 event->opaque2 = opaque2; 119 event->id = id; 120 121 g_assert(replay_mutex_locked()); 122 QTAILQ_INSERT_TAIL(&events_list, event, events); 123 } 124 125 void replay_bh_schedule_event(QEMUBH *bh) 126 { 127 if (events_enabled) { 128 uint64_t id = replay_get_current_step(); 129 replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id); 130 } else { 131 qemu_bh_schedule(bh); 132 } 133 } 134 135 void replay_add_input_event(struct InputEvent *event) 136 { 137 replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0); 138 } 139 140 void replay_add_input_sync_event(void) 141 { 142 replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0); 143 } 144 145 void replay_block_event(QEMUBH *bh, uint64_t id) 146 { 147 if (events_enabled) { 148 replay_add_event(REPLAY_ASYNC_EVENT_BLOCK, bh, NULL, id); 149 } else { 150 qemu_bh_schedule(bh); 151 } 152 } 153 154 static void replay_save_event(Event *event, int checkpoint) 155 { 156 if (replay_mode != REPLAY_MODE_PLAY) { 157 /* put the event into the file */ 158 replay_put_event(EVENT_ASYNC); 159 replay_put_byte(checkpoint); 160 replay_put_byte(event->event_kind); 161 162 /* save event-specific data */ 163 switch (event->event_kind) { 164 case REPLAY_ASYNC_EVENT_BH: 165 replay_put_qword(event->id); 166 break; 167 case REPLAY_ASYNC_EVENT_INPUT: 168 replay_save_input_event(event->opaque); 169 break; 170 case REPLAY_ASYNC_EVENT_INPUT_SYNC: 171 break; 172 case REPLAY_ASYNC_EVENT_CHAR_READ: 173 replay_event_char_read_save(event->opaque); 174 break; 175 case REPLAY_ASYNC_EVENT_BLOCK: 176 replay_put_qword(event->id); 177 break; 178 case REPLAY_ASYNC_EVENT_NET: 179 replay_event_net_save(event->opaque); 180 break; 181 default: 182 error_report("Unknown ID %" PRId64 " of replay event", event->id); 183 exit(1); 184 } 185 } 186 } 187 188 /* Called with replay mutex locked */ 189 void replay_save_events(int checkpoint) 190 { 191 g_assert(replay_mutex_locked()); 192 g_assert(checkpoint != CHECKPOINT_CLOCK_WARP_START); 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