From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41819) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VTSxp-0004vM-4Z for qemu-devel@nongnu.org; Tue, 08 Oct 2013 04:48:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1VTSxg-0003cI-N8 for qemu-devel@nongnu.org; Tue, 08 Oct 2013 04:48:21 -0400 Received: from mail-ea0-x231.google.com ([2a00:1450:4013:c01::231]:61200) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VTSxg-0003c5-FR for qemu-devel@nongnu.org; Tue, 08 Oct 2013 04:48:12 -0400 Received: by mail-ea0-f177.google.com with SMTP id f15so3703276eak.8 for ; Tue, 08 Oct 2013 01:48:11 -0700 (PDT) Sender: Paolo Bonzini From: Paolo Bonzini Date: Tue, 8 Oct 2013 10:47:35 +0200 Message-Id: <1381222058-16701-6-git-send-email-pbonzini@redhat.com> In-Reply-To: <1381222058-16701-1-git-send-email-pbonzini@redhat.com> References: <1381222058-16701-1-git-send-email-pbonzini@redhat.com> Subject: [Qemu-devel] [PATCH 5/8] timers: prepare the code for future races in calling qemu_clock_warp List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: alex@alex.org.uk Computing the deadline of all vm_clocks is somewhat expensive and calls out to qemu-timer.c; two reasons not to do it in the seqlock's write-side critical section. This however opens the door for races in setting and reading vm_clock_warp_start. To plug them, we need to cover the case where a new deadline slips in between the call to qemu_clock_deadline_ns_all and the actual modification of the icount_warp_timer. Restrict changes to vm_clock_warp_start and the icount_warp_timer's expiration time, to only move them back (which would simply cause an early wakeup). If a vm_clock timer is cancelled while CPUs are idle, this might cause the icount_warp_timer to fire unnecessarily. This is not a problem, after it fires the timer becomes inactive and the next call to timer_mod_anticipate will be precise. In addition to this, we must deactivate the icount_warp_timer _before_ checking whether CPUs are idle. This way, if the "last" CPU becomes idle during the call to timer_del we will still set up the icount_warp_timer. Signed-off-by: Paolo Bonzini --- cpus.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/cpus.c b/cpus.c index 9f450ad..08eaf23 100644 --- a/cpus.c +++ b/cpus.c @@ -319,6 +319,7 @@ void qtest_clock_warp(int64_t dest) void qemu_clock_warp(QEMUClockType type) { + int64_t clock; int64_t deadline; /* @@ -338,7 +339,7 @@ void qemu_clock_warp(QEMUClockType type) * the earliest QEMU_CLOCK_VIRTUAL timer. */ icount_warp_rt(NULL); - if (!all_cpu_threads_idle() || !qemu_clock_has_timers(QEMU_CLOCK_VIRTUAL)) { - timer_del(icount_warp_timer); + timer_del(icount_warp_timer); + if (!all_cpu_threads_idle()) { return; } @@ -348,17 +349,11 @@ void qemu_clock_warp(QEMUClockType type) return; } - vm_clock_warp_start = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); /* We want to use the earliest deadline from ALL vm_clocks */ + clock = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); - - /* Maintain prior (possibly buggy) behaviour where if no deadline - * was set (as there is no QEMU_CLOCK_VIRTUAL timer) or it is more than - * INT32_MAX nanoseconds ahead, we still use INT32_MAX - * nanoseconds. - */ - if ((deadline < 0) || (deadline > INT32_MAX)) { - deadline = INT32_MAX; + if (deadline < 0) { + return; } if (deadline > 0) { @@ -379,7 +375,10 @@ void qemu_clock_warp(QEMUClockType type) * you will not be sending network packets continuously instead of * every 100ms. */ - timer_mod(icount_warp_timer, vm_clock_warp_start + deadline); + if (vm_clock_warp_start == -1 || vm_clock_warp_start > clock) { + vm_clock_warp_start = clock; + } + timer_mod_anticipate(icount_warp_timer, clock + deadline); } else if (deadline == 0) { qemu_clock_notify(QEMU_CLOCK_VIRTUAL); } -- 1.8.3.1