summaryrefslogtreecommitdiff
path: root/replay/replay.c
diff options
context:
space:
mode:
Diffstat (limited to 'replay/replay.c')
-rw-r--r--replay/replay.c58
1 files changed, 33 insertions, 25 deletions
diff --git a/replay/replay.c b/replay/replay.c
index 7a23c62d61..8228261401 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 0xe02006
+#define REPLAY_VERSION 0xe02007
/* Size of replay log header */
#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
@@ -81,7 +81,7 @@ int replay_get_instructions(void)
void replay_account_executed_instructions(void)
{
if (replay_mode == REPLAY_MODE_PLAY) {
- replay_mutex_lock();
+ g_assert(replay_mutex_locked());
if (replay_state.instructions_count > 0) {
int count = (int)(replay_get_current_step()
- replay_state.current_step);
@@ -100,24 +100,22 @@ void replay_account_executed_instructions(void)
qemu_notify_event();
}
}
- replay_mutex_unlock();
}
}
bool replay_exception(void)
{
+
if (replay_mode == REPLAY_MODE_RECORD) {
+ g_assert(replay_mutex_locked());
replay_save_instructions();
- replay_mutex_lock();
replay_put_event(EVENT_EXCEPTION);
- replay_mutex_unlock();
return true;
} else if (replay_mode == REPLAY_MODE_PLAY) {
+ g_assert(replay_mutex_locked());
bool res = replay_has_exception();
if (res) {
- replay_mutex_lock();
replay_finish_event();
- replay_mutex_unlock();
}
return res;
}
@@ -129,10 +127,9 @@ bool replay_has_exception(void)
{
bool res = false;
if (replay_mode == REPLAY_MODE_PLAY) {
+ g_assert(replay_mutex_locked());
replay_account_executed_instructions();
- replay_mutex_lock();
res = replay_next_event_is(EVENT_EXCEPTION);
- replay_mutex_unlock();
}
return res;
@@ -141,17 +138,15 @@ bool replay_has_exception(void)
bool replay_interrupt(void)
{
if (replay_mode == REPLAY_MODE_RECORD) {
+ g_assert(replay_mutex_locked());
replay_save_instructions();
- replay_mutex_lock();
replay_put_event(EVENT_INTERRUPT);
- replay_mutex_unlock();
return true;
} else if (replay_mode == REPLAY_MODE_PLAY) {
+ g_assert(replay_mutex_locked());
bool res = replay_has_interrupt();
if (res) {
- replay_mutex_lock();
replay_finish_event();
- replay_mutex_unlock();
}
return res;
}
@@ -163,10 +158,9 @@ bool replay_has_interrupt(void)
{
bool res = false;
if (replay_mode == REPLAY_MODE_PLAY) {
+ g_assert(replay_mutex_locked());
replay_account_executed_instructions();
- replay_mutex_lock();
res = replay_next_event_is(EVENT_INTERRUPT);
- replay_mutex_unlock();
}
return res;
}
@@ -174,25 +168,35 @@ bool replay_has_interrupt(void)
void replay_shutdown_request(ShutdownCause cause)
{
if (replay_mode == REPLAY_MODE_RECORD) {
- replay_mutex_lock();
+ g_assert(replay_mutex_locked());
replay_put_event(EVENT_SHUTDOWN + cause);
- replay_mutex_unlock();
}
}
bool replay_checkpoint(ReplayCheckpoint checkpoint)
{
bool res = false;
+ static bool in_checkpoint;
assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST);
- replay_save_instructions();
if (!replay_file) {
return true;
}
- replay_mutex_lock();
+ if (in_checkpoint) {
+ /* If we are already in checkpoint, then there is no need
+ for additional synchronization.
+ Recursion occurs when HW event modifies timers.
+ Timer modification may invoke the checkpoint and
+ proceed to recursion. */
+ return true;
+ }
+ 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) {
@@ -205,12 +209,18 @@ bool replay_checkpoint(ReplayCheckpoint checkpoint)
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);
- replay_save_events(checkpoint);
+ /* This checkpoint belongs to several threads.
+ Processing events from different threads is
+ non-deterministic */
+ if (checkpoint != CHECKPOINT_CLOCK_WARP_START) {
+ replay_save_events(checkpoint);
+ }
res = true;
}
out:
- replay_mutex_unlock();
+ in_checkpoint = false;
return res;
}
@@ -233,8 +243,6 @@ static void replay_enable(const char *fname, int mode)
atexit(replay_finish);
- replay_mutex_init();
-
replay_file = fopen(fname, fmode);
if (replay_file == NULL) {
fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno));
@@ -242,8 +250,9 @@ static void replay_enable(const char *fname, int mode)
}
replay_filename = g_strdup(fname);
-
replay_mode = mode;
+ replay_mutex_init();
+
replay_state.data_kind = -1;
replay_state.instructions_count = 0;
replay_state.current_step = 0;
@@ -358,7 +367,6 @@ void replay_finish(void)
replay_snapshot = NULL;
replay_finish_events();
- replay_mutex_destroy();
}
void replay_add_blocker(Error *reason)