From nobody Wed Nov 5 14:26:05 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1534874215972538.749475505428; Tue, 21 Aug 2018 10:56:55 -0700 (PDT) Received: from localhost ([::1]:55222 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fsAtf-0004eX-4D for importer@patchew.org; Tue, 21 Aug 2018 13:56:51 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:33712) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fsA4n-0002IM-TF for qemu-devel@nongnu.org; Tue, 21 Aug 2018 13:04:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fsA4Y-0006rp-5a for qemu-devel@nongnu.org; Tue, 21 Aug 2018 13:04:11 -0400 Received: from mail-wr1-x444.google.com ([2a00:1450:4864:20::444]:46400) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fsA4X-0006ne-60 for qemu-devel@nongnu.org; Tue, 21 Aug 2018 13:04:01 -0400 Received: by mail-wr1-x444.google.com with SMTP id a108-v6so13816753wrc.13 for ; Tue, 21 Aug 2018 10:04:00 -0700 (PDT) Received: from 640k.lan (dynamic-adsl-78-12-184-244.clienti.tiscali.it. [78.12.184.244]) by smtp.gmail.com with ESMTPSA id v6-v6sm2608955wmc.43.2018.08.21.10.03.58 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 21 Aug 2018 10:03:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=RfG0Zs6mZA54jkoHiJfTSQukJQeED7djpCykJHDzWL8=; b=hMEnlFzls/oPl/LBmnln66g2msruX8UpCQfDsrSGGR5z5t6d13B/3CunENz0qX/QKW ch4esdO+/BXXI5YqOLf5hNt9PODeH2D8qmy4qb93XvDBd4413o7EVEe0ltWjC2hYFgGX ETzzfzzx0b1DYMYCgloIrFIR+WMm1QM5Dy39+6QaoC/yVwG2ZtIMwQcAjAaj3J/zZeSn OZDpk0s72sVOX0L777NBz6a/c8Wf3UDkENXMm/aHKypBa3gUS8y0Vp0zkt7t3IYYk5Ps X0HTlaKGSu2SIZ8TkcJ+CjpuweGNsYEhrb0RZHm4w+e18ycxL0sccvDN5OHaqcU6gPZp nLjw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references; bh=RfG0Zs6mZA54jkoHiJfTSQukJQeED7djpCykJHDzWL8=; b=cj9ctAOFObQ9VgWGwvwKO+7hOA+jP7UWoR9txEXKpw/AkKA6JXmIsuJ/MED/zyC/O4 rFIWAf+NB5eMcer+loC0uSb9hA9k2kZwuN0sy7iKMedTNBU4wuLTLCHbika6tsiYo39o 00RgAXPfQ/K9Q8auiaRXD0KXkqI3l85cwkgdjo13uEKPHxjIDc1OChNGYt6BZG5KkqbD Z4JtIPTrSlWnWRICTCMWBIgmgCyZSTazoSMX7WLd9xOhjYjUmznpgV3x0dWo28Prk2Gt taET0qYFNrConR3opJsO/SU1Miv6zRhny+5fAGHUWYm2r6KmRcJJH2/qw/RvCS7ujJ9X xqOA== X-Gm-Message-State: AOUpUlHZr2Qz7f5rdYGqtOqnB8kVbkNyuNrF3QhtRp0B+StO2MPNFnsa cgimFCKHeEshbU81QtpbiANXvtZW X-Google-Smtp-Source: AA+uWPyCRPv/5i8AVZ4T5GNFAA/zYIn/7JvKybSU1v818eO9B9uvxAmyxhR7FA2/zdFr1rbNaPmM2Q== X-Received: by 2002:adf:c78e:: with SMTP id l14-v6mr31381768wrg.230.1534871039254; Tue, 21 Aug 2018 10:03:59 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Tue, 21 Aug 2018 19:02:24 +0200 Message-Id: <1534870966-9287-53-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1534870966-9287-1-git-send-email-pbonzini@redhat.com> References: <1534870966-9287-1-git-send-email-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::444 Subject: [Qemu-devel] [PULL 52/74] cpus: protect TimerState writes with a spinlock X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDMRC_1 RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" In the next patch, we will need to write cpu_ticks_offset from any thread, even outside the BQL. Currently, it is protected by the BQL just because cpu_enable_ticks and cpu_disable_ticks happen to hold it, but the critical sections are well delimited and it's easy to remove the BQL dependency. Add a spinlock that matches vm_clock_seqlock, and hold it when writing to the TimerState. This also lets us fix cpu_update_icount when 64-bit atomics are not available. Fields of TiemrState are reordered to avoid padding. Signed-off-by: Paolo Bonzini --- cpus.c | 72 +++++++++++++++++++++++++++++++++++++++++++-------------------= ---- 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/cpus.c b/cpus.c index 3783651..a810a95 100644 --- a/cpus.c +++ b/cpus.c @@ -129,21 +129,27 @@ typedef struct TimersState { int64_t cpu_ticks_prev; int64_t cpu_ticks_offset; =20 - /* cpu_clock_offset can be read out of BQL, so protect it with - * this lock. + /* Protect fields that can be respectively read outside the + * BQL, and written from multiple threads. */ QemuSeqLock vm_clock_seqlock; - int64_t cpu_clock_offset; - int32_t cpu_ticks_enabled; + QemuSpin vm_clock_lock; + + int16_t cpu_ticks_enabled; =20 /* Conversion factor from emulated instructions to virtual clock ticks= . */ - int icount_time_shift; + int16_t icount_time_shift; + /* Compensate for varying guest execution speed. */ int64_t qemu_icount_bias; + + int64_t vm_clock_warp_start; + int64_t cpu_clock_offset; + /* Only written by TCG thread */ int64_t qemu_icount; + /* for adjusting icount */ - int64_t vm_clock_warp_start; QEMUTimer *icount_rt_timer; QEMUTimer *icount_vm_timer; QEMUTimer *icount_warp_timer; @@ -244,11 +250,15 @@ void cpu_update_icount(CPUState *cpu) int64_t executed =3D cpu_get_icount_executed(cpu); cpu->icount_budget -=3D executed; =20 -#ifdef CONFIG_ATOMIC64 +#ifndef CONFIG_ATOMIC64 + seqlock_write_lock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); +#endif atomic_set__nocheck(&timers_state.qemu_icount, timers_state.qemu_icount + executed); -#else /* FIXME: we need 64bit atomics to do this safely */ - timers_state.qemu_icount +=3D executed; +#ifndef CONFIG_ATOMIC64 + seqlock_write_unlock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); #endif } =20 @@ -369,14 +379,15 @@ int64_t cpu_get_clock(void) */ void cpu_enable_ticks(void) { - /* Here, the really thing protected by seqlock is cpu_clock_offset. */ - seqlock_write_begin(&timers_state.vm_clock_seqlock); + seqlock_write_lock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); if (!timers_state.cpu_ticks_enabled) { timers_state.cpu_ticks_offset -=3D cpu_get_host_ticks(); timers_state.cpu_clock_offset -=3D get_clock(); timers_state.cpu_ticks_enabled =3D 1; } - seqlock_write_end(&timers_state.vm_clock_seqlock); + seqlock_write_unlock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); } =20 /* disable cpu_get_ticks() : the clock is stopped. You must not call @@ -385,14 +396,15 @@ void cpu_enable_ticks(void) */ void cpu_disable_ticks(void) { - /* Here, the really thing protected by seqlock is cpu_clock_offset. */ - seqlock_write_begin(&timers_state.vm_clock_seqlock); + seqlock_write_lock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); if (timers_state.cpu_ticks_enabled) { timers_state.cpu_ticks_offset +=3D cpu_get_host_ticks(); timers_state.cpu_clock_offset =3D cpu_get_clock_locked(); timers_state.cpu_ticks_enabled =3D 0; } - seqlock_write_end(&timers_state.vm_clock_seqlock); + seqlock_write_unlock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); } =20 /* Correlation between real and virtual time is always going to be @@ -415,7 +427,8 @@ static void icount_adjust(void) return; } =20 - seqlock_write_begin(&timers_state.vm_clock_seqlock); + seqlock_write_lock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); cur_time =3D cpu_get_clock_locked(); cur_icount =3D cpu_get_icount_locked(); =20 @@ -439,7 +452,8 @@ static void icount_adjust(void) atomic_set__nocheck(&timers_state.qemu_icount_bias, cur_icount - (timers_state.qemu_icount << timers_state.icount_time_shift)); - seqlock_write_end(&timers_state.vm_clock_seqlock); + seqlock_write_unlock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); } =20 static void icount_adjust_rt(void *opaque) @@ -480,7 +494,8 @@ static void icount_warp_rt(void) return; } =20 - seqlock_write_begin(&timers_state.vm_clock_seqlock); + seqlock_write_lock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); if (runstate_is_running()) { int64_t clock =3D REPLAY_CLOCK(REPLAY_CLOCK_VIRTUAL_RT, cpu_get_clock_locked()); @@ -500,7 +515,8 @@ static void icount_warp_rt(void) timers_state.qemu_icount_bias + warp_delta); } timers_state.vm_clock_warp_start =3D -1; - seqlock_write_end(&timers_state.vm_clock_seqlock); + seqlock_write_unlock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); =20 if (qemu_clock_expired(QEMU_CLOCK_VIRTUAL)) { qemu_clock_notify(QEMU_CLOCK_VIRTUAL); @@ -525,10 +541,12 @@ void qtest_clock_warp(int64_t dest) int64_t deadline =3D qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL= ); int64_t warp =3D qemu_soonest_timeout(dest - clock, deadline); =20 - seqlock_write_begin(&timers_state.vm_clock_seqlock); + seqlock_write_lock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); atomic_set__nocheck(&timers_state.qemu_icount_bias, timers_state.qemu_icount_bias + warp); - seqlock_write_end(&timers_state.vm_clock_seqlock); + seqlock_write_unlock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); =20 qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL); timerlist_run_timers(aio_context->tlg.tl[QEMU_CLOCK_VIRTUAL]); @@ -595,10 +613,12 @@ void qemu_start_warp_timer(void) * It is useful when we want a deterministic execution time, * isolated from host latencies. */ - seqlock_write_begin(&timers_state.vm_clock_seqlock); + seqlock_write_lock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); atomic_set__nocheck(&timers_state.qemu_icount_bias, timers_state.qemu_icount_bias + deadline); - seqlock_write_end(&timers_state.vm_clock_seqlock); + seqlock_write_unlock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); qemu_clock_notify(QEMU_CLOCK_VIRTUAL); } else { /* @@ -609,12 +629,14 @@ void qemu_start_warp_timer(void) * you will not be sending network packets continuously instea= d of * every 100ms. */ - seqlock_write_begin(&timers_state.vm_clock_seqlock); + seqlock_write_lock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); if (timers_state.vm_clock_warp_start =3D=3D -1 || timers_state.vm_clock_warp_start > clock) { timers_state.vm_clock_warp_start =3D clock; } - seqlock_write_end(&timers_state.vm_clock_seqlock); + seqlock_write_unlock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); timer_mod_anticipate(timers_state.icount_warp_timer, clock + deadline); } --=20 1.8.3.1