diff options
author | phk <phk@FreeBSD.org> | 2002-02-24 20:04:07 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 2002-02-24 20:04:07 +0000 |
commit | a3dad41f082df22428308626a6b3540f670d3663 (patch) | |
tree | d1f06991d01fa9cf8de6e53acae90152702de4ca /sys/kern | |
parent | 559718f505145874dcc7b773d0465d839a7ad319 (diff) | |
download | FreeBSD-src-a3dad41f082df22428308626a6b3540f670d3663.zip FreeBSD-src-a3dad41f082df22428308626a6b3540f670d3663.tar.gz |
Add a generation number to timecounters and spin if it changes under
our feet when we look inside timecounter structures.
Make the "sync_other" code more robust by never overwriting the
tc_next field.
Add counters for the bin[up]time functions.
Call tc_windup() in tc_init() and switch_timecounter() to make sure
we all the fields set right.
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_tc.c | 99 |
1 files changed, 62 insertions, 37 deletions
diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c index a6b300e..09ca5a6 100644 --- a/sys/kern/kern_tc.c +++ b/sys/kern/kern_tc.c @@ -42,6 +42,8 @@ SYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime, CTLFLAG_RD, SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, ""); +static unsigned nbintime; +static unsigned nbinuptime; static unsigned nmicrotime; static unsigned nnanotime; static unsigned ngetmicrotime; @@ -50,6 +52,8 @@ static unsigned nmicrouptime; static unsigned nnanouptime; static unsigned ngetmicrouptime; static unsigned ngetnanouptime; +SYSCTL_INT(_kern_timecounter, OID_AUTO, nbintime, CTLFLAG_RD, &nbintime, 0, ""); +SYSCTL_INT(_kern_timecounter, OID_AUTO, nbinuptime, CTLFLAG_RD, &nbinuptime, 0, ""); SYSCTL_INT(_kern_timecounter, OID_AUTO, nmicrotime, CTLFLAG_RD, &nmicrotime, 0, ""); SYSCTL_INT(_kern_timecounter, OID_AUTO, nnanotime, CTLFLAG_RD, &nnanotime, 0, ""); SYSCTL_INT(_kern_timecounter, OID_AUTO, nmicrouptime, CTLFLAG_RD, &nmicrouptime, 0, ""); @@ -70,6 +74,8 @@ dummy_get_timecount(struct timecounter *tc) { static unsigned now; + if (tc->tc_generation == 0) + tc->tc_generation++; return (++now); } @@ -106,16 +112,22 @@ void binuptime(struct bintime *bt) { struct timecounter *tc; - - tc = timecounter; - *bt = tc->tc_offset; - bintime_addx(bt, tc->tc_scale * tco_delta(tc)); + unsigned gen; + + nbinuptime++; + do { + tc = timecounter; + gen = tc->tc_generation; + *bt = tc->tc_offset; + bintime_addx(bt, tc->tc_scale * tco_delta(tc)); + } while (gen == 0 || gen != tc->tc_generation); } void bintime(struct bintime *bt) { + nbintime++; binuptime(bt); bintime_add(bt, &boottimebin); } @@ -124,20 +136,28 @@ void getmicrotime(struct timeval *tvp) { struct timecounter *tc; + unsigned gen; ngetmicrotime++; - tc = timecounter; - *tvp = tc->tc_microtime; + do { + tc = timecounter; + gen = tc->tc_generation; + *tvp = tc->tc_microtime; + } while (gen == 0 || gen != tc->tc_generation); } void getnanotime(struct timespec *tsp) { struct timecounter *tc; + unsigned gen; ngetnanotime++; - tc = timecounter; - *tsp = tc->tc_nanotime; + do { + tc = timecounter; + gen = tc->tc_generation; + *tsp = tc->tc_nanotime; + } while (gen == 0 || gen != tc->tc_generation); } void @@ -164,20 +184,28 @@ void getmicrouptime(struct timeval *tvp) { struct timecounter *tc; + unsigned gen; ngetmicrouptime++; - tc = timecounter; - bintime2timeval(&tc->tc_offset, tvp); + do { + tc = timecounter; + gen = tc->tc_generation; + bintime2timeval(&tc->tc_offset, tvp); + } while (gen == 0 || gen != tc->tc_generation); } void getnanouptime(struct timespec *tsp) { struct timecounter *tc; + unsigned gen; ngetnanouptime++; - tc = timecounter; - bintime2timespec(&tc->tc_offset, tsp); + do { + tc = timecounter; + gen = tc->tc_generation; + bintime2timespec(&tc->tc_offset, tsp); + } while (gen == 0 || gen != tc->tc_generation); } void @@ -240,19 +268,19 @@ tc_init(struct timecounter *tc) tc->tc_avail = timecounter->tc_tweak->tc_avail; timecounter->tc_tweak->tc_avail = tc; } - MALLOC(t1, struct timecounter *, sizeof *t1, M_TIMECOUNTER, M_WAITOK); - tc->tc_other = t1; + MALLOC(t1, struct timecounter *, sizeof *t1, M_TIMECOUNTER, M_WAITOK | M_ZERO); + tc->tc_next = t1; *t1 = *tc; t2 = t1; t3 = NULL; for (i = 1; i < NTIMECOUNTER; i++) { MALLOC(t3, struct timecounter *, sizeof *t3, - M_TIMECOUNTER, M_WAITOK); + M_TIMECOUNTER, M_WAITOK | M_ZERO); *t3 = *tc; - t3->tc_other = t2; + t3->tc_next = t2; t2 = t3; } - t1->tc_other = t3; + t1->tc_next = t3; tc = t1; printf("Timecounter \"%s\" frequency %lu Hz\n", @@ -262,6 +290,7 @@ tc_init(struct timecounter *tc) tc->tc_offset_count = tc->tc_get_timecount(tc); binuptime(&tc->tc_offset); timecounter = tc; + tc_windup(); } void @@ -293,42 +322,34 @@ switch_timecounter(struct timecounter *newtc) splx(s); return; } - newtc = newtc->tc_tweak->tc_other; + newtc = newtc->tc_tweak->tc_next; binuptime(&newtc->tc_offset); newtc->tc_offset_count = newtc->tc_get_timecount(newtc); tco_setscales(newtc); + newtc->tc_generation = 0; timecounter = newtc; + tc_windup(); splx(s); } -static struct timecounter * -sync_other_counter(void) -{ - struct timecounter *tc, *tcn, *tco; - unsigned delta; - - tco = timecounter; - tc = tco->tc_other; - tcn = tc->tc_other; - *tc = *tco; - tc->tc_other = tcn; - delta = tco_delta(tc); - tc->tc_offset_count += delta; - tc->tc_offset_count &= tc->tc_counter_mask; - bintime_addx(&tc->tc_offset, tc->tc_scale * delta); - return (tc); -} - void tc_windup(void) { struct timecounter *tc, *tco; struct bintime bt; struct timeval tvt; + unsigned ogen, delta; int i; tco = timecounter; - tc = sync_other_counter(); + tc = tco->tc_next; + ogen = tc->tc_generation; + tc->tc_generation = 0; + bcopy(tco, tc, __offsetof(struct timecounter, tc_generation)); + delta = tco_delta(tc); + tc->tc_offset_count += delta; + tc->tc_offset_count &= tc->tc_counter_mask; + bintime_addx(&tc->tc_offset, tc->tc_scale * delta); /* * We may be inducing a tiny error here, the tc_poll_pps() may * process a latched count which happens after the tco_delta() @@ -363,6 +384,10 @@ tc_windup(void) bintime_add(&bt, &boottimebin); bintime2timeval(&bt, &tc->tc_microtime); bintime2timespec(&bt, &tc->tc_nanotime); + ogen++; + if (ogen == 0) + ogen++; + tc->tc_generation = ogen; time_second = tc->tc_microtime.tv_sec; timecounter = tc; } |