2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
16 #include <sys/types.h>
17 #include <sys/param.h>
18 #include <sys/socket.h>
20 #include <sys/ioctl.h>
21 #include <sys/resource.h>
23 #include <netinet/in.h>
24 #include <netinet/in_systm.h>
25 #include <netinet/ip.h>
26 #include <netinet/udp.h>
27 #include <arpa/inet.h>
32 #include <sys/syslog.h>
35 #endif /* defined(AIX) */
44 extern int debuglevel;
45 extern int kern_tickadj;
47 extern struct sysdata sys;
49 double drift_comp = 0.0,
52 afs_int32 update_timer = 0;
58 #define MICROSECONDS 1000000
60 #define abs(x) ((x) < 0 ? -(x) : (x))
66 adj_precision = kern_tickadj;
70 * If you have the "fix" for adjtime() installed in you kernel, you'll
71 * have to make sure that adj_precision is set to 1 here.
77 * 5.0 Logical clock procedure
79 * Only paramter is an offset to vary the clock by, in seconds. We'll either
80 * arrange for the clock to slew to accomodate the adjustment, or just preform
81 * a step adjustment if the offset is too large.
83 * The update which is to be performed is left in the external
86 * Returns non-zero if clock was reset rather than slewed.
88 * Many thanks for Dennis Ferguson <dennis@gw.ccie.utoronto.ca> for his
89 * corrections to my code.
96 struct timeval tv1, tv2;
98 struct timeval delta, olddelta;
102 * Now adjust the logical clock
108 if (offset > CLOCK_MAX || offset < -CLOCK_MAX) {
109 double steptime = offset;
111 (void) gettimeofday(&tv2, (struct timezone *) 0);
112 steptime += tv2.tv_sec;
113 steptime += tv2.tv_usec / 1000000.0;
114 tv1.tv_sec = steptime;
115 tv1.tv_usec = (steptime - tv1.tv_sec) * 1000000;
118 steptime = (tv1.tv_sec + tv1.tv_usec/1000000.0) -
119 (tv2.tv_sec + tv2.tv_usec/1000000.0);
120 printf("adj_logical: %f %f\n", offset, steptime);
123 if (settimeofday(&tv1, (struct timezone *) 0) < 0)
125 syslog(LOG_ERR, "Can't set time: %m");
131 return (1); /* indicate that step adjustment was done */
136 * If this is our very first adjustment, don't touch
137 * the drift compensation (this is f in the spec
138 * equations), else update using the *old* value
141 clock_adjust = offset;
144 else if (update_timer > 0) {
145 ai = abs(compliance);
146 ai = (double)(1<<CLOCK_COMP) -
147 (double)(1<<CLOCK_FACTOR) * ai;
148 if (ai < 1.0) /* max(... , 1.0) */
150 drift_comp += offset / (ai * (double)update_timer);
154 * Set the timer to zero. adj_host_clock() increments it
155 * so we can tell the period between updates.
160 * Now update the compliance. The compliance is h in the
163 compliance += (offset - compliance)/(double)(1<<CLOCK_TRACK);
166 delta.tv_sec = offset;
167 delta.tv_usec = (offset - delta.tv_sec) * 1000;
168 (void) adjtime2(&delta, &olddelta);
175 extern int adjtime();
178 * This is that routine that performs the periodic clock adjustment.
179 * The procedure is best described in the the NTP document. In a
180 * nutshell, we prefer to do lots of small evenly spaced adjustments.
181 * The alternative, one large adjustment, creates two much of a
182 * clock disruption and as a result oscillation.
184 * This function is called every 2**CLOCK_ADJ seconds.
189 * global for debugging?
197 struct timeval delta, olddelta;
203 * Add update period into timer so we know how long it
204 * took between the last update and the next one.
206 update_timer += 1<<CLOCK_ADJ;
208 * Should check to see if update_timer > 1 day here?
212 * Compute phase part of adjustment here and update clock_adjust.
213 * Note that the equations used here are implicit in the last
214 * two equations in the spec (in particular, look at the equation
215 * for g and figure out how to find the k==1 term given the k==0 term.)
217 adjustment = clock_adjust / (double)(1<<CLOCK_PHASE);
218 clock_adjust -= adjustment;
221 * Now add in the frequency component. Be careful to note that
222 * the ni occurs in the last equation since those equations take
223 * you from 64 second update to 64 second update (ei is the total
224 * adjustment done over 64 seconds) and we're only deal in the
225 * little 4 second adjustment interval here.
227 adjustment += drift_comp / (double)(1<<CLOCK_FREQ);
230 * Add in old adjustment residual
232 adjustment += adj_residual;
235 * Simplify. Adjustment shouldn't be bigger than 2 ms. Hope
236 * writer of spec was truth telling.
239 delta.tv_sec = adjustment;
240 if (debug && delta.tv_sec) abort();
244 #if defined(AFS_AIX32_ENV)
245 /* aix 3.1 ajdtime has unsigned bug. */
246 if (adjustment < 0.0) adj_precision = 5000;
247 else if (adjustment < 1000000.0) adj_precision = 1000;
248 else adj_precision = 5000;
250 delta.tv_usec = ((afs_int32)(adjustment * 1000000.0) / adj_precision)
253 adj_residual = adjustment - (double) delta.tv_usec / 1000000.0;
255 if (delta.tv_usec == 0)
258 if (adjtime(&delta, &olddelta) < 0)
259 syslog(LOG_ERR, "Can't adjust time: %m");
263 printf("adj: %ld us %f %f\n",
264 delta.tv_usec, drift_comp, clock_adjust);
269 #if defined(AFS_HPUX_ENV) && !defined(AFS_HPUX102_ENV)
271 * adjtime for HPUX. Basically a poor man's version of the BSD adjtime call.
272 * It accumulates adjustments until such time as there are enough to use the
273 * stime primitive. This code is ugly. It also does no range checking,
274 * since the assumption is that the adjustments will be (fairly) small.
276 * The basic mechanism is simple: we only have a coarse granularity (1
277 * second) so we accumulate changes until they exceed 1 second. When
278 * that is the case, an adjustment is made which will always be less
279 * than 1 second. If it is a negative adjustment, we won't allow it
280 * to timewarp more frequently than once every ten seconds.
283 static struct timeval cum = {0,0}; /* use to accumulate unadjusted time */
288 printf ("Zeroing aix_adjtime accumulation: %d %d\n",
289 cum.tv_sec, cum.tv_usec);
290 bzero (&cum, sizeof(cum));
293 int adjtime(newdelta, olddelta)
294 struct timeval *newdelta;
295 struct timeval *olddelta;
297 static struct timeval lastbackadj; /* last time adjusted backwards */
298 struct timeval now, new;
301 { /* punt accumulated change if sign of correction changes */
302 int dNeg = ((newdelta->tv_sec < 0 || newdelta->tv_usec < 0) ? 1 : 0);
303 int cNeg = ((cum.tv_sec < 0 || cum.tv_usec < 0) ? 1 : 0);
304 if (dNeg != cNeg) ZeroAIXcum();
309 cum.tv_usec += newdelta->tv_usec;
310 cum.tv_sec += newdelta->tv_sec + cum.tv_usec / MICROSECONDS;
311 cum.tv_usec = (cum.tv_usec < 0) ? -((-cum.tv_usec) % MICROSECONDS) :
312 cum.tv_usec % MICROSECONDS;
314 gettimeofday (&now, (struct timezone *)0);
316 new.tv_sec += cum.tv_sec;
317 new.tv_usec += cum.tv_usec;
318 if (new.tv_usec >= MICROSECONDS) new.tv_sec++, new.tv_usec -= MICROSECONDS;
319 else if (new.tv_usec < 0) new.tv_sec--, new.tv_usec += MICROSECONDS;
321 printf ("cum is %d %d, new is %d %d, now is %d %d\n",
322 cum.tv_sec, cum.tv_usec,
323 new.tv_sec, new.tv_usec, now.tv_sec, now.tv_usec);
326 if (cum.tv_sec || abs(cum.tv_usec) > 2000) {
327 /* wait till accumulated update is at least 2msec since this call
328 * seems to add some jitter. */
329 settimeofday (&new, (struct timezone *)0);
330 if (debug > 4) /* do set before doing I/O */
331 printf ("hp_adjtime: pushing clock by %d usec w/ settimeofday \n",
332 cum.tv_sec*1000000 + cum.tv_usec);
338 #endif /* defined(AFS_HPUX_ENV) */