xref: /openbmc/qemu/replay/replay-events.c (revision d759c951f3287fad04210a52f2dc93f94cf58c7f)
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-common.h"
14c0c071d0SPavel Dovgalyuk #include "qemu/error-report.h"
15c0c071d0SPavel Dovgalyuk #include "sysemu/replay.h"
16c0c071d0SPavel Dovgalyuk #include "replay-internal.h"
178a354bd9SPavel Dovgalyuk #include "block/aio.h"
18ee312992SPavel Dovgalyuk #include "ui/input.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 unsigned int read_event_kind = -1;
31c0c071d0SPavel Dovgalyuk static uint64_t read_id = -1;
32c0c071d0SPavel Dovgalyuk static int read_checkpoint = -1;
33c0c071d0SPavel Dovgalyuk 
34c0c071d0SPavel Dovgalyuk static bool events_enabled;
35c0c071d0SPavel Dovgalyuk 
36c0c071d0SPavel Dovgalyuk /* Functions */
37c0c071d0SPavel Dovgalyuk 
38c0c071d0SPavel Dovgalyuk static void replay_run_event(Event *event)
39c0c071d0SPavel Dovgalyuk {
40c0c071d0SPavel Dovgalyuk     switch (event->event_kind) {
418a354bd9SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_BH:
428a354bd9SPavel Dovgalyuk         aio_bh_call(event->opaque);
438a354bd9SPavel Dovgalyuk         break;
44ee312992SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_INPUT:
45ee312992SPavel Dovgalyuk         qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque);
46ee312992SPavel Dovgalyuk         qapi_free_InputEvent((InputEvent *)event->opaque);
47ee312992SPavel Dovgalyuk         break;
48ee312992SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_INPUT_SYNC:
49ee312992SPavel Dovgalyuk         qemu_input_event_sync_impl();
50ee312992SPavel Dovgalyuk         break;
5133577b47SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_CHAR_READ:
5233577b47SPavel Dovgalyuk         replay_event_char_read_run(event->opaque);
5333577b47SPavel Dovgalyuk         break;
5463785678SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_BLOCK:
5563785678SPavel Dovgalyuk         aio_bh_call(event->opaque);
5663785678SPavel Dovgalyuk         break;
57646c5478SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_NET:
58646c5478SPavel Dovgalyuk         replay_event_net_run(event->opaque);
59646c5478SPavel Dovgalyuk         break;
60c0c071d0SPavel Dovgalyuk     default:
61c0c071d0SPavel Dovgalyuk         error_report("Replay: invalid async event ID (%d) in the queue",
62c0c071d0SPavel Dovgalyuk                     event->event_kind);
63c0c071d0SPavel Dovgalyuk         exit(1);
64c0c071d0SPavel Dovgalyuk         break;
65c0c071d0SPavel Dovgalyuk     }
66c0c071d0SPavel Dovgalyuk }
67c0c071d0SPavel Dovgalyuk 
68c0c071d0SPavel Dovgalyuk void replay_enable_events(void)
69c0c071d0SPavel Dovgalyuk {
701652e0c3SPavel Dovgalyuk     if (replay_mode != REPLAY_MODE_NONE) {
71c0c071d0SPavel Dovgalyuk         events_enabled = true;
72c0c071d0SPavel Dovgalyuk     }
731652e0c3SPavel Dovgalyuk }
74c0c071d0SPavel Dovgalyuk 
75c0c071d0SPavel Dovgalyuk bool replay_has_events(void)
76c0c071d0SPavel Dovgalyuk {
77c0c071d0SPavel Dovgalyuk     return !QTAILQ_EMPTY(&events_list);
78c0c071d0SPavel Dovgalyuk }
79c0c071d0SPavel Dovgalyuk 
80c0c071d0SPavel Dovgalyuk void replay_flush_events(void)
81c0c071d0SPavel Dovgalyuk {
82*d759c951SAlex Bennée     g_assert(replay_mutex_locked());
83*d759c951SAlex Bennée 
84c0c071d0SPavel Dovgalyuk     while (!QTAILQ_EMPTY(&events_list)) {
85c0c071d0SPavel Dovgalyuk         Event *event = QTAILQ_FIRST(&events_list);
86c0c071d0SPavel Dovgalyuk         replay_run_event(event);
87c0c071d0SPavel Dovgalyuk         QTAILQ_REMOVE(&events_list, event, events);
88c0c071d0SPavel Dovgalyuk         g_free(event);
89c0c071d0SPavel Dovgalyuk     }
90c0c071d0SPavel Dovgalyuk }
91c0c071d0SPavel Dovgalyuk 
92c0c071d0SPavel Dovgalyuk void replay_disable_events(void)
93c0c071d0SPavel Dovgalyuk {
94c0c071d0SPavel Dovgalyuk     if (replay_mode != REPLAY_MODE_NONE) {
95c0c071d0SPavel Dovgalyuk         events_enabled = false;
96c0c071d0SPavel Dovgalyuk         /* Flush events queue before waiting of completion */
97c0c071d0SPavel Dovgalyuk         replay_flush_events();
98c0c071d0SPavel Dovgalyuk     }
99c0c071d0SPavel Dovgalyuk }
100c0c071d0SPavel Dovgalyuk 
101c0c071d0SPavel Dovgalyuk void replay_clear_events(void)
102c0c071d0SPavel Dovgalyuk {
103*d759c951SAlex Bennée     g_assert(replay_mutex_locked());
104*d759c951SAlex Bennée 
105c0c071d0SPavel Dovgalyuk     while (!QTAILQ_EMPTY(&events_list)) {
106c0c071d0SPavel Dovgalyuk         Event *event = QTAILQ_FIRST(&events_list);
107c0c071d0SPavel Dovgalyuk         QTAILQ_REMOVE(&events_list, event, events);
108c0c071d0SPavel Dovgalyuk 
109c0c071d0SPavel Dovgalyuk         g_free(event);
110c0c071d0SPavel Dovgalyuk     }
111c0c071d0SPavel Dovgalyuk }
112c0c071d0SPavel Dovgalyuk 
113c0c071d0SPavel Dovgalyuk /*! Adds specified async event to the queue */
11433577b47SPavel Dovgalyuk void replay_add_event(ReplayAsyncEventKind event_kind,
115c0c071d0SPavel Dovgalyuk                       void *opaque,
116c0c071d0SPavel Dovgalyuk                       void *opaque2, uint64_t id)
117c0c071d0SPavel Dovgalyuk {
118c0c071d0SPavel Dovgalyuk     assert(event_kind < REPLAY_ASYNC_COUNT);
119c0c071d0SPavel Dovgalyuk 
120c0c071d0SPavel Dovgalyuk     if (!replay_file || replay_mode == REPLAY_MODE_NONE
121c0c071d0SPavel Dovgalyuk         || !events_enabled) {
122c0c071d0SPavel Dovgalyuk         Event e;
123c0c071d0SPavel Dovgalyuk         e.event_kind = event_kind;
124c0c071d0SPavel Dovgalyuk         e.opaque = opaque;
125c0c071d0SPavel Dovgalyuk         e.opaque2 = opaque2;
126c0c071d0SPavel Dovgalyuk         e.id = id;
127c0c071d0SPavel Dovgalyuk         replay_run_event(&e);
128c0c071d0SPavel Dovgalyuk         return;
129c0c071d0SPavel Dovgalyuk     }
130c0c071d0SPavel Dovgalyuk 
131c0c071d0SPavel Dovgalyuk     Event *event = g_malloc0(sizeof(Event));
132c0c071d0SPavel Dovgalyuk     event->event_kind = event_kind;
133c0c071d0SPavel Dovgalyuk     event->opaque = opaque;
134c0c071d0SPavel Dovgalyuk     event->opaque2 = opaque2;
135c0c071d0SPavel Dovgalyuk     event->id = id;
136c0c071d0SPavel Dovgalyuk 
137*d759c951SAlex Bennée     g_assert(replay_mutex_locked());
138c0c071d0SPavel Dovgalyuk     QTAILQ_INSERT_TAIL(&events_list, event, events);
139c0c071d0SPavel Dovgalyuk }
1408a354bd9SPavel Dovgalyuk 
1418a354bd9SPavel Dovgalyuk void replay_bh_schedule_event(QEMUBH *bh)
1428a354bd9SPavel Dovgalyuk {
1431652e0c3SPavel Dovgalyuk     if (events_enabled) {
1448a354bd9SPavel Dovgalyuk         uint64_t id = replay_get_current_step();
1458a354bd9SPavel Dovgalyuk         replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id);
1468a354bd9SPavel Dovgalyuk     } else {
1478a354bd9SPavel Dovgalyuk         qemu_bh_schedule(bh);
1488a354bd9SPavel Dovgalyuk     }
1498a354bd9SPavel Dovgalyuk }
150c0c071d0SPavel Dovgalyuk 
151ee312992SPavel Dovgalyuk void replay_add_input_event(struct InputEvent *event)
152ee312992SPavel Dovgalyuk {
153ee312992SPavel Dovgalyuk     replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0);
154ee312992SPavel Dovgalyuk }
155ee312992SPavel Dovgalyuk 
156ee312992SPavel Dovgalyuk void replay_add_input_sync_event(void)
157ee312992SPavel Dovgalyuk {
158ee312992SPavel Dovgalyuk     replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0);
159ee312992SPavel Dovgalyuk }
160ee312992SPavel Dovgalyuk 
16163785678SPavel Dovgalyuk void replay_block_event(QEMUBH *bh, uint64_t id)
16263785678SPavel Dovgalyuk {
1631652e0c3SPavel Dovgalyuk     if (events_enabled) {
16463785678SPavel Dovgalyuk         replay_add_event(REPLAY_ASYNC_EVENT_BLOCK, bh, NULL, id);
16563785678SPavel Dovgalyuk     } else {
16663785678SPavel Dovgalyuk         qemu_bh_schedule(bh);
16763785678SPavel Dovgalyuk     }
16863785678SPavel Dovgalyuk }
16963785678SPavel Dovgalyuk 
170c0c071d0SPavel Dovgalyuk static void replay_save_event(Event *event, int checkpoint)
171c0c071d0SPavel Dovgalyuk {
172c0c071d0SPavel Dovgalyuk     if (replay_mode != REPLAY_MODE_PLAY) {
173c0c071d0SPavel Dovgalyuk         /* put the event into the file */
174c0c071d0SPavel Dovgalyuk         replay_put_event(EVENT_ASYNC);
175c0c071d0SPavel Dovgalyuk         replay_put_byte(checkpoint);
176c0c071d0SPavel Dovgalyuk         replay_put_byte(event->event_kind);
177c0c071d0SPavel Dovgalyuk 
178c0c071d0SPavel Dovgalyuk         /* save event-specific data */
179c0c071d0SPavel Dovgalyuk         switch (event->event_kind) {
1808a354bd9SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_BH:
1818a354bd9SPavel Dovgalyuk             replay_put_qword(event->id);
1828a354bd9SPavel Dovgalyuk             break;
183ee312992SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_INPUT:
184ee312992SPavel Dovgalyuk             replay_save_input_event(event->opaque);
185ee312992SPavel Dovgalyuk             break;
186ee312992SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_INPUT_SYNC:
187ee312992SPavel Dovgalyuk             break;
18833577b47SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_CHAR_READ:
18933577b47SPavel Dovgalyuk             replay_event_char_read_save(event->opaque);
19033577b47SPavel Dovgalyuk             break;
19163785678SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_BLOCK:
19263785678SPavel Dovgalyuk             replay_put_qword(event->id);
19363785678SPavel Dovgalyuk             break;
194646c5478SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_NET:
195646c5478SPavel Dovgalyuk             replay_event_net_save(event->opaque);
196646c5478SPavel Dovgalyuk             break;
197c0c071d0SPavel Dovgalyuk         default:
19895b4aed5SPavel Dovgalyuk             error_report("Unknown ID %" PRId64 " of replay event", event->id);
199c0c071d0SPavel Dovgalyuk             exit(1);
200c0c071d0SPavel Dovgalyuk         }
201c0c071d0SPavel Dovgalyuk     }
202c0c071d0SPavel Dovgalyuk }
203c0c071d0SPavel Dovgalyuk 
204c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */
205c0c071d0SPavel Dovgalyuk void replay_save_events(int checkpoint)
206c0c071d0SPavel Dovgalyuk {
207*d759c951SAlex Bennée     g_assert(replay_mutex_locked());
208c0c071d0SPavel Dovgalyuk     while (!QTAILQ_EMPTY(&events_list)) {
209c0c071d0SPavel Dovgalyuk         Event *event = QTAILQ_FIRST(&events_list);
210c0c071d0SPavel Dovgalyuk         replay_save_event(event, checkpoint);
211c0c071d0SPavel Dovgalyuk         replay_run_event(event);
212c0c071d0SPavel Dovgalyuk         QTAILQ_REMOVE(&events_list, event, events);
213c0c071d0SPavel Dovgalyuk         g_free(event);
214c0c071d0SPavel Dovgalyuk     }
215c0c071d0SPavel Dovgalyuk }
216c0c071d0SPavel Dovgalyuk 
217c0c071d0SPavel Dovgalyuk static Event *replay_read_event(int checkpoint)
218c0c071d0SPavel Dovgalyuk {
219c0c071d0SPavel Dovgalyuk     Event *event;
220c0c071d0SPavel Dovgalyuk     if (read_event_kind == -1) {
221c0c071d0SPavel Dovgalyuk         read_checkpoint = replay_get_byte();
222c0c071d0SPavel Dovgalyuk         read_event_kind = replay_get_byte();
223c0c071d0SPavel Dovgalyuk         read_id = -1;
224c0c071d0SPavel Dovgalyuk         replay_check_error();
225c0c071d0SPavel Dovgalyuk     }
226c0c071d0SPavel Dovgalyuk 
227c0c071d0SPavel Dovgalyuk     if (checkpoint != read_checkpoint) {
228c0c071d0SPavel Dovgalyuk         return NULL;
229c0c071d0SPavel Dovgalyuk     }
230c0c071d0SPavel Dovgalyuk 
231c0c071d0SPavel Dovgalyuk     /* Events that has not to be in the queue */
232c0c071d0SPavel Dovgalyuk     switch (read_event_kind) {
2338a354bd9SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_BH:
2348a354bd9SPavel Dovgalyuk         if (read_id == -1) {
2358a354bd9SPavel Dovgalyuk             read_id = replay_get_qword();
2368a354bd9SPavel Dovgalyuk         }
2378a354bd9SPavel Dovgalyuk         break;
238ee312992SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_INPUT:
239ee312992SPavel Dovgalyuk         event = g_malloc0(sizeof(Event));
240ee312992SPavel Dovgalyuk         event->event_kind = read_event_kind;
241ee312992SPavel Dovgalyuk         event->opaque = replay_read_input_event();
242ee312992SPavel Dovgalyuk         return event;
243ee312992SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_INPUT_SYNC:
244ee312992SPavel Dovgalyuk         event = g_malloc0(sizeof(Event));
245ee312992SPavel Dovgalyuk         event->event_kind = read_event_kind;
246ee312992SPavel Dovgalyuk         event->opaque = 0;
247ee312992SPavel Dovgalyuk         return event;
24833577b47SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_CHAR_READ:
24933577b47SPavel Dovgalyuk         event = g_malloc0(sizeof(Event));
25033577b47SPavel Dovgalyuk         event->event_kind = read_event_kind;
25133577b47SPavel Dovgalyuk         event->opaque = replay_event_char_read_load();
25233577b47SPavel Dovgalyuk         return event;
25363785678SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_BLOCK:
25463785678SPavel Dovgalyuk         if (read_id == -1) {
25563785678SPavel Dovgalyuk             read_id = replay_get_qword();
25663785678SPavel Dovgalyuk         }
25763785678SPavel Dovgalyuk         break;
258646c5478SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_NET:
259646c5478SPavel Dovgalyuk         event = g_malloc0(sizeof(Event));
260646c5478SPavel Dovgalyuk         event->event_kind = read_event_kind;
261646c5478SPavel Dovgalyuk         event->opaque = replay_event_net_load();
262646c5478SPavel Dovgalyuk         return event;
263c0c071d0SPavel Dovgalyuk     default:
264c0c071d0SPavel Dovgalyuk         error_report("Unknown ID %d of replay event", read_event_kind);
265c0c071d0SPavel Dovgalyuk         exit(1);
266c0c071d0SPavel Dovgalyuk         break;
267c0c071d0SPavel Dovgalyuk     }
268c0c071d0SPavel Dovgalyuk 
269c0c071d0SPavel Dovgalyuk     QTAILQ_FOREACH(event, &events_list, events) {
270c0c071d0SPavel Dovgalyuk         if (event->event_kind == read_event_kind
271c0c071d0SPavel Dovgalyuk             && (read_id == -1 || read_id == event->id)) {
272c0c071d0SPavel Dovgalyuk             break;
273c0c071d0SPavel Dovgalyuk         }
274c0c071d0SPavel Dovgalyuk     }
275c0c071d0SPavel Dovgalyuk 
276c0c071d0SPavel Dovgalyuk     if (event) {
277c0c071d0SPavel Dovgalyuk         QTAILQ_REMOVE(&events_list, event, events);
278c0c071d0SPavel Dovgalyuk     } else {
279c0c071d0SPavel Dovgalyuk         return NULL;
280c0c071d0SPavel Dovgalyuk     }
281c0c071d0SPavel Dovgalyuk 
282c0c071d0SPavel Dovgalyuk     /* Read event-specific data */
283c0c071d0SPavel Dovgalyuk 
284c0c071d0SPavel Dovgalyuk     return event;
285c0c071d0SPavel Dovgalyuk }
286c0c071d0SPavel Dovgalyuk 
287c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */
288c0c071d0SPavel Dovgalyuk void replay_read_events(int checkpoint)
289c0c071d0SPavel Dovgalyuk {
290*d759c951SAlex Bennée     g_assert(replay_mutex_locked());
291f186d64dSPavel Dovgalyuk     while (replay_state.data_kind == EVENT_ASYNC) {
292c0c071d0SPavel Dovgalyuk         Event *event = replay_read_event(checkpoint);
293c0c071d0SPavel Dovgalyuk         if (!event) {
294c0c071d0SPavel Dovgalyuk             break;
295c0c071d0SPavel Dovgalyuk         }
2961a96e3c1SPavel Dovgalyuk         replay_finish_event();
2971a96e3c1SPavel Dovgalyuk         read_event_kind = -1;
298c0c071d0SPavel Dovgalyuk         replay_run_event(event);
299c0c071d0SPavel Dovgalyuk 
300c0c071d0SPavel Dovgalyuk         g_free(event);
301c0c071d0SPavel Dovgalyuk     }
302c0c071d0SPavel Dovgalyuk }
303c0c071d0SPavel Dovgalyuk 
304c0c071d0SPavel Dovgalyuk void replay_init_events(void)
305c0c071d0SPavel Dovgalyuk {
306c0c071d0SPavel Dovgalyuk     read_event_kind = -1;
307c0c071d0SPavel Dovgalyuk }
308c0c071d0SPavel Dovgalyuk 
309c0c071d0SPavel Dovgalyuk void replay_finish_events(void)
310c0c071d0SPavel Dovgalyuk {
311c0c071d0SPavel Dovgalyuk     events_enabled = false;
312c0c071d0SPavel Dovgalyuk     replay_clear_events();
313c0c071d0SPavel Dovgalyuk }
314c0c071d0SPavel Dovgalyuk 
315c0c071d0SPavel Dovgalyuk bool replay_events_enabled(void)
316c0c071d0SPavel Dovgalyuk {
317c0c071d0SPavel Dovgalyuk     return events_enabled;
318c0c071d0SPavel Dovgalyuk }
3196d0ceb80SPavel Dovgalyuk 
3206d0ceb80SPavel Dovgalyuk uint64_t blkreplay_next_id(void)
3216d0ceb80SPavel Dovgalyuk {
3226d0ceb80SPavel Dovgalyuk     if (replay_events_enabled()) {
3236d0ceb80SPavel Dovgalyuk         return replay_state.block_request_id++;
3246d0ceb80SPavel Dovgalyuk     }
3256d0ceb80SPavel Dovgalyuk     return 0;
3266d0ceb80SPavel Dovgalyuk }
327