4 * Copyright (c) 2010-2015 Institute for System Programming
5 * of the Russian Academy of Sciences.
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.
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"
19 /* Mutex to protect reading and writing events to the log.
20 data_kind and has_unread_data are also protected
22 It also protects replay events queue which stores events to be
23 written or read to the log. */
24 static QemuMutex lock
;
25 /* Condition and queue for fair ordering of mutex lock requests. */
26 static QemuCond mutex_cond
;
27 static unsigned long mutex_head
, mutex_tail
;
29 /* File for replay writing */
30 static bool write_error
;
33 static void replay_write_error(void)
36 error_report("replay write error");
41 static void replay_read_error(void)
43 error_report("error reading the replay data");
47 void replay_put_byte(uint8_t byte
)
50 if (putc(byte
, replay_file
) == EOF
) {
56 void replay_put_event(uint8_t event
)
58 assert(event
< EVENT_COUNT
);
59 replay_put_byte(event
);
63 void replay_put_word(uint16_t word
)
65 replay_put_byte(word
>> 8);
66 replay_put_byte(word
);
69 void replay_put_dword(uint32_t dword
)
71 replay_put_word(dword
>> 16);
72 replay_put_word(dword
);
75 void replay_put_qword(int64_t qword
)
77 replay_put_dword(qword
>> 32);
78 replay_put_dword(qword
);
81 void replay_put_array(const uint8_t *buf
, size_t size
)
84 replay_put_dword(size
);
85 if (fwrite(buf
, 1, size
, replay_file
) != size
) {
91 uint8_t replay_get_byte(void)
95 int r
= getc(replay_file
);
104 uint16_t replay_get_word(void)
108 word
= replay_get_byte();
109 word
= (word
<< 8) + replay_get_byte();
115 uint32_t replay_get_dword(void)
119 dword
= replay_get_word();
120 dword
= (dword
<< 16) + replay_get_word();
126 int64_t replay_get_qword(void)
130 qword
= replay_get_dword();
131 qword
= (qword
<< 32) + replay_get_dword();
137 void replay_get_array(uint8_t *buf
, size_t *size
)
140 *size
= replay_get_dword();
141 if (fread(buf
, 1, *size
, replay_file
) != *size
) {
147 void replay_get_array_alloc(uint8_t **buf
, size_t *size
)
150 *size
= replay_get_dword();
151 *buf
= g_malloc(*size
);
152 if (fread(*buf
, 1, *size
, replay_file
) != *size
) {
158 void replay_check_error(void)
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
);
173 void replay_fetch_data_kind(void)
176 if (!replay_state
.has_unread_data
) {
177 replay_state
.data_kind
= replay_get_byte();
178 replay_state
.current_event
++;
179 if (replay_state
.data_kind
== EVENT_INSTRUCTION
) {
180 replay_state
.instruction_count
= replay_get_dword();
182 replay_check_error();
183 replay_state
.has_unread_data
= true;
184 if (replay_state
.data_kind
>= EVENT_COUNT
) {
185 error_report("Replay: unknown event kind %d",
186 replay_state
.data_kind
);
193 void replay_finish_event(void)
195 replay_state
.has_unread_data
= false;
196 replay_fetch_data_kind();
199 static __thread
bool replay_locked
;
201 void replay_mutex_init(void)
203 qemu_mutex_init(&lock
);
204 qemu_cond_init(&mutex_cond
);
205 /* Hold the mutex while we start-up */
206 replay_locked
= true;
210 bool replay_mutex_locked(void)
212 return replay_locked
;
215 /* Ordering constraints, replay_lock must be taken before BQL */
216 void replay_mutex_lock(void)
218 if (replay_mode
!= REPLAY_MODE_NONE
) {
220 g_assert(!bql_locked());
221 g_assert(!replay_mutex_locked());
222 qemu_mutex_lock(&lock
);
224 while (id
!= mutex_head
) {
225 qemu_cond_wait(&mutex_cond
, &lock
);
227 replay_locked
= true;
228 qemu_mutex_unlock(&lock
);
232 void replay_mutex_unlock(void)
234 if (replay_mode
!= REPLAY_MODE_NONE
) {
235 g_assert(replay_mutex_locked());
236 qemu_mutex_lock(&lock
);
238 replay_locked
= false;
239 qemu_cond_broadcast(&mutex_cond
);
240 qemu_mutex_unlock(&lock
);
244 void replay_advance_current_icount(uint64_t current_icount
)
246 int diff
= (int)(current_icount
- replay_state
.current_icount
);
248 /* Time can only go forward */
251 if (replay_mode
== REPLAY_MODE_RECORD
) {
253 replay_put_event(EVENT_INSTRUCTION
);
254 replay_put_dword(diff
);
255 replay_state
.current_icount
+= diff
;
257 } else if (replay_mode
== REPLAY_MODE_PLAY
) {
259 replay_state
.instruction_count
-= diff
;
260 replay_state
.current_icount
+= diff
;
261 if (replay_state
.instruction_count
== 0) {
262 assert(replay_state
.data_kind
== EVENT_INSTRUCTION
);
263 replay_finish_event();
264 /* Wake up iothread. This is required because
265 timers will not expire until clock counters
266 will be read from the log. */
270 /* Execution reached the break step */
271 if (replay_break_icount
== replay_state
.current_icount
) {
272 /* Cannot make callback directly from the vCPU thread */
273 timer_mod_ns(replay_break_timer
,
274 qemu_clock_get_ns(QEMU_CLOCK_REALTIME
));
279 /*! Saves cached instructions. */
280 void replay_save_instructions(void)
282 if (replay_file
&& replay_mode
== REPLAY_MODE_RECORD
) {
283 g_assert(replay_mutex_locked());
284 replay_advance_current_icount(replay_get_current_icount());