blob: 2e46eda6bf8b8a947c406c60765287f0b11ea7cb [file] [log] [blame]
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +03001/*
2 * replay-events.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
Peter Maydelld38ea872016-01-29 17:50:05 +000012#include "qemu/osdep.h"
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +030013#include "qemu/error-report.h"
14#include "sysemu/replay.h"
15#include "replay-internal.h"
Pavel Dovgalyuk8a354bd2015-09-17 19:24:56 +030016#include "block/aio.h"
Pavel Dovgalyukee312992015-09-17 19:25:24 +030017#include "ui/input.h"
Pavel Dovgalyuk46967b12021-04-01 11:19:51 +030018#include "hw/core/cpu.h"
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +030019
20typedef struct Event {
21 ReplayAsyncEventKind event_kind;
22 void *opaque;
23 void *opaque2;
24 uint64_t id;
25
26 QTAILQ_ENTRY(Event) events;
27} Event;
28
29static QTAILQ_HEAD(, Event) events_list = QTAILQ_HEAD_INITIALIZER(events_list);
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +030030static bool events_enabled;
31
32/* Functions */
33
34static void replay_run_event(Event *event)
35{
36 switch (event->event_kind) {
Pavel Dovgalyuk8a354bd2015-09-17 19:24:56 +030037 case REPLAY_ASYNC_EVENT_BH:
38 aio_bh_call(event->opaque);
39 break;
Pavel Dovgalyuke4ec5ad2019-09-17 14:58:19 +030040 case REPLAY_ASYNC_EVENT_BH_ONESHOT:
41 ((QEMUBHFunc *)event->opaque)(event->opaque2);
42 break;
Pavel Dovgalyukee312992015-09-17 19:25:24 +030043 case REPLAY_ASYNC_EVENT_INPUT:
44 qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque);
45 qapi_free_InputEvent((InputEvent *)event->opaque);
46 break;
47 case REPLAY_ASYNC_EVENT_INPUT_SYNC:
48 qemu_input_event_sync_impl();
49 break;
Pavel Dovgalyuk33577b42016-03-14 10:44:36 +030050 case REPLAY_ASYNC_EVENT_CHAR_READ:
51 replay_event_char_read_run(event->opaque);
52 break;
Pavel Dovgalyuk63785672016-03-14 10:45:10 +030053 case REPLAY_ASYNC_EVENT_BLOCK:
54 aio_bh_call(event->opaque);
55 break;
Pavel Dovgalyuk646c5472016-09-26 11:08:21 +030056 case REPLAY_ASYNC_EVENT_NET:
57 replay_event_net_run(event->opaque);
58 break;
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +030059 default:
60 error_report("Replay: invalid async event ID (%d) in the queue",
61 event->event_kind);
62 exit(1);
63 break;
64 }
65}
66
67void replay_enable_events(void)
68{
Pavel Dovgalyuk1652e0c2018-02-27 12:52:09 +030069 if (replay_mode != REPLAY_MODE_NONE) {
70 events_enabled = true;
71 }
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +030072}
73
74bool replay_has_events(void)
75{
76 return !QTAILQ_EMPTY(&events_list);
77}
78
79void replay_flush_events(void)
80{
Pavel Dovgalyukf9a9fb62020-10-03 20:13:37 +030081 if (replay_mode == REPLAY_MODE_NONE) {
82 return;
83 }
84
Alex Bennéed759c952018-02-27 12:52:48 +030085 g_assert(replay_mutex_locked());
86
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +030087 while (!QTAILQ_EMPTY(&events_list)) {
88 Event *event = QTAILQ_FIRST(&events_list);
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +030089 replay_run_event(event);
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +030090 QTAILQ_REMOVE(&events_list, event, events);
91 g_free(event);
92 }
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +030093}
94
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +030095/*! Adds specified async event to the queue */
Pavel Dovgalyuk33577b42016-03-14 10:44:36 +030096void replay_add_event(ReplayAsyncEventKind event_kind,
97 void *opaque,
98 void *opaque2, uint64_t id)
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +030099{
100 assert(event_kind < REPLAY_ASYNC_COUNT);
101
102 if (!replay_file || replay_mode == REPLAY_MODE_NONE
103 || !events_enabled) {
104 Event e;
105 e.event_kind = event_kind;
106 e.opaque = opaque;
107 e.opaque2 = opaque2;
108 e.id = id;
109 replay_run_event(&e);
110 return;
111 }
112
Markus Armbrusterb21e2382022-03-15 15:41:56 +0100113 Event *event = g_new0(Event, 1);
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300114 event->event_kind = event_kind;
115 event->opaque = opaque;
116 event->opaque2 = opaque2;
117 event->id = id;
118
Alex Bennéed759c952018-02-27 12:52:48 +0300119 g_assert(replay_mutex_locked());
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300120 QTAILQ_INSERT_TAIL(&events_list, event, events);
Pavel Dovgalyuk46967b12021-04-01 11:19:51 +0300121 qemu_cpu_kick(first_cpu);
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300122}
Pavel Dovgalyuk8a354bd2015-09-17 19:24:56 +0300123
124void replay_bh_schedule_event(QEMUBH *bh)
125{
Pavel Dovgalyuk1652e0c2018-02-27 12:52:09 +0300126 if (events_enabled) {
Pavel Dovgalyuk13f26712019-07-25 11:44:43 +0300127 uint64_t id = replay_get_current_icount();
Pavel Dovgalyuk8a354bd2015-09-17 19:24:56 +0300128 replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id);
129 } else {
130 qemu_bh_schedule(bh);
131 }
132}
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300133
Pavel Dovgalyuke4ec5ad2019-09-17 14:58:19 +0300134void replay_bh_schedule_oneshot_event(AioContext *ctx,
135 QEMUBHFunc *cb, void *opaque)
136{
137 if (events_enabled) {
138 uint64_t id = replay_get_current_icount();
139 replay_add_event(REPLAY_ASYNC_EVENT_BH_ONESHOT, cb, opaque, id);
140 } else {
141 aio_bh_schedule_oneshot(ctx, cb, opaque);
142 }
143}
144
Pavel Dovgalyukee312992015-09-17 19:25:24 +0300145void replay_add_input_event(struct InputEvent *event)
146{
147 replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0);
148}
149
150void replay_add_input_sync_event(void)
151{
152 replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0);
153}
154
Pavel Dovgalyuk63785672016-03-14 10:45:10 +0300155void replay_block_event(QEMUBH *bh, uint64_t id)
156{
Pavel Dovgalyuk1652e0c2018-02-27 12:52:09 +0300157 if (events_enabled) {
Pavel Dovgalyuk63785672016-03-14 10:45:10 +0300158 replay_add_event(REPLAY_ASYNC_EVENT_BLOCK, bh, NULL, id);
159 } else {
160 qemu_bh_schedule(bh);
161 }
162}
163
Pavel Dovgalyuk60618e22022-05-27 13:46:18 +0300164static void replay_save_event(Event *event)
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300165{
166 if (replay_mode != REPLAY_MODE_PLAY) {
167 /* put the event into the file */
Pavel Dovgalyuk3e214082022-05-27 13:46:23 +0300168 g_assert(event->event_kind < REPLAY_ASYNC_COUNT);
169 replay_put_event(EVENT_ASYNC + event->event_kind);
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300170
171 /* save event-specific data */
172 switch (event->event_kind) {
Pavel Dovgalyuk8a354bd2015-09-17 19:24:56 +0300173 case REPLAY_ASYNC_EVENT_BH:
Pavel Dovgalyuke4ec5ad2019-09-17 14:58:19 +0300174 case REPLAY_ASYNC_EVENT_BH_ONESHOT:
Pavel Dovgalyuk8a354bd2015-09-17 19:24:56 +0300175 replay_put_qword(event->id);
176 break;
Pavel Dovgalyukee312992015-09-17 19:25:24 +0300177 case REPLAY_ASYNC_EVENT_INPUT:
178 replay_save_input_event(event->opaque);
179 break;
180 case REPLAY_ASYNC_EVENT_INPUT_SYNC:
181 break;
Pavel Dovgalyuk33577b42016-03-14 10:44:36 +0300182 case REPLAY_ASYNC_EVENT_CHAR_READ:
183 replay_event_char_read_save(event->opaque);
184 break;
Pavel Dovgalyuk63785672016-03-14 10:45:10 +0300185 case REPLAY_ASYNC_EVENT_BLOCK:
186 replay_put_qword(event->id);
187 break;
Pavel Dovgalyuk646c5472016-09-26 11:08:21 +0300188 case REPLAY_ASYNC_EVENT_NET:
189 replay_event_net_save(event->opaque);
190 break;
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300191 default:
Pavel Dovgalyuk95b4aed2016-03-14 10:45:04 +0300192 error_report("Unknown ID %" PRId64 " of replay event", event->id);
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300193 exit(1);
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300194 }
195 }
196}
197
198/* Called with replay mutex locked */
Pavel Dovgalyuk60618e22022-05-27 13:46:18 +0300199void replay_save_events(void)
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300200{
Alex Bennéed759c952018-02-27 12:52:48 +0300201 g_assert(replay_mutex_locked());
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300202 while (!QTAILQ_EMPTY(&events_list)) {
203 Event *event = QTAILQ_FIRST(&events_list);
Pavel Dovgalyuk60618e22022-05-27 13:46:18 +0300204 replay_save_event(event);
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300205 replay_run_event(event);
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300206 QTAILQ_REMOVE(&events_list, event, events);
207 g_free(event);
208 }
209}
210
Pavel Dovgalyuk60618e22022-05-27 13:46:18 +0300211static Event *replay_read_event(void)
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300212{
213 Event *event;
Pavel Dovgalyuk3e214082022-05-27 13:46:23 +0300214 ReplayAsyncEventKind event_kind = replay_state.data_kind - EVENT_ASYNC;
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300215
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300216 /* Events that has not to be in the queue */
Pavel Dovgalyuk3e214082022-05-27 13:46:23 +0300217 switch (event_kind) {
Pavel Dovgalyuk8a354bd2015-09-17 19:24:56 +0300218 case REPLAY_ASYNC_EVENT_BH:
Pavel Dovgalyuke4ec5ad2019-09-17 14:58:19 +0300219 case REPLAY_ASYNC_EVENT_BH_ONESHOT:
Pavel Dovgalyuk0b30dc02018-02-27 12:53:22 +0300220 if (replay_state.read_event_id == -1) {
221 replay_state.read_event_id = replay_get_qword();
Pavel Dovgalyuk8a354bd2015-09-17 19:24:56 +0300222 }
223 break;
Pavel Dovgalyukee312992015-09-17 19:25:24 +0300224 case REPLAY_ASYNC_EVENT_INPUT:
Markus Armbrusterb21e2382022-03-15 15:41:56 +0100225 event = g_new0(Event, 1);
Pavel Dovgalyuk3e214082022-05-27 13:46:23 +0300226 event->event_kind = event_kind;
Pavel Dovgalyukee312992015-09-17 19:25:24 +0300227 event->opaque = replay_read_input_event();
228 return event;
229 case REPLAY_ASYNC_EVENT_INPUT_SYNC:
Markus Armbrusterb21e2382022-03-15 15:41:56 +0100230 event = g_new0(Event, 1);
Pavel Dovgalyuk3e214082022-05-27 13:46:23 +0300231 event->event_kind = event_kind;
Pavel Dovgalyukee312992015-09-17 19:25:24 +0300232 event->opaque = 0;
233 return event;
Pavel Dovgalyuk33577b42016-03-14 10:44:36 +0300234 case REPLAY_ASYNC_EVENT_CHAR_READ:
Markus Armbrusterb21e2382022-03-15 15:41:56 +0100235 event = g_new0(Event, 1);
Pavel Dovgalyuk3e214082022-05-27 13:46:23 +0300236 event->event_kind = event_kind;
Pavel Dovgalyuk33577b42016-03-14 10:44:36 +0300237 event->opaque = replay_event_char_read_load();
238 return event;
Pavel Dovgalyuk63785672016-03-14 10:45:10 +0300239 case REPLAY_ASYNC_EVENT_BLOCK:
Pavel Dovgalyuk0b30dc02018-02-27 12:53:22 +0300240 if (replay_state.read_event_id == -1) {
241 replay_state.read_event_id = replay_get_qword();
Pavel Dovgalyuk63785672016-03-14 10:45:10 +0300242 }
243 break;
Pavel Dovgalyuk646c5472016-09-26 11:08:21 +0300244 case REPLAY_ASYNC_EVENT_NET:
Markus Armbrusterb21e2382022-03-15 15:41:56 +0100245 event = g_new0(Event, 1);
Pavel Dovgalyuk3e214082022-05-27 13:46:23 +0300246 event->event_kind = event_kind;
Pavel Dovgalyuk646c5472016-09-26 11:08:21 +0300247 event->opaque = replay_event_net_load();
248 return event;
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300249 default:
Pavel Dovgalyuk3e214082022-05-27 13:46:23 +0300250 error_report("Unknown ID %d of replay event", event_kind);
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300251 exit(1);
252 break;
253 }
254
255 QTAILQ_FOREACH(event, &events_list, events) {
Pavel Dovgalyuk3e214082022-05-27 13:46:23 +0300256 if (event->event_kind == event_kind
Pavel Dovgalyuk0b30dc02018-02-27 12:53:22 +0300257 && (replay_state.read_event_id == -1
258 || replay_state.read_event_id == event->id)) {
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300259 break;
260 }
261 }
262
263 if (event) {
264 QTAILQ_REMOVE(&events_list, event, events);
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300265 }
266
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300267 return event;
268}
269
270/* Called with replay mutex locked */
Pavel Dovgalyuk60618e22022-05-27 13:46:18 +0300271void replay_read_events(void)
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300272{
Alex Bennéed759c952018-02-27 12:52:48 +0300273 g_assert(replay_mutex_locked());
Pavel Dovgalyuk3e214082022-05-27 13:46:23 +0300274 while (replay_state.data_kind >= EVENT_ASYNC
275 && replay_state.data_kind <= EVENT_ASYNC_LAST) {
Pavel Dovgalyuk60618e22022-05-27 13:46:18 +0300276 Event *event = replay_read_event();
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300277 if (!event) {
278 break;
279 }
Pavel Dovgalyuk1a96e3c2018-02-27 12:52:03 +0300280 replay_finish_event();
Pavel Dovgalyuk3e214082022-05-27 13:46:23 +0300281 replay_state.read_event_id = -1;
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300282 replay_run_event(event);
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300283
284 g_free(event);
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300285 }
286}
287
288void replay_init_events(void)
289{
Pavel Dovgalyuk3e214082022-05-27 13:46:23 +0300290 replay_state.read_event_id = -1;
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300291}
292
293void replay_finish_events(void)
294{
295 events_enabled = false;
Pavel Dovgalyukd873fe02018-09-12 11:18:59 +0300296 replay_flush_events();
Pavel Dovgalyukc0c071d2015-09-17 19:24:22 +0300297}
298
299bool replay_events_enabled(void)
300{
301 return events_enabled;
302}
Pavel Dovgalyuk6d0ceb82016-09-26 11:08:16 +0300303
304uint64_t blkreplay_next_id(void)
305{
306 if (replay_events_enabled()) {
307 return replay_state.block_request_id++;
308 }
309 return 0;
310}