diff --git a/cpus.c b/cpus.c index d8b3b46cc80396bc9cf65fb97cb002d1725f985e..68f08f5b2d80d0425f10d1e91903923bb65eb993 100644 --- a/cpus.c +++ b/cpus.c @@ -583,18 +583,29 @@ void qemu_start_warp_timer(void) return; } - /* warp clock deterministically in record/replay mode */ - if (!replay_checkpoint(CHECKPOINT_CLOCK_WARP_START)) { - return; - } + if (replay_mode != REPLAY_MODE_PLAY) { + if (!all_cpu_threads_idle()) { + return; + } - if (!all_cpu_threads_idle()) { - return; - } + if (qtest_enabled()) { + /* When testing, qtest commands advance icount. */ + return; + } - if (qtest_enabled()) { - /* When testing, qtest commands advance icount. */ - return; + replay_checkpoint(CHECKPOINT_CLOCK_WARP_START); + } else { + /* warp clock deterministically in record/replay mode */ + if (!replay_checkpoint(CHECKPOINT_CLOCK_WARP_START)) { + /* vCPU is sleeping and warp can't be started. + It is probably a race condition: notification sent + to vCPU was processed in advance and vCPU went to sleep. + Therefore we have to wake it up for doing someting. */ + if (replay_has_checkpoint()) { + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); + } + return; + } } /* We want to use the earliest deadline from ALL vm_clocks */ diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index 3ced6bc23124019483b1ca3c158e3eb132ddc2b7..7f7a594eca99c975908461c9f22934bff195944d 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -120,6 +120,9 @@ void replay_shutdown_request(ShutdownCause cause); Returns 0 in PLAY mode if checkpoint was not found. Returns 1 in all other cases. */ bool replay_checkpoint(ReplayCheckpoint checkpoint); +/*! Used to determine that checkpoint is pending. + Does not proceed to the next event in the log. */ +bool replay_has_checkpoint(void); /* Asynchronous events queue */ diff --git a/replay/replay.c b/replay/replay.c index 822826140118eaf0575bbfa8050efeb9d4b390d3..379b51ab46f13e354e3d1479c7bed471b3a8ae4f 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -224,6 +224,18 @@ out: return res; } +bool replay_has_checkpoint(void) +{ + bool res = false; + if (replay_mode == REPLAY_MODE_PLAY) { + g_assert(replay_mutex_locked()); + replay_account_executed_instructions(); + res = EVENT_CHECKPOINT <= replay_state.data_kind + && replay_state.data_kind <= EVENT_CHECKPOINT_LAST; + } + return res; +} + static void replay_enable(const char *fname, int mode) { const char *fmode = NULL;