diff options
author | 2019-01-19 01:53:44 +0000 | |
---|---|---|
committer | 2019-01-19 01:53:44 +0000 | |
commit | fa5a0c5077f1095f939c1ea212b4045cfbc0537f (patch) | |
tree | 04edb7b0c4ed8023f6b9e36566bdedb48a92fa9b /sys/kern/kern_tc.c | |
parent | 'quit' is no longer set in a signal handler so it no longer needs to (diff) | |
download | wireguard-openbsd-fa5a0c5077f1095f939c1ea212b4045cfbc0537f.tar.xz wireguard-openbsd-fa5a0c5077f1095f939c1ea212b4045cfbc0537f.zip |
Move boottime into the timehands.
To protect the timehands we first need to protect the basis for all UTC
time in the kernel: the boottime.
Because the boottime can be changed at any time it needs to be versioned
along with the other members of the timehands to enable safe lockless reads
when using it for anything. So the global boottime timespec goes away and
the static boottimebin becomes a member of the timehands. Instead of reading
the global boottime you use one of two interfaces: binboottime(9) or
microboottime(9). nanoboottime(9) can trivially be added later, though there
are no consumers for it at the moment.
This introduces one small change in behavior. We used to advance the
reported boottime just before launching kernel threads from main().
This makes it look to userland like we "booted" moments before those
threads were launched. Because there is no longer a boottime global we
can no longer trivially do this from main(), so the boottime we report
to userspace via e.g. kern.boottime will now reflect whatever the time
was when we bootstrapped the timehands via inittodr(9). This is usually
no more than a minute before the kernel threads are launched from main().
The prior behavior can be restored by adding a new interface to the
timecounter layer in a future commit.
Based on FreeBSD r303387.
Discussed with mpi@ and visa@.
ok visa@
Diffstat (limited to 'sys/kern/kern_tc.c')
-rw-r--r-- | sys/kern/kern_tc.c | 78 |
1 files changed, 56 insertions, 22 deletions
diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c index 3d02cf70224..ba8126bc33c 100644 --- a/sys/kern/kern_tc.c +++ b/sys/kern/kern_tc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_tc.c,v 1.34 2018/09/18 20:47:11 bluhm Exp $ */ +/* $OpenBSD: kern_tc.c,v 1.35 2019/01/19 01:53:44 cheloha Exp $ */ /* * Copyright (c) 2000 Poul-Henning Kamp <phk@FreeBSD.org> @@ -70,6 +70,7 @@ struct timehands { int64_t th_adjustment; u_int64_t th_scale; u_int th_offset_count; + struct bintime th_boottime; struct bintime th_offset; struct timeval th_microtime; struct timespec th_nanotime; @@ -79,20 +80,21 @@ struct timehands { }; static struct timehands th0; -static struct timehands th9 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th0}; -static struct timehands th8 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th9}; -static struct timehands th7 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th8}; -static struct timehands th6 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th7}; -static struct timehands th5 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th6}; -static struct timehands th4 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th5}; -static struct timehands th3 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th4}; -static struct timehands th2 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th3}; -static struct timehands th1 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th2}; +static struct timehands th9 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, &th0}; +static struct timehands th8 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, &th9}; +static struct timehands th7 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, &th8}; +static struct timehands th6 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, &th7}; +static struct timehands th5 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, &th6}; +static struct timehands th4 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, &th5}; +static struct timehands th3 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, &th4}; +static struct timehands th2 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, &th3}; +static struct timehands th1 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, &th2}; static struct timehands th0 = { &dummy_timecounter, 0, (uint64_t)-1 / 1000000, 0, + {0, 0}, {1, 0}, {0, 0}, {0, 0}, @@ -108,7 +110,6 @@ volatile time_t time_second = 1; volatile time_t time_uptime = 0; struct bintime naptime; -static struct bintime boottimebin; static int timestepwarnings; void tc_windup(void); @@ -130,10 +131,34 @@ tc_delta(struct timehands *th) /* * Functions for reading the time. We have to loop until we are sure that * the timehands that we operated on was not updated under our feet. See - * the comment in <sys/time.h> for a description of these 12 functions. + * the comment in <sys/time.h> for a description of these functions. */ void +binboottime(struct bintime *bt) +{ + struct timehands *th; + u_int gen; + + do { + th = timehands; + gen = th->th_generation; + membar_consumer(); + *bt = th->th_boottime; + membar_consumer(); + } while (gen == 0 || gen != th->th_generation); +} + +void +microboottime(struct timeval *tvp) +{ + struct bintime bt; + + binboottime(&bt); + bintime2timeval(&bt, tvp); +} + +void binuptime(struct bintime *bt) { struct timehands *th; @@ -170,9 +195,18 @@ microuptime(struct timeval *tvp) void bintime(struct bintime *bt) { + struct timehands *th; + u_int gen; - binuptime(bt); - bintime_add(bt, &boottimebin); + do { + th = timehands; + gen = th->th_generation; + membar_consumer(); + *bt = th->th_offset; + bintime_addx(bt, th->th_scale * tc_delta(th)); + bintime_add(bt, &th->th_boottime); + membar_consumer(); + } while (gen == 0 || gen != th->th_generation); } void @@ -316,9 +350,8 @@ tc_setrealtimeclock(const struct timespec *ts) binuptime(&bt2); timespec2bintime(ts, &bt); bintime_sub(&bt, &bt2); - bintime_add(&bt2, &boottimebin); - boottimebin = bt; - bintime2timespec(&bt, &boottime); + bintime_add(&bt2, &timehands->th_boottime); + timehands->th_boottime = bt; enqueue_randomness(ts->tv_sec); /* XXX fiddle all the little crinkly bits around the fiords... */ @@ -340,24 +373,25 @@ void tc_setclock(const struct timespec *ts) { struct bintime bt, bt2; + static int first = 1; #ifndef SMALL_KERNEL long long adj_ticks; #endif /* * When we're called for the first time, during boot when - * the root partition is mounted, boottime is still zero: - * we just need to set it. + * the root partition is mounted, we need to set boottime. */ - if (boottimebin.sec == 0) { + if (first) { tc_setrealtimeclock(ts); + first = 0; return; } enqueue_randomness(ts->tv_sec); timespec2bintime(ts, &bt); - bintime_sub(&bt, &boottimebin); + bintime_sub(&bt, &timehands->th_boottime); bt2 = timehands->th_offset; timehands->th_offset = bt; @@ -441,7 +475,7 @@ tc_windup(void) * case we missed a leap second. */ bt = th->th_offset; - bintime_add(&bt, &boottimebin); + bintime_add(&bt, &th->th_boottime); i = bt.sec - tho->th_microtime.tv_sec; if (i > LARGE_STEP) i = 2; |