xref: /openbmc/qemu/replay/replay-events.c (revision 3e21408b)
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 
replay_disable_events(void)95c0c071d0SPavel Dovgalyuk void replay_disable_events(void)
96c0c071d0SPavel Dovgalyuk {
97c0c071d0SPavel Dovgalyuk     if (replay_mode != REPLAY_MODE_NONE) {
98c0c071d0SPavel Dovgalyuk         events_enabled = false;
99c0c071d0SPavel Dovgalyuk         /* Flush events queue before waiting of completion */
100c0c071d0SPavel Dovgalyuk         replay_flush_events();
101c0c071d0SPavel Dovgalyuk     }
102c0c071d0SPavel Dovgalyuk }
103c0c071d0SPavel Dovgalyuk 
104c0c071d0SPavel Dovgalyuk /*! Adds specified async event to the queue */
replay_add_event(ReplayAsyncEventKind event_kind,void * opaque,void * opaque2,uint64_t id)10533577b47SPavel Dovgalyuk void replay_add_event(ReplayAsyncEventKind event_kind,
106c0c071d0SPavel Dovgalyuk                       void *opaque,
107c0c071d0SPavel Dovgalyuk                       void *opaque2, uint64_t id)
108c0c071d0SPavel Dovgalyuk {
109c0c071d0SPavel Dovgalyuk     assert(event_kind < REPLAY_ASYNC_COUNT);
110c0c071d0SPavel Dovgalyuk 
111c0c071d0SPavel Dovgalyuk     if (!replay_file || replay_mode == REPLAY_MODE_NONE
112c0c071d0SPavel Dovgalyuk         || !events_enabled) {
113c0c071d0SPavel Dovgalyuk         Event e;
114c0c071d0SPavel Dovgalyuk         e.event_kind = event_kind;
115c0c071d0SPavel Dovgalyuk         e.opaque = opaque;
116c0c071d0SPavel Dovgalyuk         e.opaque2 = opaque2;
117c0c071d0SPavel Dovgalyuk         e.id = id;
118c0c071d0SPavel Dovgalyuk         replay_run_event(&e);
119c0c071d0SPavel Dovgalyuk         return;
120c0c071d0SPavel Dovgalyuk     }
121c0c071d0SPavel Dovgalyuk 
122b21e2380SMarkus Armbruster     Event *event = g_new0(Event, 1);
123c0c071d0SPavel Dovgalyuk     event->event_kind = event_kind;
124c0c071d0SPavel Dovgalyuk     event->opaque = opaque;
125c0c071d0SPavel Dovgalyuk     event->opaque2 = opaque2;
126c0c071d0SPavel Dovgalyuk     event->id = id;
127c0c071d0SPavel Dovgalyuk 
128d759c951SAlex Bennée     g_assert(replay_mutex_locked());
129c0c071d0SPavel Dovgalyuk     QTAILQ_INSERT_TAIL(&events_list, event, events);
13046967b1aSPavel Dovgalyuk     qemu_cpu_kick(first_cpu);
131c0c071d0SPavel Dovgalyuk }
1328a354bd9SPavel Dovgalyuk 
replay_bh_schedule_event(QEMUBH * bh)1338a354bd9SPavel Dovgalyuk void replay_bh_schedule_event(QEMUBH *bh)
1348a354bd9SPavel Dovgalyuk {
1351652e0c3SPavel Dovgalyuk     if (events_enabled) {
13613f26713SPavel Dovgalyuk         uint64_t id = replay_get_current_icount();
1378a354bd9SPavel Dovgalyuk         replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id);
1388a354bd9SPavel Dovgalyuk     } else {
1398a354bd9SPavel Dovgalyuk         qemu_bh_schedule(bh);
1408a354bd9SPavel Dovgalyuk     }
1418a354bd9SPavel Dovgalyuk }
142c0c071d0SPavel Dovgalyuk 
replay_bh_schedule_oneshot_event(AioContext * ctx,QEMUBHFunc * cb,void * opaque)143e4ec5ad4SPavel Dovgalyuk void replay_bh_schedule_oneshot_event(AioContext *ctx,
144e4ec5ad4SPavel Dovgalyuk     QEMUBHFunc *cb, void *opaque)
145e4ec5ad4SPavel Dovgalyuk {
146e4ec5ad4SPavel Dovgalyuk     if (events_enabled) {
147e4ec5ad4SPavel Dovgalyuk         uint64_t id = replay_get_current_icount();
148e4ec5ad4SPavel Dovgalyuk         replay_add_event(REPLAY_ASYNC_EVENT_BH_ONESHOT, cb, opaque, id);
149e4ec5ad4SPavel Dovgalyuk     } else {
150e4ec5ad4SPavel Dovgalyuk         aio_bh_schedule_oneshot(ctx, cb, opaque);
151e4ec5ad4SPavel Dovgalyuk     }
152e4ec5ad4SPavel Dovgalyuk }
153e4ec5ad4SPavel Dovgalyuk 
replay_add_input_event(struct InputEvent * event)154ee312992SPavel Dovgalyuk void replay_add_input_event(struct InputEvent *event)
155ee312992SPavel Dovgalyuk {
156ee312992SPavel Dovgalyuk     replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0);
157ee312992SPavel Dovgalyuk }
158ee312992SPavel Dovgalyuk 
replay_add_input_sync_event(void)159ee312992SPavel Dovgalyuk void replay_add_input_sync_event(void)
160ee312992SPavel Dovgalyuk {
161ee312992SPavel Dovgalyuk     replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0);
162ee312992SPavel Dovgalyuk }
163ee312992SPavel Dovgalyuk 
replay_block_event(QEMUBH * bh,uint64_t id)16463785678SPavel Dovgalyuk void replay_block_event(QEMUBH *bh, uint64_t id)
16563785678SPavel Dovgalyuk {
1661652e0c3SPavel Dovgalyuk     if (events_enabled) {
16763785678SPavel Dovgalyuk         replay_add_event(REPLAY_ASYNC_EVENT_BLOCK, bh, NULL, id);
16863785678SPavel Dovgalyuk     } else {
16963785678SPavel Dovgalyuk         qemu_bh_schedule(bh);
17063785678SPavel Dovgalyuk     }
17163785678SPavel Dovgalyuk }
17263785678SPavel Dovgalyuk 
replay_save_event(Event * event)17360618e2dSPavel Dovgalyuk static void replay_save_event(Event *event)
174c0c071d0SPavel Dovgalyuk {
175c0c071d0SPavel Dovgalyuk     if (replay_mode != REPLAY_MODE_PLAY) {
176c0c071d0SPavel Dovgalyuk         /* put the event into the file */
177*3e21408bSPavel Dovgalyuk         g_assert(event->event_kind < REPLAY_ASYNC_COUNT);
178*3e21408bSPavel Dovgalyuk         replay_put_event(EVENT_ASYNC + event->event_kind);
179c0c071d0SPavel Dovgalyuk 
180c0c071d0SPavel Dovgalyuk         /* save event-specific data */
181c0c071d0SPavel Dovgalyuk         switch (event->event_kind) {
1828a354bd9SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_BH:
183e4ec5ad4SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_BH_ONESHOT:
1848a354bd9SPavel Dovgalyuk             replay_put_qword(event->id);
1858a354bd9SPavel Dovgalyuk             break;
186ee312992SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_INPUT:
187ee312992SPavel Dovgalyuk             replay_save_input_event(event->opaque);
188ee312992SPavel Dovgalyuk             break;
189ee312992SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_INPUT_SYNC:
190ee312992SPavel Dovgalyuk             break;
19133577b47SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_CHAR_READ:
19233577b47SPavel Dovgalyuk             replay_event_char_read_save(event->opaque);
19333577b47SPavel Dovgalyuk             break;
19463785678SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_BLOCK:
19563785678SPavel Dovgalyuk             replay_put_qword(event->id);
19663785678SPavel Dovgalyuk             break;
197646c5478SPavel Dovgalyuk         case REPLAY_ASYNC_EVENT_NET:
198646c5478SPavel Dovgalyuk             replay_event_net_save(event->opaque);
199646c5478SPavel Dovgalyuk             break;
200c0c071d0SPavel Dovgalyuk         default:
20195b4aed5SPavel Dovgalyuk             error_report("Unknown ID %" PRId64 " of replay event", event->id);
202c0c071d0SPavel Dovgalyuk             exit(1);
203c0c071d0SPavel Dovgalyuk         }
204c0c071d0SPavel Dovgalyuk     }
205c0c071d0SPavel Dovgalyuk }
206c0c071d0SPavel Dovgalyuk 
207c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */
replay_save_events(void)20860618e2dSPavel Dovgalyuk void replay_save_events(void)
209c0c071d0SPavel Dovgalyuk {
210d759c951SAlex Bennée     g_assert(replay_mutex_locked());
211c0c071d0SPavel Dovgalyuk     while (!QTAILQ_EMPTY(&events_list)) {
212c0c071d0SPavel Dovgalyuk         Event *event = QTAILQ_FIRST(&events_list);
21360618e2dSPavel Dovgalyuk         replay_save_event(event);
214c0c071d0SPavel Dovgalyuk         replay_run_event(event);
215c0c071d0SPavel Dovgalyuk         QTAILQ_REMOVE(&events_list, event, events);
216c0c071d0SPavel Dovgalyuk         g_free(event);
217c0c071d0SPavel Dovgalyuk     }
218c0c071d0SPavel Dovgalyuk }
219c0c071d0SPavel Dovgalyuk 
replay_read_event(void)22060618e2dSPavel Dovgalyuk static Event *replay_read_event(void)
221c0c071d0SPavel Dovgalyuk {
222c0c071d0SPavel Dovgalyuk     Event *event;
223*3e21408bSPavel Dovgalyuk     ReplayAsyncEventKind event_kind = replay_state.data_kind - EVENT_ASYNC;
224c0c071d0SPavel Dovgalyuk 
225c0c071d0SPavel Dovgalyuk     /* Events that has not to be in the queue */
226*3e21408bSPavel Dovgalyuk     switch (event_kind) {
2278a354bd9SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_BH:
228e4ec5ad4SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_BH_ONESHOT:
2290b30dc01SPavel Dovgalyuk         if (replay_state.read_event_id == -1) {
2300b30dc01SPavel Dovgalyuk             replay_state.read_event_id = replay_get_qword();
2318a354bd9SPavel Dovgalyuk         }
2328a354bd9SPavel Dovgalyuk         break;
233ee312992SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_INPUT:
234b21e2380SMarkus Armbruster         event = g_new0(Event, 1);
235*3e21408bSPavel Dovgalyuk         event->event_kind = event_kind;
236ee312992SPavel Dovgalyuk         event->opaque = replay_read_input_event();
237ee312992SPavel Dovgalyuk         return event;
238ee312992SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_INPUT_SYNC:
239b21e2380SMarkus Armbruster         event = g_new0(Event, 1);
240*3e21408bSPavel Dovgalyuk         event->event_kind = event_kind;
241ee312992SPavel Dovgalyuk         event->opaque = 0;
242ee312992SPavel Dovgalyuk         return event;
24333577b47SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_CHAR_READ:
244b21e2380SMarkus Armbruster         event = g_new0(Event, 1);
245*3e21408bSPavel Dovgalyuk         event->event_kind = event_kind;
24633577b47SPavel Dovgalyuk         event->opaque = replay_event_char_read_load();
24733577b47SPavel Dovgalyuk         return event;
24863785678SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_BLOCK:
2490b30dc01SPavel Dovgalyuk         if (replay_state.read_event_id == -1) {
2500b30dc01SPavel Dovgalyuk             replay_state.read_event_id = replay_get_qword();
25163785678SPavel Dovgalyuk         }
25263785678SPavel Dovgalyuk         break;
253646c5478SPavel Dovgalyuk     case REPLAY_ASYNC_EVENT_NET:
254b21e2380SMarkus Armbruster         event = g_new0(Event, 1);
255*3e21408bSPavel Dovgalyuk         event->event_kind = event_kind;
256646c5478SPavel Dovgalyuk         event->opaque = replay_event_net_load();
257646c5478SPavel Dovgalyuk         return event;
258c0c071d0SPavel Dovgalyuk     default:
259*3e21408bSPavel Dovgalyuk         error_report("Unknown ID %d of replay event", event_kind);
260c0c071d0SPavel Dovgalyuk         exit(1);
261c0c071d0SPavel Dovgalyuk         break;
262c0c071d0SPavel Dovgalyuk     }
263c0c071d0SPavel Dovgalyuk 
264c0c071d0SPavel Dovgalyuk     QTAILQ_FOREACH(event, &events_list, events) {
265*3e21408bSPavel Dovgalyuk         if (event->event_kind == event_kind
2660b30dc01SPavel Dovgalyuk             && (replay_state.read_event_id == -1
2670b30dc01SPavel Dovgalyuk                 || replay_state.read_event_id == event->id)) {
268c0c071d0SPavel Dovgalyuk             break;
269c0c071d0SPavel Dovgalyuk         }
270c0c071d0SPavel Dovgalyuk     }
271c0c071d0SPavel Dovgalyuk 
272c0c071d0SPavel Dovgalyuk     if (event) {
273c0c071d0SPavel Dovgalyuk         QTAILQ_REMOVE(&events_list, event, events);
274c0c071d0SPavel Dovgalyuk     }
275c0c071d0SPavel Dovgalyuk 
276c0c071d0SPavel Dovgalyuk     return event;
277c0c071d0SPavel Dovgalyuk }
278c0c071d0SPavel Dovgalyuk 
279c0c071d0SPavel Dovgalyuk /* Called with replay mutex locked */
replay_read_events(void)28060618e2dSPavel Dovgalyuk void replay_read_events(void)
281c0c071d0SPavel Dovgalyuk {
282d759c951SAlex Bennée     g_assert(replay_mutex_locked());
283*3e21408bSPavel Dovgalyuk     while (replay_state.data_kind >= EVENT_ASYNC
284*3e21408bSPavel Dovgalyuk         && replay_state.data_kind <= EVENT_ASYNC_LAST) {
28560618e2dSPavel Dovgalyuk         Event *event = replay_read_event();
286c0c071d0SPavel Dovgalyuk         if (!event) {
287c0c071d0SPavel Dovgalyuk             break;
288c0c071d0SPavel Dovgalyuk         }
2891a96e3c1SPavel Dovgalyuk         replay_finish_event();
290*3e21408bSPavel Dovgalyuk         replay_state.read_event_id = -1;
291c0c071d0SPavel Dovgalyuk         replay_run_event(event);
292c0c071d0SPavel Dovgalyuk 
293c0c071d0SPavel Dovgalyuk         g_free(event);
294c0c071d0SPavel Dovgalyuk     }
295c0c071d0SPavel Dovgalyuk }
296c0c071d0SPavel Dovgalyuk 
replay_init_events(void)297c0c071d0SPavel Dovgalyuk void replay_init_events(void)
298c0c071d0SPavel Dovgalyuk {
299*3e21408bSPavel Dovgalyuk     replay_state.read_event_id = -1;
300c0c071d0SPavel Dovgalyuk }
301c0c071d0SPavel Dovgalyuk 
replay_finish_events(void)302c0c071d0SPavel Dovgalyuk void replay_finish_events(void)
303c0c071d0SPavel Dovgalyuk {
304c0c071d0SPavel Dovgalyuk     events_enabled = false;
305d873fe03SPavel Dovgalyuk     replay_flush_events();
306c0c071d0SPavel Dovgalyuk }
307c0c071d0SPavel Dovgalyuk 
replay_events_enabled(void)308c0c071d0SPavel Dovgalyuk bool replay_events_enabled(void)
309c0c071d0SPavel Dovgalyuk {
310c0c071d0SPavel Dovgalyuk     return events_enabled;
311c0c071d0SPavel Dovgalyuk }
3126d0ceb80SPavel Dovgalyuk 
blkreplay_next_id(void)3136d0ceb80SPavel Dovgalyuk uint64_t blkreplay_next_id(void)
3146d0ceb80SPavel Dovgalyuk {
3156d0ceb80SPavel Dovgalyuk     if (replay_events_enabled()) {
3166d0ceb80SPavel Dovgalyuk         return replay_state.block_request_id++;
3176d0ceb80SPavel Dovgalyuk     }
3186d0ceb80SPavel Dovgalyuk     return 0;
3196d0ceb80SPavel Dovgalyuk }
320