diff options
author | 2006-01-13 22:02:37 +0000 | |
---|---|---|
committer | 2006-01-13 22:02:37 +0000 | |
commit | 308cb777af00b675376e3736131d615573bb0a2c (patch) | |
tree | 7a714587f7549902e7f1e993aad584992bea8be5 /sys/kern/kern_time.c | |
parent | list other maxds models (diff) | |
download | wireguard-openbsd-308cb777af00b675376e3736131d615573bb0a2c.tar.xz wireguard-openbsd-308cb777af00b675376e3736131d615573bb0a2c.zip |
auto adjusting adjtime. be more responsive to large clock deltas,
and attempt to compensate for incorrect clocks by adjusting ticks
slowly. ok deraadt
Diffstat (limited to 'sys/kern/kern_time.c')
-rw-r--r-- | sys/kern/kern_time.c | 56 |
1 files changed, 47 insertions, 9 deletions
diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index 3258fc69dbb..864a675f823 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_time.c,v 1.52 2005/11/28 00:14:29 jsg Exp $ */ +/* $OpenBSD: kern_time.c,v 1.53 2006/01/13 22:02:37 tedu Exp $ */ /* $NetBSD: kern_time.c,v 1.20 1996/02/18 11:57:06 fvdl Exp $ */ /* @@ -351,6 +351,7 @@ sys_settimeofday(struct proc *p, void *v, register_t *retval) #ifdef __HAVE_TIMECOUNTER struct timeval adjtimedelta; /* unapplied time correction */ #else +int tick_skew; /* constant adjustment applied to tick */ int tickdelta; /* current clock skew, us. per tick */ long timedelta; /* unapplied time correction, us. */ long bigadj = 1000000; /* use 10x skew above bigadj us. */ @@ -381,9 +382,11 @@ sys_adjtime(struct proc *p, void *v, register_t *retval) return (0); #else + static int increase_skew; struct timeval atv; - long ndelta, ntickdelta, odelta; + long secdelta, ndelta, ntickdelta, odelta; int s, error; + int largeadj = 0; if ((error = suser(p, 0))) return (error); @@ -398,12 +401,21 @@ sys_adjtime(struct proc *p, void *v, register_t *retval) * hardclock(), tickdelta will become zero, lest the correction * overshoot and start taking us away from the desired final time. */ - if (atv.tv_sec > LONG_MAX / 1000000L) + secdelta = atv.tv_sec; + + /* if this is going to take more than 4 hours, speed it up */ + if (secdelta / 1000000L > 4 * 3600L) { + largeadj = 1; + ndelta = LONG_MAX; + } else if (secdelta / 1000000L < -4 * 3600L) { + largeadj = 1; + ndelta = LONG_MIN; + } else if (secdelta > LONG_MAX / 1000000L) { ndelta = LONG_MAX; - else if (atv.tv_sec < LONG_MIN / 1000000L) + } else if (secdelta < LONG_MIN / 1000000L) { ndelta = LONG_MIN; - else { - ndelta = atv.tv_sec * 1000000L; + } else { + ndelta = secdelta * 1000000L; odelta = ndelta; ndelta += atv.tv_usec; if (atv.tv_usec > 0 && ndelta <= odelta) @@ -412,26 +424,52 @@ sys_adjtime(struct proc *p, void *v, register_t *retval) ndelta = LONG_MIN; } - if (ndelta > bigadj || ndelta < -bigadj) + if (largeadj) + ntickdelta = 100 * tickadj; + else if (ndelta > bigadj || ndelta < -bigadj) ntickdelta = 10 * tickadj; else ntickdelta = tickadj; + if (ntickdelta > tick / 4) + ntickdelta = tick / 4; if (ndelta % ntickdelta) ndelta = ndelta / ntickdelta * ntickdelta; /* * To make hardclock()'s job easier, make the per-tick delta negative * if we want time to run slower; then hardclock can simply compute - * tick + tickdelta, and subtract tickdelta from timedelta. + * tick + tickdelta, and subtract tickdelta from timedelta. If + * we notice we are sliding away from where we want to be, + * take notice so next time we can increase the adjustment. */ - if (ndelta < 0) + if (ndelta < 0) { ntickdelta = -ntickdelta; + if (ndelta < timedelta) + increase_skew--; + else + increase_skew++; + } else { + if (ndelta > timedelta) + increase_skew++; + else + increase_skew--; + } s = splclock(); odelta = timedelta; timedelta = ndelta; tickdelta = ntickdelta; splx(s); + if (increase_skew <= -5) { + if (--tick_skew < -tick / 4) + tick_skew = -tick / 4; + increase_skew = 0; + } else if (increase_skew >= 5) { + if (++tick_skew > tick / 4) + tick_skew = tick / 4; + increase_skew = 0; + } + if (SCARG(uap, olddelta)) { atv.tv_sec = odelta / 1000000; atv.tv_usec = odelta % 1000000; |