replay-internal.c (7051B)
1/* 2 * replay-internal.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 "sysemu/replay.h" 14#include "sysemu/runstate.h" 15#include "replay-internal.h" 16#include "qemu/error-report.h" 17#include "qemu/main-loop.h" 18 19/* Mutex to protect reading and writing events to the log. 20 data_kind and has_unread_data are also protected 21 by this mutex. 22 It also protects replay events queue which stores events to be 23 written or read to the log. */ 24static QemuMutex lock; 25/* Condition and queue for fair ordering of mutex lock requests. */ 26static QemuCond mutex_cond; 27static unsigned long mutex_head, mutex_tail; 28 29/* File for replay writing */ 30static bool write_error; 31FILE *replay_file; 32 33static void replay_write_error(void) 34{ 35 if (!write_error) { 36 error_report("replay write error"); 37 write_error = true; 38 } 39} 40 41static void replay_read_error(void) 42{ 43 error_report("error reading the replay data"); 44 exit(1); 45} 46 47void replay_put_byte(uint8_t byte) 48{ 49 if (replay_file) { 50 if (putc(byte, replay_file) == EOF) { 51 replay_write_error(); 52 } 53 } 54} 55 56void replay_put_event(uint8_t event) 57{ 58 assert(event < EVENT_COUNT); 59 replay_put_byte(event); 60} 61 62 63void replay_put_word(uint16_t word) 64{ 65 replay_put_byte(word >> 8); 66 replay_put_byte(word); 67} 68 69void replay_put_dword(uint32_t dword) 70{ 71 replay_put_word(dword >> 16); 72 replay_put_word(dword); 73} 74 75void replay_put_qword(int64_t qword) 76{ 77 replay_put_dword(qword >> 32); 78 replay_put_dword(qword); 79} 80 81void replay_put_array(const uint8_t *buf, size_t size) 82{ 83 if (replay_file) { 84 replay_put_dword(size); 85 if (fwrite(buf, 1, size, replay_file) != size) { 86 replay_write_error(); 87 } 88 } 89} 90 91uint8_t replay_get_byte(void) 92{ 93 uint8_t byte = 0; 94 if (replay_file) { 95 int r = getc(replay_file); 96 if (r == EOF) { 97 replay_read_error(); 98 } 99 byte = r; 100 } 101 return byte; 102} 103 104uint16_t replay_get_word(void) 105{ 106 uint16_t word = 0; 107 if (replay_file) { 108 word = replay_get_byte(); 109 word = (word << 8) + replay_get_byte(); 110 } 111 112 return word; 113} 114 115uint32_t replay_get_dword(void) 116{ 117 uint32_t dword = 0; 118 if (replay_file) { 119 dword = replay_get_word(); 120 dword = (dword << 16) + replay_get_word(); 121 } 122 123 return dword; 124} 125 126int64_t replay_get_qword(void) 127{ 128 int64_t qword = 0; 129 if (replay_file) { 130 qword = replay_get_dword(); 131 qword = (qword << 32) + replay_get_dword(); 132 } 133 134 return qword; 135} 136 137void replay_get_array(uint8_t *buf, size_t *size) 138{ 139 if (replay_file) { 140 *size = replay_get_dword(); 141 if (fread(buf, 1, *size, replay_file) != *size) { 142 replay_read_error(); 143 } 144 } 145} 146 147void replay_get_array_alloc(uint8_t **buf, size_t *size) 148{ 149 if (replay_file) { 150 *size = replay_get_dword(); 151 *buf = g_malloc(*size); 152 if (fread(*buf, 1, *size, replay_file) != *size) { 153 replay_read_error(); 154 } 155 } 156} 157 158void replay_check_error(void) 159{ 160 if (replay_file) { 161 if (feof(replay_file)) { 162 error_report("replay file is over"); 163 qemu_system_vmstop_request_prepare(); 164 qemu_system_vmstop_request(RUN_STATE_PAUSED); 165 } else if (ferror(replay_file)) { 166 error_report("replay file is over or something goes wrong"); 167 qemu_system_vmstop_request_prepare(); 168 qemu_system_vmstop_request(RUN_STATE_INTERNAL_ERROR); 169 } 170 } 171} 172 173void replay_fetch_data_kind(void) 174{ 175 if (replay_file) { 176 if (!replay_state.has_unread_data) { 177 replay_state.data_kind = replay_get_byte(); 178 if (replay_state.data_kind == EVENT_INSTRUCTION) { 179 replay_state.instruction_count = replay_get_dword(); 180 } 181 replay_check_error(); 182 replay_state.has_unread_data = 1; 183 if (replay_state.data_kind >= EVENT_COUNT) { 184 error_report("Replay: unknown event kind %d", 185 replay_state.data_kind); 186 exit(1); 187 } 188 } 189 } 190} 191 192void replay_finish_event(void) 193{ 194 replay_state.has_unread_data = 0; 195 replay_fetch_data_kind(); 196} 197 198static __thread bool replay_locked; 199 200void replay_mutex_init(void) 201{ 202 qemu_mutex_init(&lock); 203 qemu_cond_init(&mutex_cond); 204 /* Hold the mutex while we start-up */ 205 replay_locked = true; 206 ++mutex_tail; 207} 208 209bool replay_mutex_locked(void) 210{ 211 return replay_locked; 212} 213 214/* Ordering constraints, replay_lock must be taken before BQL */ 215void replay_mutex_lock(void) 216{ 217 if (replay_mode != REPLAY_MODE_NONE) { 218 unsigned long id; 219 g_assert(!qemu_mutex_iothread_locked()); 220 g_assert(!replay_mutex_locked()); 221 qemu_mutex_lock(&lock); 222 id = mutex_tail++; 223 while (id != mutex_head) { 224 qemu_cond_wait(&mutex_cond, &lock); 225 } 226 replay_locked = true; 227 qemu_mutex_unlock(&lock); 228 } 229} 230 231void replay_mutex_unlock(void) 232{ 233 if (replay_mode != REPLAY_MODE_NONE) { 234 g_assert(replay_mutex_locked()); 235 qemu_mutex_lock(&lock); 236 ++mutex_head; 237 replay_locked = false; 238 qemu_cond_broadcast(&mutex_cond); 239 qemu_mutex_unlock(&lock); 240 } 241} 242 243void replay_advance_current_icount(uint64_t current_icount) 244{ 245 int diff = (int)(current_icount - replay_state.current_icount); 246 247 /* Time can only go forward */ 248 assert(diff >= 0); 249 250 if (replay_mode == REPLAY_MODE_RECORD) { 251 if (diff > 0) { 252 replay_put_event(EVENT_INSTRUCTION); 253 replay_put_dword(diff); 254 replay_state.current_icount += diff; 255 } 256 } else if (replay_mode == REPLAY_MODE_PLAY) { 257 if (diff > 0) { 258 replay_state.instruction_count -= diff; 259 replay_state.current_icount += diff; 260 if (replay_state.instruction_count == 0) { 261 assert(replay_state.data_kind == EVENT_INSTRUCTION); 262 replay_finish_event(); 263 /* Wake up iothread. This is required because 264 timers will not expire until clock counters 265 will be read from the log. */ 266 qemu_notify_event(); 267 } 268 } 269 /* Execution reached the break step */ 270 if (replay_break_icount == replay_state.current_icount) { 271 /* Cannot make callback directly from the vCPU thread */ 272 timer_mod_ns(replay_break_timer, 273 qemu_clock_get_ns(QEMU_CLOCK_REALTIME)); 274 } 275 } 276} 277 278/*! Saves cached instructions. */ 279void replay_save_instructions(void) 280{ 281 if (replay_file && replay_mode == REPLAY_MODE_RECORD) { 282 g_assert(replay_mutex_locked()); 283 replay_advance_current_icount(replay_get_current_icount()); 284 } 285}