mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-29 05:13:54 -06:00
replay: synchronize on every virtual timer callback
Sometimes virtual timer callbacks depend on order
of virtual timer processing and warping of virtual clock.
Therefore every callback should be logged to make replay deterministic.
This patch creates a checkpoint before every virtual timer callback.
With these checkpoints virtual timers processing and clock warping
events order is completely deterministic.
Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
Acked-by: Alex Bennée <alex.bennee@linaro.org>
--
v2:
- remove mutex lock/unlock for virtual clock checkpoint since it is
not process any asynchronous events (commit ca9759c2a9
)
- bump record/replay log file version
Message-Id: <159012932716.27256.8854065545365559921.stgit@pasha-ThinkPad-X280>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
255ae6e215
commit
677a3baba4
2 changed files with 10 additions and 24 deletions
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
/* Current version of the replay mechanism.
|
/* Current version of the replay mechanism.
|
||||||
Increase it when file format changes. */
|
Increase it when file format changes. */
|
||||||
#define REPLAY_VERSION 0xe02009
|
#define REPLAY_VERSION 0xe0200a
|
||||||
/* Size of replay log header */
|
/* Size of replay log header */
|
||||||
#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
|
#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
|
||||||
|
|
||||||
|
|
|
@ -501,7 +501,6 @@ bool timerlist_run_timers(QEMUTimerList *timer_list)
|
||||||
bool progress = false;
|
bool progress = false;
|
||||||
QEMUTimerCB *cb;
|
QEMUTimerCB *cb;
|
||||||
void *opaque;
|
void *opaque;
|
||||||
bool need_replay_checkpoint = false;
|
|
||||||
|
|
||||||
if (!atomic_read(&timer_list->active_timers)) {
|
if (!atomic_read(&timer_list->active_timers)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -517,16 +516,6 @@ bool timerlist_run_timers(QEMUTimerList *timer_list)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case QEMU_CLOCK_VIRTUAL:
|
case QEMU_CLOCK_VIRTUAL:
|
||||||
if (replay_mode != REPLAY_MODE_NONE) {
|
|
||||||
/* Checkpoint for virtual clock is redundant in cases where
|
|
||||||
* it's being triggered with only non-EXTERNAL timers, because
|
|
||||||
* these timers don't change guest state directly.
|
|
||||||
* Since it has conditional dependence on specific timers, it is
|
|
||||||
* subject to race conditions and requires special handling.
|
|
||||||
* See below.
|
|
||||||
*/
|
|
||||||
need_replay_checkpoint = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case QEMU_CLOCK_HOST:
|
case QEMU_CLOCK_HOST:
|
||||||
if (!replay_checkpoint(CHECKPOINT_CLOCK_HOST)) {
|
if (!replay_checkpoint(CHECKPOINT_CLOCK_HOST)) {
|
||||||
|
@ -559,19 +548,16 @@ bool timerlist_run_timers(QEMUTimerList *timer_list)
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (need_replay_checkpoint
|
/* Checkpoint for virtual clock is redundant in cases where
|
||||||
&& !(ts->attributes & QEMU_TIMER_ATTR_EXTERNAL)) {
|
* it's being triggered with only non-EXTERNAL timers, because
|
||||||
/* once we got here, checkpoint clock only once */
|
* these timers don't change guest state directly.
|
||||||
need_replay_checkpoint = false;
|
*/
|
||||||
|
if (replay_mode != REPLAY_MODE_NONE
|
||||||
|
&& timer_list->clock->type == QEMU_CLOCK_VIRTUAL
|
||||||
|
&& !(ts->attributes & QEMU_TIMER_ATTR_EXTERNAL)
|
||||||
|
&& !replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) {
|
||||||
qemu_mutex_unlock(&timer_list->active_timers_lock);
|
qemu_mutex_unlock(&timer_list->active_timers_lock);
|
||||||
if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) {
|
goto out;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
qemu_mutex_lock(&timer_list->active_timers_lock);
|
|
||||||
/* The lock was released; start over again in case the list was
|
|
||||||
* modified.
|
|
||||||
*/
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove timer from the list before calling the callback */
|
/* remove timer from the list before calling the callback */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue