Hello tech list,

My CLOCK_MONOTONIC can jump backwards.  It looks like a problem with
tk_generation in the user timekeep page.  If tk_offset_count and
tk_offset change but tk_generation doesn't change, then libc can mix
old and new values and calculate a bogus time.

This diff tries to fix it.  The kernel has 2 sets of timehands, th0
and th1, but libc has only 1 timekeep page.  If the kernel switches
between th0 and th1 while they have the same generation, then libc
can't see the switch.  Is diff OK, or should we do something else?

The attached monocheck.c can detect the problem.
It loops until CLOCK_MONOTONIC decreases.    --George

Index: kern/kern_tc.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_tc.c,v
retrieving revision 1.62
diff -u -p -r1.62 kern_tc.c
--- kern/kern_tc.c      6 Jul 2020 13:33:09 -0000       1.62
+++ kern/kern_tc.c      13 Jul 2020 02:59:58 -0000
@@ -98,7 +98,8 @@ static struct timehands th0 = {
        .th_counter = &dummy_timecounter,
        .th_scale = UINT64_MAX / 1000000,
        .th_offset = { .sec = 1, .frac = 0 },
-       .th_generation = 1,
+       /* Keep apart generations of th0, th1, for user timekeep. */
+       .th_generation = UINT_MAX / 2,
        .th_next = &th1
 };
 
#include <sys/time.h>
#include <err.h>
#include <time.h>

int
main(void)
{
        struct timespec diff, now, then;

        if (clock_gettime(CLOCK_MONOTONIC, &then) == -1)
                err(1, "clock_gettime");
        for (;;) {
                if (clock_gettime(CLOCK_MONOTONIC, &now) == -1)
                        err(1, "clock_gettime");
                if (timespeccmp(&now, &then, <)) {
                        timespecsub(&then, &now, &diff);
                        errx(1, "then %lld.%09ld - now %lld.%09ld "
                            "= diff %lld.%09ld",
                            then.tv_sec, then.tv_nsec,
                            now.tv_sec,  now.tv_nsec,
                            diff.tv_sec, diff.tv_nsec);
                }
                then = now;
        }
}

Reply via email to