diff options
author | cperciva <cperciva@FreeBSD.org> | 2010-11-22 09:13:25 +0000 |
---|---|---|
committer | cperciva <cperciva@FreeBSD.org> | 2010-11-22 09:13:25 +0000 |
commit | 6cdc82f90731dd5c361708b204ef977079a6a146 (patch) | |
tree | 7eeada262b358d7d01b66418e625a174d131b1a4 | |
parent | 46e50a7603917cf17df6f85004e94e846f192e37 (diff) | |
download | FreeBSD-src-6cdc82f90731dd5c361708b204ef977079a6a146.zip FreeBSD-src-6cdc82f90731dd5c361708b204ef977079a6a146.tar.gz |
In tc_windup, handle the case where the previous call to tc_windup was
more than 1s earlier. Prior to this commit, the computation of
th_scale * delta (which produces a 64-bit value equal to the time since
the last tc_windup call in units of 2^(-64) seconds) would overflow and
any complete seconds would be lost.
We fix this by repeatedly converting tc_frequency units of timecounter
to one seconds; this is not exactly correct, since it loses the NTP
adjustment, but if we find ourselves going more than 1s at a time between
clock interrupts, losing a few seconds worth of NTP adjustments is the
least of our problems...
-rw-r--r-- | sys/kern/kern_tc.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c index 3e8d470..2487b6b 100644 --- a/sys/kern/kern_tc.c +++ b/sys/kern/kern_tc.c @@ -442,6 +442,16 @@ tc_windup(void) ncount = 0; th->th_offset_count += delta; th->th_offset_count &= th->th_counter->tc_counter_mask; + while (delta > th->th_counter->tc_frequency) { + /* Eat complete unadjusted seconds. */ + delta -= th->th_counter->tc_frequency; + th->th_offset.sec++; + } + if ((delta > th->th_counter->tc_frequency / 2) && + (th->th_scale * delta < (uint64_t)1 << 63)) { + /* The product th_scale * delta just barely overflows. */ + th->th_offset.sec++; + } bintime_addx(&th->th_offset, th->th_scale * delta); /* |