Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/kern timecounter(9): Use seqlock for atomic snapshots of...



details:   https://anonhg.NetBSD.org/src/rev/276efc6b80d9
branches:  trunk
changeset: 377570:276efc6b80d9
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Mon Jul 17 21:51:20 2023 +0000

description:
timecounter(9): Use seqlock for atomic snapshots of timebase.

diffstat:

 sys/kern/kern_tc.c |  61 ++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 44 insertions(+), 17 deletions(-)

diffs (143 lines):

diff -r ab58bb724ce3 -r 276efc6b80d9 sys/kern/kern_tc.c
--- a/sys/kern/kern_tc.c        Mon Jul 17 21:12:29 2023 +0000
+++ b/sys/kern/kern_tc.c        Mon Jul 17 21:51:20 2023 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_tc.c,v 1.70 2023/07/17 15:41:05 riastradh Exp $ */
+/* $NetBSD: kern_tc.c,v 1.71 2023/07/17 21:51:20 riastradh Exp $ */
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -40,7 +40,7 @@
 
 #include <sys/cdefs.h>
 /* __FBSDID("$FreeBSD: src/sys/kern/kern_tc.c,v 1.166 2005/09/19 22:16:31 andre Exp $"); */
-__KERNEL_RCSID(0, "$NetBSD: kern_tc.c,v 1.70 2023/07/17 15:41:05 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_tc.c,v 1.71 2023/07/17 21:51:20 riastradh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ntp.h"
@@ -146,7 +146,10 @@ static volatile struct {
 };
 #endif
 
-static struct bintime timebasebin;
+static struct {
+       struct bintime bin;
+       volatile unsigned gen;  /* even when stable, odd when changing */
+} timebase __cacheline_aligned;
 
 static int timestepwarnings;
 
@@ -496,10 +499,12 @@ microuptime(struct timeval *tvp)
 void
 bintime(struct bintime *bt)
 {
+       struct bintime boottime;
 
        TC_COUNT(nbintime);
        binuptime(bt);
-       bintime_add(bt, &timebasebin);
+       getbinboottime(&boottime);
+       bintime_add(bt, &boottime);
 }
 
 void
@@ -568,6 +573,7 @@ void
 getbintime(struct bintime *bt)
 {
        struct timehands *th;
+       struct bintime boottime;
        u_int gen;
 
        TC_COUNT(ngetbintime);
@@ -576,7 +582,8 @@ getbintime(struct bintime *bt)
                gen = th->th_generation;
                *bt = th->th_offset;
        } while (gen == 0 || gen != th->th_generation);
-       bintime_add(bt, &timebasebin);
+       getbinboottime(&boottime);
+       bintime_add(bt, &boottime);
 }
 
 static inline void
@@ -642,14 +649,25 @@ getmicroboottime(struct timeval *tvp)
 }
 
 void
-getbinboottime(struct bintime *bt)
+getbinboottime(struct bintime *basep)
 {
+       struct bintime base;
+       unsigned gen;
+
+       do {
+               /* Spin until the timebase isn't changing.  */
+               while ((gen = atomic_load_relaxed(&timebase.gen)) & 1)
+                       SPINLOCK_BACKOFF_HOOK;
 
-       /*
-        * XXX Need lockless read synchronization around timebasebin
-        * (and not just here).
-        */
-       *bt = timebasebin;
+               /* Read out a snapshot of the timebase.  */
+               membar_consumer();
+               base = timebase.bin;
+               membar_consumer();
+
+               /* Restart if it changed while we were reading.  */
+       } while (gen != atomic_load_relaxed(&timebase.gen));
+
+       *basep = base;
 }
 
 /*
@@ -839,8 +857,12 @@ tc_setclock(const struct timespec *ts)
        binuptime(&bt2);
        timespec2bintime(ts, &bt);
        bintime_sub(&bt, &bt2);
-       bintime_add(&bt2, &timebasebin);
-       timebasebin = bt;
+       bintime_add(&bt2, &timebase.bin);
+       timebase.gen |= 1;      /* change in progress */
+       membar_producer();
+       timebase.bin = bt;
+       membar_producer();
+       timebase.gen++;         /* commit change */
        tc_windup();
        mutex_spin_exit(&timecounter_lock);
 
@@ -921,7 +943,7 @@ tc_windup(void)
         * the adjustment resulting from adjtime() calls.
         */
        bt = th->th_offset;
-       bintime_add(&bt, &timebasebin);
+       bintime_add(&bt, &timebase.bin);
        i = bt.sec - tho->th_microtime.tv_sec;
        if (i > LARGE_STEP)
                i = 2;
@@ -929,8 +951,13 @@ tc_windup(void)
                t = bt.sec;
                ntp_update_second(&th->th_adjustment, &bt.sec);
                s_update = 1;
-               if (bt.sec != t)
-                       timebasebin.sec += bt.sec - t;
+               if (bt.sec != t) {
+                       timebase.gen |= 1;      /* change in progress */
+                       membar_producer();
+                       timebase.bin.sec += bt.sec - t;
+                       membar_producer();
+                       timebase.gen++;         /* commit change */
+               }
        }
 
        /* Update the UTC timestamps used by the get*() functions. */
@@ -1273,7 +1300,7 @@ pps_ref_event(struct pps_state *pps,
        /* Convert the count to a bintime. */
        bt = pps->capth->th_offset;
        bintime_addx(&bt, pps->capth->th_scale * (acount - pps->capth->th_offset_count));
-       bintime_add(&bt, &timebasebin);
+       bintime_add(&bt, &timebase.bin);
 
        if ((refmode & PPS_REFEVNT_PPS) == 0) {
                /* determine difference to reference time stamp */



Home | Main Index | Thread Index | Old Index