aboutsummaryrefslogtreecommitdiff
path: root/replay/replay.c
diff options
context:
space:
mode:
authorPavel Dovgalyuk <pavel.dovgalyuk@ispras.ru>2022-05-27 13:46:18 +0300
committerPaolo Bonzini <pbonzini@redhat.com>2022-06-06 09:26:53 +0200
commit60618e2d77691e44bb78e23b2b0cf07b5c405e56 (patch)
tree992cfb9f63c5a9d8962cffcf678e8c6445993556 /replay/replay.c
parent75bbe5e5ec2867f098a31bfd553a1fb084289cc2 (diff)
replay: rewrite async event handling
This patch decouples checkpoints and async events. It was a tricky part of replay implementation. Now it becomes much simpler and easier to maintain. Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru> Acked-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <165364837856.688121.8785039478408995979.stgit@pasha-ThinkPad-X280> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'replay/replay.c')
-rw-r--r--replay/replay.c74
1 files changed, 30 insertions, 44 deletions
diff --git a/replay/replay.c b/replay/replay.c
index 2d3607998a..ccd7edec76 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -22,7 +22,7 @@
/* Current version of the replay mechanism.
Increase it when file format changes. */
-#define REPLAY_VERSION 0xe0200a
+#define REPLAY_VERSION 0xe0200b
/* Size of replay log header */
#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
@@ -171,64 +171,49 @@ void replay_shutdown_request(ShutdownCause cause)
bool replay_checkpoint(ReplayCheckpoint checkpoint)
{
- bool res = false;
- static bool in_checkpoint;
assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST);
- if (!replay_file) {
- return true;
- }
-
- if (in_checkpoint) {
- /*
- Recursion occurs when HW event modifies timers.
- Prevent performing icount warp in this case and
- wait for another invocation of the checkpoint.
- */
- g_assert(replay_mode == REPLAY_MODE_PLAY);
- return false;
- }
- in_checkpoint = true;
-
replay_save_instructions();
if (replay_mode == REPLAY_MODE_PLAY) {
g_assert(replay_mutex_locked());
if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) {
replay_finish_event();
- } else if (replay_state.data_kind != EVENT_ASYNC) {
- res = false;
- goto out;
+ } else {
+ return false;
}
- replay_read_events(checkpoint);
- /* replay_read_events may leave some unread events.
- Return false if not all of the events associated with
- checkpoint were processed */
- res = replay_state.data_kind != EVENT_ASYNC;
} else if (replay_mode == REPLAY_MODE_RECORD) {
g_assert(replay_mutex_locked());
replay_put_event(EVENT_CHECKPOINT + checkpoint);
- /* This checkpoint belongs to several threads.
- Processing events from different threads is
- non-deterministic */
- if (checkpoint != CHECKPOINT_CLOCK_WARP_START
- /* FIXME: this is temporary fix, other checkpoints
- may also be invoked from the different threads someday.
- Asynchronous event processing should be refactored
- to create additional replay event kind which is
- nailed to the one of the threads and which processes
- the event queue. */
- && checkpoint != CHECKPOINT_CLOCK_VIRTUAL) {
- replay_save_events(checkpoint);
- }
- res = true;
}
-out:
- in_checkpoint = false;
- return res;
+ return true;
+}
+
+void replay_async_events(void)
+{
+ static bool processing = false;
+ /*
+ * If we are already processing the events, recursion may occur
+ * in case of incorrect implementation when HW event modifies timers.
+ * Timer modification may invoke the icount warp, event processing,
+ * and cause the recursion.
+ */
+ g_assert(!processing);
+ processing = true;
+
+ replay_save_instructions();
+
+ if (replay_mode == REPLAY_MODE_PLAY) {
+ g_assert(replay_mutex_locked());
+ replay_read_events();
+ } else if (replay_mode == REPLAY_MODE_RECORD) {
+ g_assert(replay_mutex_locked());
+ replay_save_events();
+ }
+ processing = false;
}
-bool replay_has_checkpoint(void)
+bool replay_has_event(void)
{
bool res = false;
if (replay_mode == REPLAY_MODE_PLAY) {
@@ -236,6 +221,7 @@ bool replay_has_checkpoint(void)
replay_account_executed_instructions();
res = EVENT_CHECKPOINT <= replay_state.data_kind
&& replay_state.data_kind <= EVENT_CHECKPOINT_LAST;
+ res = res || replay_state.data_kind == EVENT_ASYNC;
}
return res;
}