]> Git Repo - qemu.git/blame - replay/replay.c
replay: initialization and deinitialization
[qemu.git] / replay / replay.c
CommitLineData
d73abd6d
PD
1/*
2 * replay.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
26bc60ac 12#include "qemu-common.h"
d73abd6d 13#include "sysemu/replay.h"
26bc60ac
PD
14#include "replay-internal.h"
15#include "qemu/timer.h"
8b427044 16#include "qemu/main-loop.h"
b60c48a7 17#include "sysemu/sysemu.h"
7615936e
PD
18#include "qemu/error-report.h"
19
20/* Current version of the replay mechanism.
21 Increase it when file format changes. */
22#define REPLAY_VERSION 0xe02002
23/* Size of replay log header */
24#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
d73abd6d
PD
25
26ReplayMode replay_mode = REPLAY_MODE_NONE;
26bc60ac 27
7615936e
PD
28/* Name of replay file */
29static char *replay_filename;
26bc60ac
PD
30ReplayState replay_state;
31
32bool replay_next_event_is(int event)
33{
34 bool res = false;
35
36 /* nothing to skip - not all instructions used */
37 if (replay_state.instructions_count != 0) {
38 assert(replay_data_kind == EVENT_INSTRUCTION);
39 return event == EVENT_INSTRUCTION;
40 }
41
42 while (true) {
43 if (event == replay_data_kind) {
44 res = true;
45 }
46 switch (replay_data_kind) {
b60c48a7
PD
47 case EVENT_SHUTDOWN:
48 replay_finish_event();
49 qemu_system_shutdown_request();
50 break;
26bc60ac
PD
51 default:
52 /* clock, time_t, checkpoint and other events */
53 return res;
54 }
55 }
56 return res;
57}
58
59uint64_t replay_get_current_step(void)
60{
61 return cpu_get_icount_raw();
62}
8b427044
PD
63
64int replay_get_instructions(void)
65{
66 int res = 0;
67 replay_mutex_lock();
68 if (replay_next_event_is(EVENT_INSTRUCTION)) {
69 res = replay_state.instructions_count;
70 }
71 replay_mutex_unlock();
72 return res;
73}
74
75void replay_account_executed_instructions(void)
76{
77 if (replay_mode == REPLAY_MODE_PLAY) {
78 replay_mutex_lock();
79 if (replay_state.instructions_count > 0) {
80 int count = (int)(replay_get_current_step()
81 - replay_state.current_step);
82 replay_state.instructions_count -= count;
83 replay_state.current_step += count;
84 if (replay_state.instructions_count == 0) {
85 assert(replay_data_kind == EVENT_INSTRUCTION);
86 replay_finish_event();
87 /* Wake up iothread. This is required because
88 timers will not expire until clock counters
89 will be read from the log. */
90 qemu_notify_event();
91 }
92 }
93 replay_mutex_unlock();
94 }
95}
6f060969
PD
96
97bool replay_exception(void)
98{
99 if (replay_mode == REPLAY_MODE_RECORD) {
100 replay_save_instructions();
101 replay_mutex_lock();
102 replay_put_event(EVENT_EXCEPTION);
103 replay_mutex_unlock();
104 return true;
105 } else if (replay_mode == REPLAY_MODE_PLAY) {
106 bool res = replay_has_exception();
107 if (res) {
108 replay_mutex_lock();
109 replay_finish_event();
110 replay_mutex_unlock();
111 }
112 return res;
113 }
114
115 return true;
116}
117
118bool replay_has_exception(void)
119{
120 bool res = false;
121 if (replay_mode == REPLAY_MODE_PLAY) {
122 replay_account_executed_instructions();
123 replay_mutex_lock();
124 res = replay_next_event_is(EVENT_EXCEPTION);
125 replay_mutex_unlock();
126 }
127
128 return res;
129}
130
131bool replay_interrupt(void)
132{
133 if (replay_mode == REPLAY_MODE_RECORD) {
134 replay_save_instructions();
135 replay_mutex_lock();
136 replay_put_event(EVENT_INTERRUPT);
137 replay_mutex_unlock();
138 return true;
139 } else if (replay_mode == REPLAY_MODE_PLAY) {
140 bool res = replay_has_interrupt();
141 if (res) {
142 replay_mutex_lock();
143 replay_finish_event();
144 replay_mutex_unlock();
145 }
146 return res;
147 }
148
149 return true;
150}
151
152bool replay_has_interrupt(void)
153{
154 bool res = false;
155 if (replay_mode == REPLAY_MODE_PLAY) {
156 replay_account_executed_instructions();
157 replay_mutex_lock();
158 res = replay_next_event_is(EVENT_INTERRUPT);
159 replay_mutex_unlock();
160 }
161 return res;
162}
b60c48a7
PD
163
164void replay_shutdown_request(void)
165{
166 if (replay_mode == REPLAY_MODE_RECORD) {
167 replay_mutex_lock();
168 replay_put_event(EVENT_SHUTDOWN);
169 replay_mutex_unlock();
170 }
171}
8bd7f71d
PD
172
173bool replay_checkpoint(ReplayCheckpoint checkpoint)
174{
175 bool res = false;
176 assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST);
177 replay_save_instructions();
178
179 if (!replay_file) {
180 return true;
181 }
182
183 replay_mutex_lock();
184
185 if (replay_mode == REPLAY_MODE_PLAY) {
186 if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) {
187 replay_finish_event();
188 } else if (replay_data_kind != EVENT_ASYNC) {
189 res = false;
190 goto out;
191 }
192 replay_read_events(checkpoint);
193 /* replay_read_events may leave some unread events.
194 Return false if not all of the events associated with
195 checkpoint were processed */
196 res = replay_data_kind != EVENT_ASYNC;
197 } else if (replay_mode == REPLAY_MODE_RECORD) {
198 replay_put_event(EVENT_CHECKPOINT + checkpoint);
199 replay_save_events(checkpoint);
200 res = true;
201 }
202out:
203 replay_mutex_unlock();
204 return res;
205}
7615936e
PD
206
207static void replay_enable(const char *fname, int mode)
208{
209 const char *fmode = NULL;
210 assert(!replay_file);
211
212 switch (mode) {
213 case REPLAY_MODE_RECORD:
214 fmode = "wb";
215 break;
216 case REPLAY_MODE_PLAY:
217 fmode = "rb";
218 break;
219 default:
220 fprintf(stderr, "Replay: internal error: invalid replay mode\n");
221 exit(1);
222 }
223
224 atexit(replay_finish);
225
226 replay_mutex_init();
227
228 replay_file = fopen(fname, fmode);
229 if (replay_file == NULL) {
230 fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno));
231 exit(1);
232 }
233
234 replay_filename = g_strdup(fname);
235
236 replay_mode = mode;
237 replay_data_kind = -1;
238 replay_state.instructions_count = 0;
239 replay_state.current_step = 0;
240
241 /* skip file header for RECORD and check it for PLAY */
242 if (replay_mode == REPLAY_MODE_RECORD) {
243 fseek(replay_file, HEADER_SIZE, SEEK_SET);
244 } else if (replay_mode == REPLAY_MODE_PLAY) {
245 unsigned int version = replay_get_dword();
246 if (version != REPLAY_VERSION) {
247 fprintf(stderr, "Replay: invalid input log file version\n");
248 exit(1);
249 }
250 /* go to the beginning */
251 fseek(replay_file, HEADER_SIZE, SEEK_SET);
252 replay_fetch_data_kind();
253 }
254
255 replay_init_events();
256}
257
258void replay_configure(QemuOpts *opts)
259{
260 const char *fname;
261 const char *rr;
262 ReplayMode mode = REPLAY_MODE_NONE;
263
264 rr = qemu_opt_get(opts, "rr");
265 if (!rr) {
266 /* Just enabling icount */
267 return;
268 } else if (!strcmp(rr, "record")) {
269 mode = REPLAY_MODE_RECORD;
270 } else if (!strcmp(rr, "replay")) {
271 mode = REPLAY_MODE_PLAY;
272 } else {
273 error_report("Invalid icount rr option: %s", rr);
274 exit(1);
275 }
276
277 fname = qemu_opt_get(opts, "rrfile");
278 if (!fname) {
279 error_report("File name not specified for replay");
280 exit(1);
281 }
282
283 replay_enable(fname, mode);
284}
285
286void replay_start(void)
287{
288 if (replay_mode == REPLAY_MODE_NONE) {
289 return;
290 }
291
292 /* Timer for snapshotting will be set up here. */
293
294 replay_enable_events();
295}
296
297void replay_finish(void)
298{
299 if (replay_mode == REPLAY_MODE_NONE) {
300 return;
301 }
302
303 replay_save_instructions();
304
305 /* finalize the file */
306 if (replay_file) {
307 if (replay_mode == REPLAY_MODE_RECORD) {
308 /* write end event */
309 replay_put_event(EVENT_END);
310
311 /* write header */
312 fseek(replay_file, 0, SEEK_SET);
313 replay_put_dword(REPLAY_VERSION);
314 }
315
316 fclose(replay_file);
317 replay_file = NULL;
318 }
319 if (replay_filename) {
320 g_free(replay_filename);
321 replay_filename = NULL;
322 }
323
324 replay_finish_events();
325 replay_mutex_destroy();
326}
This page took 0.055655 seconds and 4 git commands to generate.