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 default: 52 error_report("Replay: invalid async event ID (%d) in the queue", 53 event->event_kind); 54 exit(1); 55 break; 56 } 57 } 58 59 void replay_enable_events(void) 60 { 61 events_enabled = true; 62 } 63 64 bool replay_has_events(void) 65 { 66 return !QTAILQ_EMPTY(&events_list); 67 } 68 69 void replay_flush_events(void) 70 { 71 replay_mutex_lock(); 72 while (!QTAILQ_EMPTY(&events_list)) { 73 Event *event = QTAILQ_FIRST(&events_list); 74 replay_mutex_unlock(); 75 replay_run_event(event); 76 replay_mutex_lock(); 77 QTAILQ_REMOVE(&events_list, event, events); 78 g_free(event); 79 } 80 replay_mutex_unlock(); 81 } 82 83 void replay_disable_events(void) 84 { 85 if (replay_mode != REPLAY_MODE_NONE) { 86 events_enabled = false; 87 /* Flush events queue before waiting of completion */ 88 replay_flush_events(); 89 } 90 } 91 92 void replay_clear_events(void) 93 { 94 replay_mutex_lock(); 95 while (!QTAILQ_EMPTY(&events_list)) { 96 Event *event = QTAILQ_FIRST(&events_list); 97 QTAILQ_REMOVE(&events_list, event, events); 98 99 g_free(event); 100 } 101 replay_mutex_unlock(); 102 } 103 104 /*! Adds specified async event to the queue */ 105 static void replay_add_event(ReplayAsyncEventKind event_kind, 106 void *opaque, 107 void *opaque2, uint64_t id) 108 { 109 assert(event_kind < REPLAY_ASYNC_COUNT); 110 111 if (!replay_file || replay_mode == REPLAY_MODE_NONE 112 || !events_enabled) { 113 Event e; 114 e.event_kind = event_kind; 115 e.opaque = opaque; 116 e.opaque2 = opaque2; 117 e.id = id; 118 replay_run_event(&e); 119 return; 120 } 121 122 Event *event = g_malloc0(sizeof(Event)); 123 event->event_kind = event_kind; 124 event->opaque = opaque; 125 event->opaque2 = opaque2; 126 event->id = id; 127 128 replay_mutex_lock(); 129 QTAILQ_INSERT_TAIL(&events_list, event, events); 130 replay_mutex_unlock(); 131 } 132 133 void replay_bh_schedule_event(QEMUBH *bh) 134 { 135 if (replay_mode != REPLAY_MODE_NONE) { 136 uint64_t id = replay_get_current_step(); 137 replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id); 138 } else { 139 qemu_bh_schedule(bh); 140 } 141 } 142 143 void replay_add_input_event(struct InputEvent *event) 144 { 145 replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0); 146 } 147 148 void replay_add_input_sync_event(void) 149 { 150 replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0); 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 default: 172 error_report("Unknown ID %d of replay event", read_event_kind); 173 exit(1); 174 } 175 } 176 } 177 178 /* Called with replay mutex locked */ 179 void replay_save_events(int checkpoint) 180 { 181 while (!QTAILQ_EMPTY(&events_list)) { 182 Event *event = QTAILQ_FIRST(&events_list); 183 replay_save_event(event, checkpoint); 184 185 replay_mutex_unlock(); 186 replay_run_event(event); 187 replay_mutex_lock(); 188 QTAILQ_REMOVE(&events_list, event, events); 189 g_free(event); 190 } 191 } 192 193 static Event *replay_read_event(int checkpoint) 194 { 195 Event *event; 196 if (read_event_kind == -1) { 197 read_checkpoint = replay_get_byte(); 198 read_event_kind = replay_get_byte(); 199 read_id = -1; 200 replay_check_error(); 201 } 202 203 if (checkpoint != read_checkpoint) { 204 return NULL; 205 } 206 207 /* Events that has not to be in the queue */ 208 switch (read_event_kind) { 209 case REPLAY_ASYNC_EVENT_BH: 210 if (read_id == -1) { 211 read_id = replay_get_qword(); 212 } 213 break; 214 case REPLAY_ASYNC_EVENT_INPUT: 215 event = g_malloc0(sizeof(Event)); 216 event->event_kind = read_event_kind; 217 event->opaque = replay_read_input_event(); 218 return event; 219 case REPLAY_ASYNC_EVENT_INPUT_SYNC: 220 event = g_malloc0(sizeof(Event)); 221 event->event_kind = read_event_kind; 222 event->opaque = 0; 223 return event; 224 default: 225 error_report("Unknown ID %d of replay event", read_event_kind); 226 exit(1); 227 break; 228 } 229 230 QTAILQ_FOREACH(event, &events_list, events) { 231 if (event->event_kind == read_event_kind 232 && (read_id == -1 || read_id == event->id)) { 233 break; 234 } 235 } 236 237 if (event) { 238 QTAILQ_REMOVE(&events_list, event, events); 239 } else { 240 return NULL; 241 } 242 243 /* Read event-specific data */ 244 245 return event; 246 } 247 248 /* Called with replay mutex locked */ 249 void replay_read_events(int checkpoint) 250 { 251 while (replay_data_kind == EVENT_ASYNC) { 252 Event *event = replay_read_event(checkpoint); 253 if (!event) { 254 break; 255 } 256 replay_mutex_unlock(); 257 replay_run_event(event); 258 replay_mutex_lock(); 259 260 g_free(event); 261 replay_finish_event(); 262 read_event_kind = -1; 263 } 264 } 265 266 void replay_init_events(void) 267 { 268 read_event_kind = -1; 269 } 270 271 void replay_finish_events(void) 272 { 273 events_enabled = false; 274 replay_clear_events(); 275 } 276 277 bool replay_events_enabled(void) 278 { 279 return events_enabled; 280 } 281