summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_ntptime.c
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2002-04-15 12:23:11 +0000
committerphk <phk@FreeBSD.org>2002-04-15 12:23:11 +0000
commitb6bf4c07cfa2b20a71ec5c6e20bf929d299043c5 (patch)
tree733a8aba038268bb9bbfe0becf82c0d69fb2477b /sys/kern/kern_ntptime.c
parent3bc1e338fc199c90b88b05b395b5a427f9497a15 (diff)
downloadFreeBSD-src-b6bf4c07cfa2b20a71ec5c6e20bf929d299043c5.zip
FreeBSD-src-b6bf4c07cfa2b20a71ec5c6e20bf929d299043c5.tar.gz
Improve the implementation of adjtime(2).
Apply the change as a continuous slew rather than as a series of discrete steps and make it possible to adjust arbitraryly huge amounts of time in either direction. In practice this is done by hooking into the same once-per-second loop as the NTP PLL and setting a suitable frequency offset deducting the amount slewed from the remainder. If the remaining delta is larger than 1 second we slew at 5000PPM (5msec/sec), for a delta less than a second we slew at 500PPM (500usec/sec) and for the last one second period we will slew at whatever rate (less than 500PPM) it takes to eliminate the delta entirely. The old implementation stepped the clock a number of microseconds every HZ to acheive the same effect, using the same rates of change. Eliminate the global variables tickadj, tickdelta and timedelta and their various use and initializations. This removes the most significant obstacle to running timecounter and NTP housekeeping from a timeout rather than hardclock.
Diffstat (limited to 'sys/kern/kern_ntptime.c')
-rw-r--r--sys/kern/kern_ntptime.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/sys/kern/kern_ntptime.c b/sys/kern/kern_ntptime.c
index 4a9c7a6..d8218db 100644
--- a/sys/kern/kern_ntptime.c
+++ b/sys/kern/kern_ntptime.c
@@ -152,6 +152,8 @@ static l_fp time_offset; /* time offset (ns) */
static l_fp time_freq; /* frequency offset (ns/s) */
static l_fp time_adj; /* tick adjust (ns/s) */
+static int64_t time_adjtime; /* correction from adjtime(2) (usec) */
+
#ifdef PPS_SYNC
/*
* The following variables are used when a pulse-per-second (PPS) signal
@@ -437,6 +439,7 @@ void
ntp_update_second(struct timecounter *tcp)
{
u_int32_t *newsec;
+ int tickrate;
l_fp ftemp; /* 32/64-bit temporary */
newsec = &tcp->tc_offset.sec;
@@ -532,7 +535,31 @@ ntp_update_second(struct timecounter *tcp)
time_adj = ftemp;
L_SUB(time_offset, ftemp);
L_ADD(time_adj, time_freq);
+
+ /*
+ * Apply any correction from adjtime(2). If more than one second
+ * off we slew at a rate of 5ms/s (5000 PPM) else 500us/s (500PPM)
+ * until the last second is slewed the final < 500 usecs.
+ */
+ if (time_adjtime != 0) {
+ if (time_adjtime > 1000000)
+ tickrate = 5000;
+ else if (time_adjtime < -1000000)
+ tickrate = -5000;
+ else if (time_adjtime > 500)
+ tickrate = 500;
+ else if (time_adjtime < -500)
+ tickrate = -500;
+ else if (time_adjtime != 0)
+ tickrate = time_adjtime;
+ else
+ tickrate = 0; /* GCC sucks! */
+ time_adjtime -= tickrate;
+ L_LINT(ftemp, tickrate * 1000);
+ L_ADD(time_adj, ftemp);
+ }
tcp->tc_adjustment = time_adj;
+
#ifdef PPS_SYNC
if (pps_valid > 0)
pps_valid--;
@@ -865,3 +892,50 @@ hardpps(tsp, nsec)
time_freq = pps_freq;
}
#endif /* PPS_SYNC */
+
+#ifndef _SYS_SYSPROTO_H_
+struct adjtime_args {
+ struct timeval *delta;
+ struct timeval *olddelta;
+};
+#endif
+/*
+ * MPSAFE
+ */
+/* ARGSUSED */
+int
+adjtime(struct thread *td, struct adjtime_args *uap)
+{
+ struct timeval atv;
+ int error;
+
+ mtx_lock(&Giant);
+
+ if ((error = suser(td)))
+ goto done2;
+ if (uap->olddelta) {
+ atv.tv_sec = time_adjtime / 1000000;
+ atv.tv_usec = time_adjtime % 1000000;
+ if (atv.tv_usec < 0) {
+ atv.tv_usec += 1000000;
+ atv.tv_sec--;
+ }
+ printf("Old: time_adjtime = %ld.%06ld %lld\n",
+ atv.tv_sec, atv.tv_usec, time_adjtime);
+ error = copyout(&atv, uap->olddelta, sizeof(atv));
+ if (error)
+ goto done2;
+ }
+ if (uap->delta) {
+ error = copyin(uap->delta, &atv, sizeof(atv));
+ if (error)
+ goto done2;
+ time_adjtime = (int64_t)atv.tv_sec * 1000000 + atv.tv_usec;
+ printf("New: time_adjtime = %ld.%06ld %lld\n",
+ atv.tv_sec, atv.tv_usec, time_adjtime);
+ }
+done2:
+ mtx_unlock(&Giant);
+ return (error);
+}
+
OpenPOWER on IntegriCloud