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-common.h" 13 #include "qemu/error-report.h" 14 #include "sysemu/replay.h" 15 #include "replay-internal.h" 16 17 typedef struct Event { 18 ReplayAsyncEventKind event_kind; 19 void *opaque; 20 void *opaque2; 21 uint64_t id; 22 23 QTAILQ_ENTRY(Event) events; 24 } Event; 25 26 static QTAILQ_HEAD(, Event) events_list = QTAILQ_HEAD_INITIALIZER(events_list); 27 static unsigned int read_event_kind = -1; 28 static uint64_t read_id = -1; 29 static int read_checkpoint = -1; 30 31 static bool events_enabled; 32 33 /* Functions */ 34 35 static void replay_run_event(Event *event) 36 { 37 switch (event->event_kind) { 38 default: 39 error_report("Replay: invalid async event ID (%d) in the queue", 40 event->event_kind); 41 exit(1); 42 break; 43 } 44 } 45 46 void replay_enable_events(void) 47 { 48 events_enabled = true; 49 } 50 51 bool replay_has_events(void) 52 { 53 return !QTAILQ_EMPTY(&events_list); 54 } 55 56 void replay_flush_events(void) 57 { 58 replay_mutex_lock(); 59 while (!QTAILQ_EMPTY(&events_list)) { 60 Event *event = QTAILQ_FIRST(&events_list); 61 replay_mutex_unlock(); 62 replay_run_event(event); 63 replay_mutex_lock(); 64 QTAILQ_REMOVE(&events_list, event, events); 65 g_free(event); 66 } 67 replay_mutex_unlock(); 68 } 69 70 void replay_disable_events(void) 71 { 72 if (replay_mode != REPLAY_MODE_NONE) { 73 events_enabled = false; 74 /* Flush events queue before waiting of completion */ 75 replay_flush_events(); 76 } 77 } 78 79 void replay_clear_events(void) 80 { 81 replay_mutex_lock(); 82 while (!QTAILQ_EMPTY(&events_list)) { 83 Event *event = QTAILQ_FIRST(&events_list); 84 QTAILQ_REMOVE(&events_list, event, events); 85 86 g_free(event); 87 } 88 replay_mutex_unlock(); 89 } 90 91 /*! Adds specified async event to the queue */ 92 #if 0 93 static void replay_add_event(ReplayAsyncEventKind event_kind, 94 void *opaque, 95 void *opaque2, uint64_t id) 96 { 97 assert(event_kind < REPLAY_ASYNC_COUNT); 98 99 if (!replay_file || replay_mode == REPLAY_MODE_NONE 100 || !events_enabled) { 101 Event e; 102 e.event_kind = event_kind; 103 e.opaque = opaque; 104 e.opaque2 = opaque2; 105 e.id = id; 106 replay_run_event(&e); 107 return; 108 } 109 110 Event *event = g_malloc0(sizeof(Event)); 111 event->event_kind = event_kind; 112 event->opaque = opaque; 113 event->opaque2 = opaque2; 114 event->id = id; 115 116 replay_mutex_lock(); 117 QTAILQ_INSERT_TAIL(&events_list, event, events); 118 replay_mutex_unlock(); 119 } 120 #endif 121 122 static void replay_save_event(Event *event, int checkpoint) 123 { 124 if (replay_mode != REPLAY_MODE_PLAY) { 125 /* put the event into the file */ 126 replay_put_event(EVENT_ASYNC); 127 replay_put_byte(checkpoint); 128 replay_put_byte(event->event_kind); 129 130 /* save event-specific data */ 131 switch (event->event_kind) { 132 default: 133 error_report("Unknown ID %d of replay event", read_event_kind); 134 exit(1); 135 break; 136 } 137 } 138 } 139 140 /* Called with replay mutex locked */ 141 void replay_save_events(int checkpoint) 142 { 143 while (!QTAILQ_EMPTY(&events_list)) { 144 Event *event = QTAILQ_FIRST(&events_list); 145 replay_save_event(event, checkpoint); 146 147 replay_mutex_unlock(); 148 replay_run_event(event); 149 replay_mutex_lock(); 150 QTAILQ_REMOVE(&events_list, event, events); 151 g_free(event); 152 } 153 } 154 155 static Event *replay_read_event(int checkpoint) 156 { 157 Event *event; 158 if (read_event_kind == -1) { 159 read_checkpoint = replay_get_byte(); 160 read_event_kind = replay_get_byte(); 161 read_id = -1; 162 replay_check_error(); 163 } 164 165 if (checkpoint != read_checkpoint) { 166 return NULL; 167 } 168 169 /* Events that has not to be in the queue */ 170 switch (read_event_kind) { 171 default: 172 error_report("Unknown ID %d of replay event", read_event_kind); 173 exit(1); 174 break; 175 } 176 177 QTAILQ_FOREACH(event, &events_list, events) { 178 if (event->event_kind == read_event_kind 179 && (read_id == -1 || read_id == event->id)) { 180 break; 181 } 182 } 183 184 if (event) { 185 QTAILQ_REMOVE(&events_list, event, events); 186 } else { 187 return NULL; 188 } 189 190 /* Read event-specific data */ 191 192 return event; 193 } 194 195 /* Called with replay mutex locked */ 196 void replay_read_events(int checkpoint) 197 { 198 while (replay_data_kind == EVENT_ASYNC) { 199 Event *event = replay_read_event(checkpoint); 200 if (!event) { 201 break; 202 } 203 replay_mutex_unlock(); 204 replay_run_event(event); 205 replay_mutex_lock(); 206 207 g_free(event); 208 replay_finish_event(); 209 read_event_kind = -1; 210 } 211 } 212 213 void replay_init_events(void) 214 { 215 read_event_kind = -1; 216 } 217 218 void replay_finish_events(void) 219 { 220 events_enabled = false; 221 replay_clear_events(); 222 } 223 224 bool replay_events_enabled(void) 225 { 226 return events_enabled; 227 } 228