Updating time counters without memory barriers is wrong. Put
authorbluhm <bluhm@openbsd.org>
Tue, 18 Sep 2018 20:47:11 +0000 (20:47 +0000)
committerbluhm <bluhm@openbsd.org>
Tue, 18 Sep 2018 20:47:11 +0000 (20:47 +0000)
membar_producer() into tc_windup() and membar_consumer() into the
uptime functions.  They order the visibility of the time and
generation number updates.
This is a combination of what NetBSD and FreeBSD do.
OK kettenis@

sys/kern/kern_tc.c

index 9aa4470..3d02cf7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kern_tc.c,v 1.33 2018/05/28 18:05:42 guenther Exp $ */
+/*     $OpenBSD: kern_tc.c,v 1.34 2018/09/18 20:47:11 bluhm Exp $ */
 
 /*
  * Copyright (c) 2000 Poul-Henning Kamp <phk@FreeBSD.org>
@@ -22,6 +22,7 @@
  */
 
 #include <sys/param.h>
+#include <sys/atomic.h>
 #include <sys/kernel.h>
 #include <sys/timeout.h>
 #include <sys/sysctl.h>
@@ -141,8 +142,10 @@ binuptime(struct bintime *bt)
        do {
                th = timehands;
                gen = th->th_generation;
+               membar_consumer();
                *bt = th->th_offset;
                bintime_addx(bt, th->th_scale * tc_delta(th));
+               membar_consumer();
        } while (gen == 0 || gen != th->th_generation);
 }
 
@@ -199,7 +202,9 @@ getnanouptime(struct timespec *tsp)
        do {
                th = timehands;
                gen = th->th_generation;
+               membar_consumer();
                bintime2timespec(&th->th_offset, tsp);
+               membar_consumer();
        } while (gen == 0 || gen != th->th_generation);
 }
 
@@ -212,7 +217,9 @@ getmicrouptime(struct timeval *tvp)
        do {
                th = timehands;
                gen = th->th_generation;
+               membar_consumer();
                bintime2timeval(&th->th_offset, tvp);
+               membar_consumer();
        } while (gen == 0 || gen != th->th_generation);
 }
 
@@ -225,7 +232,9 @@ getnanotime(struct timespec *tsp)
        do {
                th = timehands;
                gen = th->th_generation;
+               membar_consumer();
                *tsp = th->th_nanotime;
+               membar_consumer();
        } while (gen == 0 || gen != th->th_generation);
 }
 
@@ -238,7 +247,9 @@ getmicrotime(struct timeval *tvp)
        do {
                th = timehands;
                gen = th->th_generation;
+               membar_consumer();
                *tvp = th->th_microtime;
+               membar_consumer();
        } while (gen == 0 || gen != th->th_generation);
 }
 
@@ -390,6 +401,7 @@ tc_windup(void)
        th = tho->th_next;
        ogen = th->th_generation;
        th->th_generation = 0;
+       membar_producer();
        memcpy(th, tho, offsetof(struct timehands, th_generation));
 
        /*
@@ -481,11 +493,13 @@ tc_windup(void)
         */
        if (++ogen == 0)
                ogen = 1;
+       membar_producer();
        th->th_generation = ogen;
 
        /* Go live with the new struct timehands. */
        time_second = th->th_microtime.tv_sec;
        time_uptime = th->th_offset.sec;
+       membar_producer();
        timehands = th;
 }