xref: /openbmc/qemu/replay/replay-events.c (revision ca9759c2)
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 bool events_enabled;
31c0c071d0SPavel Dovgalyuk 
32c0c071d0SPavel Dovgalyuk /* Functions */
33c0c071d0SPavel Dovgalyuk 
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;
40ee312992SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_INPUT:
41ee312992SPavel Dovgalyuk         qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque);
42ee312992SPavel Dovgalyuk         qapi_free_InputEvent((InputEvent *)event->opaque);
43ee312992SPavel Dovgalyuk         break;
44ee312992SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_INPUT_SYNC:
45ee312992SPavel Dovgalyuk         qemu_input_event_sync_impl();
46ee312992SPavel Dovgalyuk         break;
4733577b47SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_CHAR_READ:
4833577b47SPavel Dovgalyuk         replay_event_char_read_run(event->opaque);
4933577b47SPavel Dovgalyuk         break;
5063785678SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_BLOCK:
5163785678SPavel Dovgalyuk         aio_bh_call(event->opaque);
5263785678SPavel Dovgalyuk         break;
53646c5478SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_NET:
54646c5478SPavel Dovgalyuk         replay_event_net_run(event->opaque);
55646c5478SPavel Dovgalyuk         break;
56c0c071d0SPavel Dovgalyuk     default:
57c0c071d0SPavel Dovgalyuk         error_report("Replay: invalid async event ID (%d) in the queue",
58c0c071d0SPavel Dovgalyuk                     event->event_kind);
59c0c071d0SPavel Dovgalyuk         exit(1);
60c0c071d0SPavel Dovgalyuk         break;
61c0c071d0SPavel Dovgalyuk     }
62c0c071d0SPavel Dovgalyuk }
63c0c071d0SPavel Dovgalyuk 
64c0c071d0SPavel Dovgalyuk void replay_enable_events(void)
65c0c071d0SPavel Dovgalyuk {
661652e0c3SPavel Dovgalyuk     if (replay_mode != REPLAY_MODE_NONE) {
67c0c071d0SPavel Dovgalyuk         events_enabled = true;
68c0c071d0SPavel Dovgalyuk     }
691652e0c3SPavel Dovgalyuk }
70c0c071d0SPavel Dovgalyuk 
71c0c071d0SPavel Dovgalyuk bool replay_has_events(void)
72c0c071d0SPavel Dovgalyuk {
73c0c071d0SPavel Dovgalyuk     return !QTAILQ_EMPTY(&events_list);
74c0c071d0SPavel Dovgalyuk }
75c0c071d0SPavel Dovgalyuk 
76c0c071d0SPavel Dovgalyuk void replay_flush_events(void)
77c0c071d0SPavel Dovgalyuk {
78d759c951SAlex Bennée     g_assert(replay_mutex_locked());
79d759c951SAlex Bennée 
80c0c071d0SPavel Dovgalyuk     while (!QTAILQ_EMPTY(&events_list)) {
81c0c071d0SPavel Dovgalyuk         Event *event = QTAILQ_FIRST(&events_list);
82c0c071d0SPavel Dovgalyuk         replay_run_event(event);
83c0c071d0SPavel Dovgalyuk         QTAILQ_REMOVE(&events_list, event, events);
84c0c071d0SPavel Dovgalyuk         g_free(event);
85c0c071d0SPavel Dovgalyuk     }
86c0c071d0SPavel Dovgalyuk }
87c0c071d0SPavel Dovgalyuk 
88c0c071d0SPavel Dovgalyuk void replay_disable_events(void)
89c0c071d0SPavel Dovgalyuk {
90c0c071d0SPavel Dovgalyuk     if (replay_mode != REPLAY_MODE_NONE) {
91c0c071d0SPavel Dovgalyuk         events_enabled = false;
92c0c071d0SPavel Dovgalyuk         /* Flush events queue before waiting of completion */
93c0c071d0SPavel Dovgalyuk         replay_flush_events();
94c0c071d0SPavel Dovgalyuk     }
95c0c071d0SPavel Dovgalyuk }
96c0c071d0SPavel Dovgalyuk 
97c0c071d0SPavel Dovgalyuk /*! Adds specified async event to the queue */
9833577b47SPavel Dovgalyuk void replay_add_event(ReplayAsyncEventKind event_kind,
99c0c071d0SPavel Dovgalyuk                       void *opaque,
100c0c071d0SPavel Dovgalyuk                       void *opaque2, uint64_t id)
101c0c071d0SPavel Dovgalyuk {
102c0c071d0SPavel Dovgalyuk     assert(event_kind < REPLAY_ASYNC_COUNT);
103c0c071d0SPavel Dovgalyuk 
104c0c071d0SPavel Dovgalyuk     if (!replay_file || replay_mode == REPLAY_MODE_NONE
105c0c071d0SPavel Dovgalyuk         || !events_enabled) {
106c0c071d0SPavel Dovgalyuk         Event e;
107c0c071d0SPavel Dovgalyuk         e.event_kind = event_kind;
108c0c071d0SPavel Dovgalyuk         e.opaque = opaque;
109c0c071d0SPavel Dovgalyuk         e.opaque2 = opaque2;
110c0c071d0SPavel Dovgalyuk         e.id = id;
111c0c071d0SPavel Dovgalyuk         replay_run_event(&e);
112c0c071d0SPavel Dovgalyuk         return;
113c0c071d0SPavel Dovgalyuk     }
114c0c071d0SPavel Dovgalyuk 
115c0c071d0SPavel Dovgalyuk     Event *event = g_malloc0(sizeof(Event));
116c0c071d0SPavel Dovgalyuk     event->event_kind = event_kind;
117c0c071d0SPavel Dovgalyuk     event->opaque = opaque;
118c0c071d0SPavel Dovgalyuk     event->opaque2 = opaque2;
119c0c071d0SPavel Dovgalyuk     event->id = id;
120c0c071d0SPavel Dovgalyuk 
121d759c951SAlex Bennée     g_assert(replay_mutex_locked());
122c0c071d0SPavel Dovgalyuk     QTAILQ_INSERT_TAIL(&events_list, event, events);
123c0c071d0SPavel Dovgalyuk }
1248a354bd9SPavel Dovgalyuk 
1258a354bd9SPavel Dovgalyuk void replay_bh_schedule_event(QEMUBH *bh)
1268a354bd9SPavel Dovgalyuk {
1271652e0c3SPavel Dovgalyuk     if (events_enabled) {
1288a354bd9SPavel Dovgalyuk         uint64_t id = replay_get_current_step();
1298a354bd9SPavel Dovgalyuk         replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id);
1308a354bd9SPavel Dovgalyuk     } else {
1318a354bd9SPavel Dovgalyuk         qemu_bh_schedule(bh);
1328a354bd9SPavel Dovgalyuk     }
1338a354bd9SPavel Dovgalyuk }
134c0c071d0SPavel Dovgalyuk 
135ee312992SPavel Dovgalyuk void replay_add_input_event(struct InputEvent *event)
136ee312992SPavel Dovgalyuk {
137ee312992SPavel Dovgalyuk     replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0);
138ee312992SPavel Dovgalyuk }
139ee312992SPavel Dovgalyuk 
140ee312992SPavel Dovgalyuk void replay_add_input_sync_event(void)
141ee312992SPavel Dovgalyuk {
142ee312992SPavel Dovgalyuk     replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0);
143ee312992SPavel Dovgalyuk }
144ee312992SPavel Dovgalyuk 
14563785678SPavel Dovgalyuk void replay_block_event(QEMUBH *bh, uint64_t id)
14663785678SPavel Dovgalyuk {
1471652e0c3SPavel Dovgalyuk     if (events_enabled) {
14863785678SPavel Dovgalyuk         replay_add_event(REPLAY_ASYNC_EVENT_BLOCK, bh, NULL, id);
14963785678SPavel Dovgalyuk     } else {
15063785678SPavel Dovgalyuk         qemu_bh_schedule(bh);
15163785678SPavel Dovgalyuk     }
15263785678SPavel Dovgalyuk }
15363785678SPavel Dovgalyuk 
154c0c071d0SPavel Dovgalyuk static void replay_save_event(Event *event, int checkpoint)
155c0c071d0SPavel Dovgalyuk {
156c0c071d0SPavel Dovgalyuk     if (replay_mode != REPLAY_MODE_PLAY) {
157c0c071d0SPavel Dovgalyuk         /* put the event into the file */
158c0c071d0SPavel Dovgalyuk         replay_put_event(EVENT_ASYNC);
159c0c071d0SPavel Dovgalyuk         replay_put_byte(checkpoint);
160c0c071d0SPavel Dovgalyuk         replay_put_byte(event->event_kind);
161c0c071d0SPavel Dovgalyuk 
162c0c071d0SPavel Dovgalyuk         /* save event-specific data */
163c0c071d0SPavel Dovgalyuk         switch (event->event_kind) {
1648a354bd9SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_BH:
1658a354bd9SPavel Dovgalyuk             replay_put_qword(event->id);
1668a354bd9SPavel Dovgalyuk             break;
167ee312992SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_INPUT:
168ee312992SPavel Dovgalyuk             replay_save_input_event(event->opaque);
169ee312992SPavel Dovgalyuk             break;
170ee312992SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_INPUT_SYNC:
171ee312992SPavel Dovgalyuk             break;
17233577b47SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_CHAR_READ:
17333577b47SPavel Dovgalyuk             replay_event_char_read_save(event->opaque);
17433577b47SPavel Dovgalyuk             break;
17563785678SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_BLOCK:
17663785678SPavel Dovgalyuk             replay_put_qword(event->id);
17763785678SPavel Dovgalyuk             break;
178646c5478SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_NET:
179646c5478SPavel Dovgalyuk             replay_event_net_save(event->opaque);
180646c5478SPavel Dovgalyuk             break;
181c0c071d0SPavel Dovgalyuk         default:
18295b4aed5SPavel Dovgalyuk             error_report("Unknown ID %" PRId64 " of replay event", event->id);
183c0c071d0SPavel Dovgalyuk             exit(1);
184c0c071d0SPavel Dovgalyuk         }
185c0c071d0SPavel Dovgalyuk     }
186c0c071d0SPavel Dovgalyuk }
187c0c071d0SPavel Dovgalyuk 
188c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */
189c0c071d0SPavel Dovgalyuk void replay_save_events(int checkpoint)
190c0c071d0SPavel Dovgalyuk {
191d759c951SAlex Bennée     g_assert(replay_mutex_locked());
19289e46eb4SPavel Dovgalyuk     g_assert(checkpoint != CHECKPOINT_CLOCK_WARP_START);
193*ca9759c2SPavel Dovgalyuk     g_assert(checkpoint != CHECKPOINT_CLOCK_VIRTUAL);
194c0c071d0SPavel Dovgalyuk     while (!QTAILQ_EMPTY(&events_list)) {
195c0c071d0SPavel Dovgalyuk         Event *event = QTAILQ_FIRST(&events_list);
196c0c071d0SPavel Dovgalyuk         replay_save_event(event, checkpoint);
197c0c071d0SPavel Dovgalyuk         replay_run_event(event);
198c0c071d0SPavel Dovgalyuk         QTAILQ_REMOVE(&events_list, event, events);
199c0c071d0SPavel Dovgalyuk         g_free(event);
200c0c071d0SPavel Dovgalyuk     }
201c0c071d0SPavel Dovgalyuk }
202c0c071d0SPavel Dovgalyuk 
203c0c071d0SPavel Dovgalyuk static Event *replay_read_event(int checkpoint)
204c0c071d0SPavel Dovgalyuk {
205c0c071d0SPavel Dovgalyuk     Event *event;
2060b30dc01SPavel Dovgalyuk     if (replay_state.read_event_kind == -1) {
2070b30dc01SPavel Dovgalyuk         replay_state.read_event_checkpoint = replay_get_byte();
2080b30dc01SPavel Dovgalyuk         replay_state.read_event_kind = replay_get_byte();
2090b30dc01SPavel Dovgalyuk         replay_state.read_event_id = -1;
210c0c071d0SPavel Dovgalyuk         replay_check_error();
211c0c071d0SPavel Dovgalyuk     }
212c0c071d0SPavel Dovgalyuk 
2130b30dc01SPavel Dovgalyuk     if (checkpoint != replay_state.read_event_checkpoint) {
214c0c071d0SPavel Dovgalyuk         return NULL;
215c0c071d0SPavel Dovgalyuk     }
216c0c071d0SPavel Dovgalyuk 
217c0c071d0SPavel Dovgalyuk     /* Events that has not to be in the queue */
2180b30dc01SPavel Dovgalyuk     switch (replay_state.read_event_kind) {
2198a354bd9SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_BH:
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:
225ee312992SPavel Dovgalyuk         event = g_malloc0(sizeof(Event));
2260b30dc01SPavel Dovgalyuk         event->event_kind = replay_state.read_event_kind;
227ee312992SPavel Dovgalyuk         event->opaque = replay_read_input_event();
228ee312992SPavel Dovgalyuk         return event;
229ee312992SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_INPUT_SYNC:
230ee312992SPavel Dovgalyuk         event = g_malloc0(sizeof(Event));
2310b30dc01SPavel Dovgalyuk         event->event_kind = replay_state.read_event_kind;
232ee312992SPavel Dovgalyuk         event->opaque = 0;
233ee312992SPavel Dovgalyuk         return event;
23433577b47SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_CHAR_READ:
23533577b47SPavel Dovgalyuk         event = g_malloc0(sizeof(Event));
2360b30dc01SPavel Dovgalyuk         event->event_kind = replay_state.read_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:
245646c5478SPavel Dovgalyuk         event = g_malloc0(sizeof(Event));
2460b30dc01SPavel Dovgalyuk         event->event_kind = replay_state.read_event_kind;
247646c5478SPavel Dovgalyuk         event->opaque = replay_event_net_load();
248646c5478SPavel Dovgalyuk         return event;
249c0c071d0SPavel Dovgalyuk     default:
2500b30dc01SPavel Dovgalyuk         error_report("Unknown ID %d of replay event",
2510b30dc01SPavel Dovgalyuk             replay_state.read_event_kind);
252c0c071d0SPavel Dovgalyuk         exit(1);
253c0c071d0SPavel Dovgalyuk         break;
254c0c071d0SPavel Dovgalyuk     }
255c0c071d0SPavel Dovgalyuk 
256c0c071d0SPavel Dovgalyuk     QTAILQ_FOREACH(event, &events_list, events) {
2570b30dc01SPavel Dovgalyuk         if (event->event_kind == replay_state.read_event_kind
2580b30dc01SPavel Dovgalyuk             && (replay_state.read_event_id == -1
2590b30dc01SPavel Dovgalyuk                 || replay_state.read_event_id == event->id)) {
260c0c071d0SPavel Dovgalyuk             break;
261c0c071d0SPavel Dovgalyuk         }
262c0c071d0SPavel Dovgalyuk     }
263c0c071d0SPavel Dovgalyuk 
264c0c071d0SPavel Dovgalyuk     if (event) {
265c0c071d0SPavel Dovgalyuk         QTAILQ_REMOVE(&events_list, event, events);
266c0c071d0SPavel Dovgalyuk     } else {
267c0c071d0SPavel Dovgalyuk         return NULL;
268c0c071d0SPavel Dovgalyuk     }
269c0c071d0SPavel Dovgalyuk 
270c0c071d0SPavel Dovgalyuk     /* Read event-specific data */
271c0c071d0SPavel Dovgalyuk 
272c0c071d0SPavel Dovgalyuk     return event;
273c0c071d0SPavel Dovgalyuk }
274c0c071d0SPavel Dovgalyuk 
275c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */
276c0c071d0SPavel Dovgalyuk void replay_read_events(int checkpoint)
277c0c071d0SPavel Dovgalyuk {
278d759c951SAlex Bennée     g_assert(replay_mutex_locked());
279f186d64dSPavel Dovgalyuk     while (replay_state.data_kind == EVENT_ASYNC) {
280c0c071d0SPavel Dovgalyuk         Event *event = replay_read_event(checkpoint);
281c0c071d0SPavel Dovgalyuk         if (!event) {
282c0c071d0SPavel Dovgalyuk             break;
283c0c071d0SPavel Dovgalyuk         }
2841a96e3c1SPavel Dovgalyuk         replay_finish_event();
2850b30dc01SPavel Dovgalyuk         replay_state.read_event_kind = -1;
286c0c071d0SPavel Dovgalyuk         replay_run_event(event);
287c0c071d0SPavel Dovgalyuk 
288c0c071d0SPavel Dovgalyuk         g_free(event);
289c0c071d0SPavel Dovgalyuk     }
290c0c071d0SPavel Dovgalyuk }
291c0c071d0SPavel Dovgalyuk 
292c0c071d0SPavel Dovgalyuk void replay_init_events(void)
293c0c071d0SPavel Dovgalyuk {
2940b30dc01SPavel Dovgalyuk     replay_state.read_event_kind = -1;
295c0c071d0SPavel Dovgalyuk }
296c0c071d0SPavel Dovgalyuk 
297c0c071d0SPavel Dovgalyuk void replay_finish_events(void)
298c0c071d0SPavel Dovgalyuk {
299c0c071d0SPavel Dovgalyuk     events_enabled = false;
300d873fe03SPavel Dovgalyuk     replay_flush_events();
301c0c071d0SPavel Dovgalyuk }
302c0c071d0SPavel Dovgalyuk 
303c0c071d0SPavel Dovgalyuk bool replay_events_enabled(void)
304c0c071d0SPavel Dovgalyuk {
305c0c071d0SPavel Dovgalyuk     return events_enabled;
306c0c071d0SPavel Dovgalyuk }
3076d0ceb80SPavel Dovgalyuk 
3086d0ceb80SPavel Dovgalyuk uint64_t blkreplay_next_id(void)
3096d0ceb80SPavel Dovgalyuk {
3106d0ceb80SPavel Dovgalyuk     if (replay_events_enabled()) {
3116d0ceb80SPavel Dovgalyuk         return replay_state.block_request_id++;
3126d0ceb80SPavel Dovgalyuk     }
3136d0ceb80SPavel Dovgalyuk     return 0;
3146d0ceb80SPavel Dovgalyuk }
315