summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_time.c
diff options
context:
space:
mode:
authortedu <tedu@openbsd.org>2006-01-13 22:02:37 +0000
committertedu <tedu@openbsd.org>2006-01-13 22:02:37 +0000
commit308cb777af00b675376e3736131d615573bb0a2c (patch)
tree7a714587f7549902e7f1e993aad584992bea8be5 /sys/kern/kern_time.c
parentlist other maxds models (diff)
downloadwireguard-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.c56
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;