1c0c071d0SPavel Dovgalyuk /*
2c0c071d0SPavel Dovgalyuk * replay-events.c
3c0c071d0SPavel Dovgalyuk *
4c0c071d0SPavel Dovgalyuk * Copyright (c) 2010-2015 Institute for System Programming
5c0c071d0SPavel Dovgalyuk * of the Russian Academy of Sciences.
6c0c071d0SPavel Dovgalyuk *
7c0c071d0SPavel Dovgalyuk * This work is licensed under the terms of the GNU GPL, version 2 or later.
8c0c071d0SPavel Dovgalyuk * See the COPYING file in the top-level directory.
9c0c071d0SPavel Dovgalyuk *
10c0c071d0SPavel Dovgalyuk */
11c0c071d0SPavel Dovgalyuk
12d38ea87aSPeter Maydell #include "qemu/osdep.h"
13c0c071d0SPavel Dovgalyuk #include "qemu/error-report.h"
14c0c071d0SPavel Dovgalyuk #include "sysemu/replay.h"
15c0c071d0SPavel Dovgalyuk #include "replay-internal.h"
168a354bd9SPavel Dovgalyuk #include "block/aio.h"
17ee312992SPavel Dovgalyuk #include "ui/input.h"
1846967b1aSPavel Dovgalyuk #include "hw/core/cpu.h"
19c0c071d0SPavel Dovgalyuk
20c0c071d0SPavel Dovgalyuk typedef struct Event {
21c0c071d0SPavel Dovgalyuk ReplayAsyncEventKind event_kind;
22c0c071d0SPavel Dovgalyuk void *opaque;
23c0c071d0SPavel Dovgalyuk void *opaque2;
24c0c071d0SPavel Dovgalyuk uint64_t id;
25c0c071d0SPavel Dovgalyuk
26c0c071d0SPavel Dovgalyuk QTAILQ_ENTRY(Event) events;
27c0c071d0SPavel Dovgalyuk } Event;
28c0c071d0SPavel Dovgalyuk
29c0c071d0SPavel Dovgalyuk static QTAILQ_HEAD(, Event) events_list = QTAILQ_HEAD_INITIALIZER(events_list);
30c0c071d0SPavel Dovgalyuk static bool events_enabled;
31c0c071d0SPavel Dovgalyuk
32c0c071d0SPavel Dovgalyuk /* Functions */
33c0c071d0SPavel Dovgalyuk
replay_run_event(Event * event)34c0c071d0SPavel Dovgalyuk static void replay_run_event(Event *event)
35c0c071d0SPavel Dovgalyuk {
36c0c071d0SPavel Dovgalyuk switch (event->event_kind) {
378a354bd9SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH:
388a354bd9SPavel Dovgalyuk aio_bh_call(event->opaque);
398a354bd9SPavel Dovgalyuk break;
40e4ec5ad4SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH_ONESHOT:
41e4ec5ad4SPavel Dovgalyuk ((QEMUBHFunc *)event->opaque)(event->opaque2);
42e4ec5ad4SPavel Dovgalyuk break;
43ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT:
44ee312992SPavel Dovgalyuk qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque);
45ee312992SPavel Dovgalyuk qapi_free_InputEvent((InputEvent *)event->opaque);
46ee312992SPavel Dovgalyuk break;
47ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT_SYNC:
48ee312992SPavel Dovgalyuk qemu_input_event_sync_impl();
49ee312992SPavel Dovgalyuk break;
5033577b47SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_CHAR_READ:
5133577b47SPavel Dovgalyuk replay_event_char_read_run(event->opaque);
5233577b47SPavel Dovgalyuk break;
5363785678SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BLOCK:
5463785678SPavel Dovgalyuk aio_bh_call(event->opaque);
5563785678SPavel Dovgalyuk break;
56646c5478SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_NET:
57646c5478SPavel Dovgalyuk replay_event_net_run(event->opaque);
58646c5478SPavel Dovgalyuk break;
59c0c071d0SPavel Dovgalyuk default:
60c0c071d0SPavel Dovgalyuk error_report("Replay: invalid async event ID (%d) in the queue",
61c0c071d0SPavel Dovgalyuk event->event_kind);
62c0c071d0SPavel Dovgalyuk exit(1);
63c0c071d0SPavel Dovgalyuk break;
64c0c071d0SPavel Dovgalyuk }
65c0c071d0SPavel Dovgalyuk }
66c0c071d0SPavel Dovgalyuk
replay_enable_events(void)67c0c071d0SPavel Dovgalyuk void replay_enable_events(void)
68c0c071d0SPavel Dovgalyuk {
691652e0c3SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_NONE) {
70c0c071d0SPavel Dovgalyuk events_enabled = true;
71c0c071d0SPavel Dovgalyuk }
721652e0c3SPavel Dovgalyuk }
73c0c071d0SPavel Dovgalyuk
replay_has_events(void)74c0c071d0SPavel Dovgalyuk bool replay_has_events(void)
75c0c071d0SPavel Dovgalyuk {
76c0c071d0SPavel Dovgalyuk return !QTAILQ_EMPTY(&events_list);
77c0c071d0SPavel Dovgalyuk }
78c0c071d0SPavel Dovgalyuk
replay_flush_events(void)79c0c071d0SPavel Dovgalyuk void replay_flush_events(void)
80c0c071d0SPavel Dovgalyuk {
81f9a9fb65SPavel Dovgalyuk if (replay_mode == REPLAY_MODE_NONE) {
82f9a9fb65SPavel Dovgalyuk return;
83f9a9fb65SPavel Dovgalyuk }
84f9a9fb65SPavel Dovgalyuk
85d759c951SAlex Bennée g_assert(replay_mutex_locked());
86d759c951SAlex Bennée
87c0c071d0SPavel Dovgalyuk while (!QTAILQ_EMPTY(&events_list)) {
88c0c071d0SPavel Dovgalyuk Event *event = QTAILQ_FIRST(&events_list);
89c0c071d0SPavel Dovgalyuk replay_run_event(event);
90c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events);
91c0c071d0SPavel Dovgalyuk g_free(event);
92c0c071d0SPavel Dovgalyuk }
93c0c071d0SPavel Dovgalyuk }
94c0c071d0SPavel Dovgalyuk
95c0c071d0SPavel Dovgalyuk /*! Adds specified async event to the queue */
replay_add_event(ReplayAsyncEventKind event_kind,void * opaque,void * opaque2,uint64_t id)9633577b47SPavel Dovgalyuk void replay_add_event(ReplayAsyncEventKind event_kind,
97c0c071d0SPavel Dovgalyuk void *opaque,
98c0c071d0SPavel Dovgalyuk void *opaque2, uint64_t id)
99c0c071d0SPavel Dovgalyuk {
100c0c071d0SPavel Dovgalyuk assert(event_kind < REPLAY_ASYNC_COUNT);
101c0c071d0SPavel Dovgalyuk
102c0c071d0SPavel Dovgalyuk if (!replay_file || replay_mode == REPLAY_MODE_NONE
103c0c071d0SPavel Dovgalyuk || !events_enabled) {
104c0c071d0SPavel Dovgalyuk Event e;
105c0c071d0SPavel Dovgalyuk e.event_kind = event_kind;
106c0c071d0SPavel Dovgalyuk e.opaque = opaque;
107c0c071d0SPavel Dovgalyuk e.opaque2 = opaque2;
108c0c071d0SPavel Dovgalyuk e.id = id;
109c0c071d0SPavel Dovgalyuk replay_run_event(&e);
110c0c071d0SPavel Dovgalyuk return;
111c0c071d0SPavel Dovgalyuk }
112c0c071d0SPavel Dovgalyuk
113b21e2380SMarkus Armbruster Event *event = g_new0(Event, 1);
114c0c071d0SPavel Dovgalyuk event->event_kind = event_kind;
115c0c071d0SPavel Dovgalyuk event->opaque = opaque;
116c0c071d0SPavel Dovgalyuk event->opaque2 = opaque2;
117c0c071d0SPavel Dovgalyuk event->id = id;
118c0c071d0SPavel Dovgalyuk
119d759c951SAlex Bennée g_assert(replay_mutex_locked());
120c0c071d0SPavel Dovgalyuk QTAILQ_INSERT_TAIL(&events_list, event, events);
12146967b1aSPavel Dovgalyuk qemu_cpu_kick(first_cpu);
122c0c071d0SPavel Dovgalyuk }
1238a354bd9SPavel Dovgalyuk
replay_bh_schedule_event(QEMUBH * bh)1248a354bd9SPavel Dovgalyuk void replay_bh_schedule_event(QEMUBH *bh)
1258a354bd9SPavel Dovgalyuk {
1261652e0c3SPavel Dovgalyuk if (events_enabled) {
12713f26713SPavel Dovgalyuk uint64_t id = replay_get_current_icount();
1288a354bd9SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id);
1298a354bd9SPavel Dovgalyuk } else {
1308a354bd9SPavel Dovgalyuk qemu_bh_schedule(bh);
1318a354bd9SPavel Dovgalyuk }
1328a354bd9SPavel Dovgalyuk }
133c0c071d0SPavel Dovgalyuk
replay_bh_schedule_oneshot_event(AioContext * ctx,QEMUBHFunc * cb,void * opaque)134e4ec5ad4SPavel Dovgalyuk void replay_bh_schedule_oneshot_event(AioContext *ctx,
135e4ec5ad4SPavel Dovgalyuk QEMUBHFunc *cb, void *opaque)
136e4ec5ad4SPavel Dovgalyuk {
137e4ec5ad4SPavel Dovgalyuk if (events_enabled) {
138e4ec5ad4SPavel Dovgalyuk uint64_t id = replay_get_current_icount();
139e4ec5ad4SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_BH_ONESHOT, cb, opaque, id);
140e4ec5ad4SPavel Dovgalyuk } else {
141e4ec5ad4SPavel Dovgalyuk aio_bh_schedule_oneshot(ctx, cb, opaque);
142e4ec5ad4SPavel Dovgalyuk }
143e4ec5ad4SPavel Dovgalyuk }
144e4ec5ad4SPavel Dovgalyuk
replay_add_input_event(struct InputEvent * event)145ee312992SPavel Dovgalyuk void replay_add_input_event(struct InputEvent *event)
146ee312992SPavel Dovgalyuk {
147ee312992SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0);
148ee312992SPavel Dovgalyuk }
149ee312992SPavel Dovgalyuk
replay_add_input_sync_event(void)150ee312992SPavel Dovgalyuk void replay_add_input_sync_event(void)
151ee312992SPavel Dovgalyuk {
152ee312992SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0);
153ee312992SPavel Dovgalyuk }
154ee312992SPavel Dovgalyuk
replay_block_event(QEMUBH * bh,uint64_t id)15563785678SPavel Dovgalyuk void replay_block_event(QEMUBH *bh, uint64_t id)
15663785678SPavel Dovgalyuk {
1571652e0c3SPavel Dovgalyuk if (events_enabled) {
15863785678SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_BLOCK, bh, NULL, id);
15963785678SPavel Dovgalyuk } else {
16063785678SPavel Dovgalyuk qemu_bh_schedule(bh);
16163785678SPavel Dovgalyuk }
16263785678SPavel Dovgalyuk }
16363785678SPavel Dovgalyuk
replay_save_event(Event * event)16460618e2dSPavel Dovgalyuk static void replay_save_event(Event *event)
165c0c071d0SPavel Dovgalyuk {
166c0c071d0SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_PLAY) {
167c0c071d0SPavel Dovgalyuk /* put the event into the file */
168*3e21408bSPavel Dovgalyuk g_assert(event->event_kind < REPLAY_ASYNC_COUNT);
169*3e21408bSPavel Dovgalyuk replay_put_event(EVENT_ASYNC + event->event_kind);
170c0c071d0SPavel Dovgalyuk
171c0c071d0SPavel Dovgalyuk /* save event-specific data */
172c0c071d0SPavel Dovgalyuk switch (event->event_kind) {
1738a354bd9SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH:
174e4ec5ad4SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH_ONESHOT:
1758a354bd9SPavel Dovgalyuk replay_put_qword(event->id);
1768a354bd9SPavel Dovgalyuk break;
177ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT:
178ee312992SPavel Dovgalyuk replay_save_input_event(event->opaque);
179ee312992SPavel Dovgalyuk break;
180ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT_SYNC:
181ee312992SPavel Dovgalyuk break;
18233577b47SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_CHAR_READ:
18333577b47SPavel Dovgalyuk replay_event_char_read_save(event->opaque);
18433577b47SPavel Dovgalyuk break;
18563785678SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BLOCK:
18663785678SPavel Dovgalyuk replay_put_qword(event->id);
18763785678SPavel Dovgalyuk break;
188646c5478SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_NET:
189646c5478SPavel Dovgalyuk replay_event_net_save(event->opaque);
190646c5478SPavel Dovgalyuk break;
191c0c071d0SPavel Dovgalyuk default:
19295b4aed5SPavel Dovgalyuk error_report("Unknown ID %" PRId64 " of replay event", event->id);
193c0c071d0SPavel Dovgalyuk exit(1);
194c0c071d0SPavel Dovgalyuk }
195c0c071d0SPavel Dovgalyuk }
196c0c071d0SPavel Dovgalyuk }
197c0c071d0SPavel Dovgalyuk
198c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */
replay_save_events(void)19960618e2dSPavel Dovgalyuk void replay_save_events(void)
200c0c071d0SPavel Dovgalyuk {
201d759c951SAlex Bennée g_assert(replay_mutex_locked());
202c0c071d0SPavel Dovgalyuk while (!QTAILQ_EMPTY(&events_list)) {
203c0c071d0SPavel Dovgalyuk Event *event = QTAILQ_FIRST(&events_list);
20460618e2dSPavel Dovgalyuk replay_save_event(event);
205c0c071d0SPavel Dovgalyuk replay_run_event(event);
206c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events);
207c0c071d0SPavel Dovgalyuk g_free(event);
208c0c071d0SPavel Dovgalyuk }
209c0c071d0SPavel Dovgalyuk }
210c0c071d0SPavel Dovgalyuk
replay_read_event(void)21160618e2dSPavel Dovgalyuk static Event *replay_read_event(void)
212c0c071d0SPavel Dovgalyuk {
213c0c071d0SPavel Dovgalyuk Event *event;
214*3e21408bSPavel Dovgalyuk ReplayAsyncEventKind event_kind = replay_state.data_kind - EVENT_ASYNC;
215c0c071d0SPavel Dovgalyuk
216c0c071d0SPavel Dovgalyuk /* Events that has not to be in the queue */
217*3e21408bSPavel Dovgalyuk switch (event_kind) {
2188a354bd9SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH:
219e4ec5ad4SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BH_ONESHOT:
2200b30dc01SPavel Dovgalyuk if (replay_state.read_event_id == -1) {
2210b30dc01SPavel Dovgalyuk replay_state.read_event_id = replay_get_qword();
2228a354bd9SPavel Dovgalyuk }
2238a354bd9SPavel Dovgalyuk break;
224ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT:
225b21e2380SMarkus Armbruster event = g_new0(Event, 1);
226*3e21408bSPavel Dovgalyuk event->event_kind = event_kind;
227ee312992SPavel Dovgalyuk event->opaque = replay_read_input_event();
228ee312992SPavel Dovgalyuk return event;
229ee312992SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_INPUT_SYNC:
230b21e2380SMarkus Armbruster event = g_new0(Event, 1);
231*3e21408bSPavel Dovgalyuk event->event_kind = event_kind;
232ee312992SPavel Dovgalyuk event->opaque = 0;
233ee312992SPavel Dovgalyuk return event;
23433577b47SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_CHAR_READ:
235b21e2380SMarkus Armbruster event = g_new0(Event, 1);
236*3e21408bSPavel Dovgalyuk event->event_kind = event_kind;
23733577b47SPavel Dovgalyuk event->opaque = replay_event_char_read_load();
23833577b47SPavel Dovgalyuk return event;
23963785678SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_BLOCK:
2400b30dc01SPavel Dovgalyuk if (replay_state.read_event_id == -1) {
2410b30dc01SPavel Dovgalyuk replay_state.read_event_id = replay_get_qword();
24263785678SPavel Dovgalyuk }
24363785678SPavel Dovgalyuk break;
244646c5478SPavel Dovgalyuk case REPLAY_ASYNC_EVENT_NET:
245b21e2380SMarkus Armbruster event = g_new0(Event, 1);
246*3e21408bSPavel Dovgalyuk event->event_kind = event_kind;
247646c5478SPavel Dovgalyuk event->opaque = replay_event_net_load();
248646c5478SPavel Dovgalyuk return event;
249c0c071d0SPavel Dovgalyuk default:
250*3e21408bSPavel Dovgalyuk error_report("Unknown ID %d of replay event", event_kind);
251c0c071d0SPavel Dovgalyuk exit(1);
252c0c071d0SPavel Dovgalyuk break;
253c0c071d0SPavel Dovgalyuk }
254c0c071d0SPavel Dovgalyuk
255c0c071d0SPavel Dovgalyuk QTAILQ_FOREACH(event, &events_list, events) {
256*3e21408bSPavel Dovgalyuk if (event->event_kind == event_kind
2570b30dc01SPavel Dovgalyuk && (replay_state.read_event_id == -1
2580b30dc01SPavel Dovgalyuk || replay_state.read_event_id == event->id)) {
259c0c071d0SPavel Dovgalyuk break;
260c0c071d0SPavel Dovgalyuk }
261c0c071d0SPavel Dovgalyuk }
262c0c071d0SPavel Dovgalyuk
263c0c071d0SPavel Dovgalyuk if (event) {
264c0c071d0SPavel Dovgalyuk QTAILQ_REMOVE(&events_list, event, events);
265c0c071d0SPavel Dovgalyuk }
266c0c071d0SPavel Dovgalyuk
267c0c071d0SPavel Dovgalyuk return event;
268c0c071d0SPavel Dovgalyuk }
269c0c071d0SPavel Dovgalyuk
270c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */
replay_read_events(void)27160618e2dSPavel Dovgalyuk void replay_read_events(void)
272c0c071d0SPavel Dovgalyuk {
273d759c951SAlex Bennée g_assert(replay_mutex_locked());
274*3e21408bSPavel Dovgalyuk while (replay_state.data_kind >= EVENT_ASYNC
275*3e21408bSPavel Dovgalyuk && replay_state.data_kind <= EVENT_ASYNC_LAST) {
27660618e2dSPavel Dovgalyuk Event *event = replay_read_event();
277c0c071d0SPavel Dovgalyuk if (!event) {
278c0c071d0SPavel Dovgalyuk break;
279c0c071d0SPavel Dovgalyuk }
2801a96e3c1SPavel Dovgalyuk replay_finish_event();
281*3e21408bSPavel Dovgalyuk replay_state.read_event_id = -1;
282c0c071d0SPavel Dovgalyuk replay_run_event(event);
283c0c071d0SPavel Dovgalyuk
284c0c071d0SPavel Dovgalyuk g_free(event);
285c0c071d0SPavel Dovgalyuk }
286c0c071d0SPavel Dovgalyuk }
287c0c071d0SPavel Dovgalyuk
replay_init_events(void)288c0c071d0SPavel Dovgalyuk void replay_init_events(void)
289c0c071d0SPavel Dovgalyuk {
290*3e21408bSPavel Dovgalyuk replay_state.read_event_id = -1;
291c0c071d0SPavel Dovgalyuk }
292c0c071d0SPavel Dovgalyuk
replay_finish_events(void)293c0c071d0SPavel Dovgalyuk void replay_finish_events(void)
294c0c071d0SPavel Dovgalyuk {
295c0c071d0SPavel Dovgalyuk events_enabled = false;
296d873fe03SPavel Dovgalyuk replay_flush_events();
297c0c071d0SPavel Dovgalyuk }
298c0c071d0SPavel Dovgalyuk
replay_events_enabled(void)299c0c071d0SPavel Dovgalyuk bool replay_events_enabled(void)
300c0c071d0SPavel Dovgalyuk {
301c0c071d0SPavel Dovgalyuk return events_enabled;
302c0c071d0SPavel Dovgalyuk }
3036d0ceb80SPavel Dovgalyuk
blkreplay_next_id(void)3046d0ceb80SPavel Dovgalyuk uint64_t blkreplay_next_id(void)
3056d0ceb80SPavel Dovgalyuk {
3066d0ceb80SPavel Dovgalyuk if (replay_events_enabled()) {
3076d0ceb80SPavel Dovgalyuk return replay_state.block_request_id++;
3086d0ceb80SPavel Dovgalyuk }
3096d0ceb80SPavel Dovgalyuk return 0;
3106d0ceb80SPavel Dovgalyuk }
311