summaryrefslogtreecommitdiffstats
path: root/util/qemu-timer.c
diff options
context:
space:
mode:
authorPeter Maydell2018-10-19 20:01:07 +0200
committerPeter Maydell2018-10-19 20:01:07 +0200
commitb312532fd03413d0e6ae6767ec793a3e30f487b8 (patch)
treeb394d3bc03a88a5a0d9b98e29bc21b6512e17a6c /util/qemu-timer.c
parentMerge remote-tracking branch 'remotes/rth/tags/pull-tcg-20181018' into staging (diff)
parentreplay: pass raw icount value to replay_save_clock (diff)
downloadqemu-b312532fd03413d0e6ae6767ec793a3e30f487b8.tar.gz
qemu-b312532fd03413d0e6ae6767ec793a3e30f487b8.tar.xz
qemu-b312532fd03413d0e6ae6767ec793a3e30f487b8.zip
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
* RTC fixes (Artem) * icount fixes (Artem) * rr fixes (Pavel, myself) * hotplug cleanup (Igor) * SCSI fixes (myself) * 4.20-rc1 KVM header update (myself) * coalesced PIO support (Peng Hao) * HVF fixes (Roman B.) * Hyper-V refactoring (Roman K.) * Support for Hyper-V IPI (Vitaly) # gpg: Signature made Fri 19 Oct 2018 12:47:58 BST # gpg: using RSA key BFFBD25F78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * remotes/bonzini/tags/for-upstream: (47 commits) replay: pass raw icount value to replay_save_clock target/i386: kvm: just return after migrate_add_blocker failed hyperv_testdev: add SynIC message and event testmodes hyperv: process POST_MESSAGE hypercall hyperv: add support for KVM_HYPERV_EVENTFD hyperv: process SIGNAL_EVENT hypercall hyperv: add synic event flag signaling hyperv: add synic message delivery hyperv: make overlay pages for SynIC hyperv: only add SynIC in compatible configurations hyperv: qom-ify SynIC hyperv:synic: split capability testing and setting i386: add hyperv-stub for CONFIG_HYPERV=n default-configs: collect CONFIG_HYPERV* in hyperv.mak hyperv: factor out arch-independent API into hw/hyperv hyperv: make hyperv_vp_index inline hyperv: split hyperv-proto.h into x86 and arch-independent parts hyperv: rename kvm_hv_sint_route_set_sint hyperv: make HvSintRoute reference-counted hyperv: address HvSintRoute by X86CPU pointer ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'util/qemu-timer.c')
-rw-r--r--util/qemu-timer.c65
1 files changed, 52 insertions, 13 deletions
diff --git a/util/qemu-timer.c b/util/qemu-timer.c
index eb60d8f73a..1cc1b2f2c3 100644
--- a/util/qemu-timer.c
+++ b/util/qemu-timer.c
@@ -339,14 +339,19 @@ int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout)
}
-void timer_init_tl(QEMUTimer *ts,
- QEMUTimerList *timer_list, int scale,
- QEMUTimerCB *cb, void *opaque)
+void timer_init_full(QEMUTimer *ts,
+ QEMUTimerListGroup *timer_list_group, QEMUClockType type,
+ int scale, int attributes,
+ QEMUTimerCB *cb, void *opaque)
{
- ts->timer_list = timer_list;
+ if (!timer_list_group) {
+ timer_list_group = &main_loop_tlg;
+ }
+ ts->timer_list = timer_list_group->tl[type];
ts->cb = cb;
ts->opaque = opaque;
ts->scale = scale;
+ ts->attributes = attributes;
ts->expire_time = -1;
}
@@ -484,6 +489,7 @@ bool timerlist_run_timers(QEMUTimerList *timer_list)
bool progress = false;
QEMUTimerCB *cb;
void *opaque;
+ bool need_replay_checkpoint = false;
if (!atomic_read(&timer_list->active_timers)) {
return false;
@@ -496,12 +502,18 @@ bool timerlist_run_timers(QEMUTimerList *timer_list)
switch (timer_list->clock->type) {
case QEMU_CLOCK_REALTIME:
- case QEMU_CLOCK_VIRTUAL_EXT:
break;
default:
case QEMU_CLOCK_VIRTUAL:
- if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) {
- goto out;
+ 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;
case QEMU_CLOCK_HOST:
@@ -516,14 +528,39 @@ bool timerlist_run_timers(QEMUTimerList *timer_list)
break;
}
+ /*
+ * Extract expired timers from active timers list and and process them.
+ *
+ * In rr mode we need "filtered" checkpointing for virtual clock. The
+ * checkpoint must be recorded/replayed before processing any non-EXTERNAL timer,
+ * and that must only be done once since the clock value stays the same. Because
+ * non-EXTERNAL timers may appear in the timers list while it being processed,
+ * the checkpoint can be issued at a time until no timers are left and we are
+ * done".
+ */
current_time = qemu_clock_get_ns(timer_list->clock->type);
- for(;;) {
- qemu_mutex_lock(&timer_list->active_timers_lock);
- ts = timer_list->active_timers;
+ qemu_mutex_lock(&timer_list->active_timers_lock);
+ while ((ts = timer_list->active_timers)) {
if (!timer_expired_ns(ts, current_time)) {
- qemu_mutex_unlock(&timer_list->active_timers_lock);
+ /* No expired timers left. The checkpoint can be skipped
+ * if no timers fired or they were all external.
+ */
break;
}
+ if (need_replay_checkpoint
+ && !(ts->attributes & QEMU_TIMER_ATTR_EXTERNAL)) {
+ /* once we got here, checkpoint clock only once */
+ need_replay_checkpoint = false;
+ qemu_mutex_unlock(&timer_list->active_timers_lock);
+ if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) {
+ 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 */
timer_list->active_timers = ts->next;
@@ -531,12 +568,15 @@ bool timerlist_run_timers(QEMUTimerList *timer_list)
ts->expire_time = -1;
cb = ts->cb;
opaque = ts->opaque;
- qemu_mutex_unlock(&timer_list->active_timers_lock);
/* run the callback (the timer list can be modified) */
+ qemu_mutex_unlock(&timer_list->active_timers_lock);
cb(opaque);
+ qemu_mutex_lock(&timer_list->active_timers_lock);
+
progress = true;
}
+ qemu_mutex_unlock(&timer_list->active_timers_lock);
out:
qemu_event_set(&timer_list->timers_done_ev);
@@ -598,7 +638,6 @@ int64_t qemu_clock_get_ns(QEMUClockType type)
return get_clock();
default:
case QEMU_CLOCK_VIRTUAL:
- case QEMU_CLOCK_VIRTUAL_EXT:
if (use_icount) {
return cpu_get_icount();
} else {