diff options
author | Pavel Dovgalyuk | 2022-05-27 12:46:18 +0200 |
---|---|---|
committer | Paolo Bonzini | 2022-06-06 09:26:53 +0200 |
commit | 60618e2d77691e44bb78e23b2b0cf07b5c405e56 (patch) | |
tree | 992cfb9f63c5a9d8962cffcf678e8c6445993556 /replay | |
parent | replay: notify vCPU when BH is scheduled (diff) | |
download | qemu-60618e2d77691e44bb78e23b2b0cf07b5c405e56.tar.gz qemu-60618e2d77691e44bb78e23b2b0cf07b5c405e56.tar.xz qemu-60618e2d77691e44bb78e23b2b0cf07b5c405e56.zip |
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')
-rw-r--r-- | replay/replay-events.c | 20 | ||||
-rw-r--r-- | replay/replay-internal.h | 6 | ||||
-rw-r--r-- | replay/replay-snapshot.c | 1 | ||||
-rw-r--r-- | replay/replay.c | 74 |
4 files changed, 38 insertions, 63 deletions
diff --git a/replay/replay-events.c b/replay/replay-events.c index ac47c89834..db1decf9dd 100644 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -170,12 +170,11 @@ void replay_block_event(QEMUBH *bh, uint64_t id) } } -static void replay_save_event(Event *event, int checkpoint) +static void replay_save_event(Event *event) { if (replay_mode != REPLAY_MODE_PLAY) { /* put the event into the file */ replay_put_event(EVENT_ASYNC); - replay_put_byte(checkpoint); replay_put_byte(event->event_kind); /* save event-specific data */ @@ -206,34 +205,27 @@ static void replay_save_event(Event *event, int checkpoint) } /* Called with replay mutex locked */ -void replay_save_events(int checkpoint) +void replay_save_events(void) { g_assert(replay_mutex_locked()); - g_assert(checkpoint != CHECKPOINT_CLOCK_WARP_START); - g_assert(checkpoint != CHECKPOINT_CLOCK_VIRTUAL); while (!QTAILQ_EMPTY(&events_list)) { Event *event = QTAILQ_FIRST(&events_list); - replay_save_event(event, checkpoint); + replay_save_event(event); replay_run_event(event); QTAILQ_REMOVE(&events_list, event, events); g_free(event); } } -static Event *replay_read_event(int checkpoint) +static Event *replay_read_event(void) { Event *event; if (replay_state.read_event_kind == -1) { - replay_state.read_event_checkpoint = replay_get_byte(); replay_state.read_event_kind = replay_get_byte(); replay_state.read_event_id = -1; replay_check_error(); } - if (checkpoint != replay_state.read_event_checkpoint) { - return NULL; - } - /* Events that has not to be in the queue */ switch (replay_state.read_event_kind) { case REPLAY_ASYNC_EVENT_BH: @@ -294,11 +286,11 @@ static Event *replay_read_event(int checkpoint) } /* Called with replay mutex locked */ -void replay_read_events(int checkpoint) +void replay_read_events(void) { g_assert(replay_mutex_locked()); while (replay_state.data_kind == EVENT_ASYNC) { - Event *event = replay_read_event(checkpoint); + Event *event = replay_read_event(); if (!event) { break; } diff --git a/replay/replay-internal.h b/replay/replay-internal.h index 97649ed8d7..d6e631a394 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -87,8 +87,6 @@ typedef struct ReplayState { int32_t read_event_kind; /*! Asynchronous event id read from the log */ uint64_t read_event_id; - /*! Asynchronous event checkpoint id read from the log */ - int32_t read_event_checkpoint; } ReplayState; extern ReplayState replay_state; @@ -152,9 +150,9 @@ void replay_finish_events(void); /*! Returns true if there are any unsaved events in the queue */ bool replay_has_events(void); /*! Saves events from queue into the file */ -void replay_save_events(int checkpoint); +void replay_save_events(void); /*! Read events from the file into the input queue */ -void replay_read_events(int checkpoint); +void replay_read_events(void); /*! Adds specified async event to the queue */ void replay_add_event(ReplayAsyncEventKind event_kind, void *opaque, void *opaque2, uint64_t id); diff --git a/replay/replay-snapshot.c b/replay/replay-snapshot.c index e8767a1937..7e935deb15 100644 --- a/replay/replay-snapshot.c +++ b/replay/replay-snapshot.c @@ -61,7 +61,6 @@ static const VMStateDescription vmstate_replay = { VMSTATE_UINT64(block_request_id, ReplayState), VMSTATE_INT32(read_event_kind, ReplayState), VMSTATE_UINT64(read_event_id, ReplayState), - VMSTATE_INT32(read_event_checkpoint, ReplayState), VMSTATE_END_OF_LIST() }, }; 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; } |