]> git.proxmox.com Git - mirror_qemu.git/blame - replay/replay-internal.c
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
[mirror_qemu.git] / replay / replay-internal.c
CommitLineData
c92079f4
PD
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
d38ea87a 12#include "qemu/osdep.h"
c92079f4 13#include "qemu-common.h"
26bc60ac 14#include "sysemu/replay.h"
c92079f4
PD
15#include "replay-internal.h"
16#include "qemu/error-report.h"
17#include "sysemu/sysemu.h"
18
c16861ef 19/* Mutex to protect reading and writing events to the log.
f186d64d 20 data_kind and has_unread_data are also protected
c16861ef
PD
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
c92079f4 26/* File for replay writing */
6dc0f529 27static bool write_error;
c92079f4
PD
28FILE *replay_file;
29
6dc0f529
PD
30static void replay_write_error(void)
31{
32 if (!write_error) {
33 error_report("replay write error");
34 write_error = true;
35 }
36}
37
c92079f4
PD
38void replay_put_byte(uint8_t byte)
39{
40 if (replay_file) {
6dc0f529
PD
41 if (putc(byte, replay_file) == EOF) {
42 replay_write_error();
43 }
c92079f4
PD
44 }
45}
46
47void replay_put_event(uint8_t event)
48{
26bc60ac 49 assert(event < EVENT_COUNT);
c92079f4
PD
50 replay_put_byte(event);
51}
52
53
54void replay_put_word(uint16_t word)
55{
56 replay_put_byte(word >> 8);
57 replay_put_byte(word);
58}
59
60void replay_put_dword(uint32_t dword)
61{
62 replay_put_word(dword >> 16);
63 replay_put_word(dword);
64}
65
66void replay_put_qword(int64_t qword)
67{
68 replay_put_dword(qword >> 32);
69 replay_put_dword(qword);
70}
71
72void replay_put_array(const uint8_t *buf, size_t size)
73{
74 if (replay_file) {
75 replay_put_dword(size);
6dc0f529
PD
76 if (fwrite(buf, 1, size, replay_file) != size) {
77 replay_write_error();
78 }
c92079f4
PD
79 }
80}
81
82uint8_t replay_get_byte(void)
83{
84 uint8_t byte = 0;
85 if (replay_file) {
86 byte = getc(replay_file);
87 }
88 return byte;
89}
90
91uint16_t replay_get_word(void)
92{
93 uint16_t word = 0;
94 if (replay_file) {
95 word = replay_get_byte();
96 word = (word << 8) + replay_get_byte();
97 }
98
99 return word;
100}
101
102uint32_t replay_get_dword(void)
103{
104 uint32_t dword = 0;
105 if (replay_file) {
106 dword = replay_get_word();
107 dword = (dword << 16) + replay_get_word();
108 }
109
110 return dword;
111}
112
113int64_t replay_get_qword(void)
114{
115 int64_t qword = 0;
116 if (replay_file) {
117 qword = replay_get_dword();
118 qword = (qword << 32) + replay_get_dword();
119 }
120
121 return qword;
122}
123
124void replay_get_array(uint8_t *buf, size_t *size)
125{
126 if (replay_file) {
127 *size = replay_get_dword();
128 if (fread(buf, 1, *size, replay_file) != *size) {
129 error_report("replay read error");
130 }
131 }
132}
133
134void replay_get_array_alloc(uint8_t **buf, size_t *size)
135{
136 if (replay_file) {
137 *size = replay_get_dword();
138 *buf = g_malloc(*size);
139 if (fread(*buf, 1, *size, replay_file) != *size) {
140 error_report("replay read error");
141 }
142 }
143}
144
145void replay_check_error(void)
146{
147 if (replay_file) {
148 if (feof(replay_file)) {
149 error_report("replay file is over");
150 qemu_system_vmstop_request_prepare();
151 qemu_system_vmstop_request(RUN_STATE_PAUSED);
152 } else if (ferror(replay_file)) {
153 error_report("replay file is over or something goes wrong");
154 qemu_system_vmstop_request_prepare();
155 qemu_system_vmstop_request(RUN_STATE_INTERNAL_ERROR);
156 }
157 }
158}
159
160void replay_fetch_data_kind(void)
161{
162 if (replay_file) {
f186d64d
PD
163 if (!replay_state.has_unread_data) {
164 replay_state.data_kind = replay_get_byte();
165 if (replay_state.data_kind == EVENT_INSTRUCTION) {
26bc60ac
PD
166 replay_state.instructions_count = replay_get_dword();
167 }
c92079f4 168 replay_check_error();
f186d64d
PD
169 replay_state.has_unread_data = 1;
170 if (replay_state.data_kind >= EVENT_COUNT) {
171 error_report("Replay: unknown event kind %d",
172 replay_state.data_kind);
26bc60ac
PD
173 exit(1);
174 }
c92079f4
PD
175 }
176 }
177}
178
179void replay_finish_event(void)
180{
f186d64d 181 replay_state.has_unread_data = 0;
c92079f4
PD
182 replay_fetch_data_kind();
183}
c16861ef 184
180d30be
AB
185static __thread bool replay_locked;
186
c16861ef
PD
187void replay_mutex_init(void)
188{
189 qemu_mutex_init(&lock);
d759c951
AB
190 /* Hold the mutex while we start-up */
191 qemu_mutex_lock(&lock);
192 replay_locked = true;
c16861ef
PD
193}
194
a36544d3 195bool replay_mutex_locked(void)
180d30be
AB
196{
197 return replay_locked;
198}
199
d759c951 200/* Ordering constraints, replay_lock must be taken before BQL */
c16861ef
PD
201void replay_mutex_lock(void)
202{
d759c951
AB
203 if (replay_mode != REPLAY_MODE_NONE) {
204 g_assert(!qemu_mutex_iothread_locked());
205 g_assert(!replay_mutex_locked());
206 qemu_mutex_lock(&lock);
207 replay_locked = true;
208 }
c16861ef
PD
209}
210
211void replay_mutex_unlock(void)
212{
d759c951
AB
213 if (replay_mode != REPLAY_MODE_NONE) {
214 g_assert(replay_mutex_locked());
215 replay_locked = false;
216 qemu_mutex_unlock(&lock);
217 }
c16861ef 218}
26bc60ac 219
74c0b816
PB
220void replay_advance_current_step(uint64_t current_step)
221{
222 int diff = (int)(replay_get_current_step() - replay_state.current_step);
223
224 /* Time can only go forward */
225 assert(diff >= 0);
226
227 if (diff > 0) {
228 replay_put_event(EVENT_INSTRUCTION);
229 replay_put_dword(diff);
230 replay_state.current_step += diff;
231 }
232}
233
26bc60ac
PD
234/*! Saves cached instructions. */
235void replay_save_instructions(void)
236{
237 if (replay_file && replay_mode == REPLAY_MODE_RECORD) {
d759c951 238 g_assert(replay_mutex_locked());
74c0b816 239 replay_advance_current_step(replay_get_current_step());
26bc60ac
PD
240 }
241}