diff options
Diffstat (limited to 'replay/replay.c')
-rw-r--r-- | replay/replay.c | 58 |
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) |