1 /* $NetBSD: systime.c,v 1.4 2003/12/04 17:22:31 drochner Exp $ */
4 * systime -- routines to fiddle a UNIX clock.
6 * ATTENTION: Get approval from Dave Mills on all changes to this file!
9 #include "ntp_machine.h"
11 #include "ntp_syslog.h"
12 #include "ntp_unixtime.h"
13 #include "ntp_stdlib.h"
14 #include "ntp_random.h"
15 #include "ntpd.h" /* for sys_precision */
21 #ifdef HAVE_SYS_PARAM_H
22 # include <sys/param.h>
26 #endif /* HAVE_UTMP_H */
29 #endif /* HAVE_UTMPX_H */
32 * These routines (get_systime, step_systime, adj_systime) implement an
33 * interface between the system independent NTP clock and the Unix
34 * system clock in various architectures and operating systems.
36 * Time is a precious quantity in these routines and every effort is
37 * made to minimize errors by always rounding toward zero and amortizing
38 * adjustment residues. By default the adjustment quantum is 1 us for
39 * the usual Unix tickadj() system call, but this can be increased if
40 * necessary by the tick configuration command. For instance, when the
41 * adjtime() quantum is a clock tick for a 100-Hz clock, the quantum
44 #if defined RELIANTUNIX_CLOCK || defined SCO5_CLOCK
45 double sys_tick
= 10e-3; /* 10 ms tickadj() */
47 double sys_tick
= 1e-6; /* 1 us tickadj() */
49 double sys_residual
= 0; /* adjustment residue (s) */
54 * get_systime - return system time in NTP timestamp format.
58 l_fp
*now
/* system time */
63 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
64 struct timespec ts
; /* seconds and nanoseconds */
67 * Convert Unix clock from seconds and nanoseconds to seconds.
68 * The bottom is only two bits down, so no need for fuzz.
69 * Some systems don't have that level of precision, however...
71 # ifdef HAVE_CLOCK_GETTIME
72 clock_gettime(CLOCK_REALTIME
, &ts
);
74 getclock(TIMEOFDAY
, &ts
);
76 now
->l_i
= ts
.tv_sec
+ JAN_1970
;
77 dtemp
= ts
.tv_nsec
/ 1e9
;
79 #else /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
80 struct timeval tv
; /* seconds and microseconds */
83 * Convert Unix clock from seconds and microseconds to seconds.
84 * Add in unbiased random fuzz beneath the microsecond.
86 GETTIMEOFDAY(&tv
, NULL
);
87 now
->l_i
= tv
.tv_sec
+ JAN_1970
;
88 dtemp
= tv
.tv_usec
/ 1e6
;
90 #endif /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
93 * ntp_random() produces 31 bits (always nonnegative).
94 * This bit is done only after the precision has been
97 if (sys_precision
!= 0)
98 dtemp
+= (ntp_random() / FRAC
- .5) / (1 <<
102 * Renormalize to seconds past 1900 and fraction.
104 dtemp
+= sys_residual
;
108 } else if (dtemp
< 0) {
113 now
->l_uf
= (u_int32
)dtemp
;
118 * adj_systime - adjust system time by the argument.
120 #if !defined SYS_WINNT
121 int /* 0 okay, 1 error */
123 double now
/* adjustment (s) */
126 struct timeval adjtv
; /* new adjustment */
127 struct timeval oadjtv
; /* residual adjustment */
133 * Most Unix adjtime() implementations adjust the system clock
134 * in microsecond quanta, but some adjust in 10-ms quanta. We
135 * carefully round the adjustment to the nearest quantum, then
136 * adjust in quanta and keep the residue for later.
138 dtemp
= now
+ sys_residual
;
143 adjtv
.tv_sec
= (long)dtemp
;
144 dtemp
-= adjtv
.tv_sec
;
145 ticks
= (long)(dtemp
/ sys_tick
+ .5);
146 adjtv
.tv_usec
= (long)(ticks
* sys_tick
* 1e6
);
147 dtemp
-= adjtv
.tv_usec
/ 1e6
;
148 sys_residual
= dtemp
;
151 * Convert to signed seconds and microseconds for the Unix
152 * adjtime() system call. Note we purposely lose the adjtime()
156 adjtv
.tv_sec
= -adjtv
.tv_sec
;
157 adjtv
.tv_usec
= -adjtv
.tv_usec
;
158 sys_residual
= -sys_residual
;
160 if (adjtv
.tv_sec
!= 0 || adjtv
.tv_usec
!= 0) {
161 if (adjtime(&adjtv
, &oadjtv
) < 0) {
162 msyslog(LOG_ERR
, "adj_systime: %m");
172 * step_systime - step the system clock.
179 struct timeval timetv
, adjtv
, oldtimetv
;
182 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
186 dtemp
= sys_residual
+ now
;
190 adjtv
.tv_sec
= (int32
)dtemp
;
191 adjtv
.tv_usec
= (u_int32
)((dtemp
-
192 (double)adjtv
.tv_sec
) * 1e6
+ .5);
194 adjtv
.tv_sec
= (int32
)dtemp
;
195 adjtv
.tv_usec
= (u_int32
)((dtemp
-
196 (double)adjtv
.tv_sec
) * 1e6
+ .5);
198 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
199 # ifdef HAVE_CLOCK_GETTIME
200 (void) clock_gettime(CLOCK_REALTIME
, &ts
);
202 (void) getclock(TIMEOFDAY
, &ts
);
204 timetv
.tv_sec
= ts
.tv_sec
;
205 timetv
.tv_usec
= ts
.tv_nsec
/ 1000;
206 #else /* not HAVE_GETCLOCK */
207 (void) GETTIMEOFDAY(&timetv
, (struct timezone
*)0);
208 #endif /* not HAVE_GETCLOCK */
214 printf("step_systime: step %.6f residual %.6f\n", now
, sys_residual
);
217 timetv
.tv_sec
-= adjtv
.tv_sec
;
218 timetv
.tv_usec
-= adjtv
.tv_usec
;
219 if (timetv
.tv_usec
< 0) {
221 timetv
.tv_usec
+= 1000000;
224 timetv
.tv_sec
+= adjtv
.tv_sec
;
225 timetv
.tv_usec
+= adjtv
.tv_usec
;
226 if (timetv
.tv_usec
>= 1000000) {
228 timetv
.tv_usec
-= 1000000;
231 if (ntp_set_tod(&timetv
, NULL
) != 0) {
232 msyslog(LOG_ERR
, "step-systime: %m");
237 #ifdef NEED_HPUX_ADJTIME
239 * CHECKME: is this correct when called by ntpdate?????
245 * FreeBSD, for example, has:
247 * char ut_line[UT_LINESIZE];
248 * char ut_name[UT_NAMESIZE];
249 * char ut_host[UT_HOSTSIZE];
252 * and appends line="|", name="date", host="", time for the OLD
253 * and appends line="{", name="date", host="", time for the NEW
256 * Some OSes have utmp, some have utmpx.
260 * Write old and new time entries in utmp and wtmp if step
261 * adjustment is greater than one second.
263 * This might become even Uglier...
265 if (oldtimetv
.tv_sec
!= timetv
.tv_sec
)
275 memset((char *)&ut
, 0, sizeof(ut
));
278 memset((char *)&utx
, 0, sizeof(utx
));
284 # ifdef HAVE_PUTUTLINE
285 ut
.ut_type
= OLD_TIME
;
286 (void)strcpy(ut
.ut_line
, OTIME_MSG
);
287 ut
.ut_time
= oldtimetv
.tv_sec
;
290 ut
.ut_type
= NEW_TIME
;
291 (void)strcpy(ut
.ut_line
, NTIME_MSG
);
292 ut
.ut_time
= timetv
.tv_sec
;
295 # else /* not HAVE_PUTUTLINE */
296 # endif /* not HAVE_PUTUTLINE */
297 #endif /* UPDATE_UTMP */
302 # ifdef HAVE_PUTUTXLINE
303 utx
.ut_type
= OLD_TIME
;
304 (void)strcpy(utx
.ut_line
, OTIME_MSG
);
305 utx
.ut_tv
= oldtimetv
;
308 utx
.ut_type
= NEW_TIME
;
309 (void)strcpy(utx
.ut_line
, NTIME_MSG
);
313 # else /* not HAVE_PUTUTXLINE */
314 # endif /* not HAVE_PUTUTXLINE */
315 #endif /* UPDATE_UTMPX */
320 # ifdef HAVE_PUTUTLINE
322 ut
.ut_type
= OLD_TIME
;
323 (void)strcpy(ut
.ut_line
, OTIME_MSG
);
324 ut
.ut_time
= oldtimetv
.tv_sec
;
326 ut
.ut_type
= NEW_TIME
;
327 (void)strcpy(ut
.ut_line
, NTIME_MSG
);
328 ut
.ut_time
= timetv
.tv_sec
;
331 # else /* not HAVE_PUTUTLINE */
332 # endif /* not HAVE_PUTUTLINE */
333 #endif /* UPDATE_WTMP */
338 # ifdef HAVE_PUTUTXLINE
339 utx
.ut_type
= OLD_TIME
;
340 utx
.ut_tv
= oldtimetv
;
341 (void)strcpy(utx
.ut_line
, OTIME_MSG
);
342 # ifdef HAVE_UPDWTMPX
343 updwtmpx(WTMPX_FILE
, &utx
);
344 # else /* not HAVE_UPDWTMPX */
345 # endif /* not HAVE_UPDWTMPX */
346 # else /* not HAVE_PUTUTXLINE */
347 # endif /* not HAVE_PUTUTXLINE */
348 # ifdef HAVE_PUTUTXLINE
349 utx
.ut_type
= NEW_TIME
;
351 (void)strcpy(utx
.ut_line
, NTIME_MSG
);
352 # ifdef HAVE_UPDWTMPX
353 updwtmpx(WTMPX_FILE
, &utx
);
354 # else /* not HAVE_UPDWTMPX */
355 # endif /* not HAVE_UPDWTMPX */
356 # else /* not HAVE_PUTUTXLINE */
357 # endif /* not HAVE_PUTUTXLINE */
358 #endif /* UPDATE_WTMPX */
366 * Clock routines for the simulator - Harish Nair, with help
369 * get_systime - return the system time in NTP timestamp format
373 l_fp
*now
/* current system time in l_fp */ )
376 * To fool the code that determines the local clock precision,
377 * we advance the clock a minimum of 200 nanoseconds on every
378 * clock read. This is appropriate for a typical modern machine
379 * with nanosecond clocks. Note we make no attempt here to
380 * simulate reading error, since the error is so small. This may
381 * change when the need comes to implement picosecond clocks.
383 if (ntp_node
.ntp_time
== ntp_node
.last_time
)
384 ntp_node
.ntp_time
+= 200e-9;
385 ntp_node
.last_time
= ntp_node
.ntp_time
;
386 DTOLFP(ntp_node
.ntp_time
, now
);
391 * adj_systime - advance or retard the system clock exactly like the
394 int /* always succeeds */
396 double now
/* time adjustment (s) */
399 struct timeval adjtv
; /* new adjustment */
405 * Most Unix adjtime() implementations adjust the system clock
406 * in microsecond quanta, but some adjust in 10-ms quanta. We
407 * carefully round the adjustment to the nearest quantum, then
408 * adjust in quanta and keep the residue for later.
410 dtemp
= now
+ sys_residual
;
415 adjtv
.tv_sec
= (long)dtemp
;
416 dtemp
-= adjtv
.tv_sec
;
417 ticks
= (long)(dtemp
/ sys_tick
+ .5);
418 adjtv
.tv_usec
= (long)(ticks
* sys_tick
* 1e6
);
419 dtemp
-= adjtv
.tv_usec
/ 1e6
;
420 sys_residual
= dtemp
;
423 * Convert to signed seconds and microseconds for the Unix
424 * adjtime() system call. Note we purposely lose the adjtime()
428 adjtv
.tv_sec
= -adjtv
.tv_sec
;
429 adjtv
.tv_usec
= -adjtv
.tv_usec
;
430 sys_residual
= -sys_residual
;
438 * step_systime - step the system clock. We are religious here.
440 int /* always succeeds */
442 double now
/* step adjustment (s) */
447 printf("step_systime: time %.6f adj %.6f\n",
448 ntp_node
.ntp_time
, now
);
450 ntp_node
.ntp_time
+= now
;
455 * node_clock - update the clocks
457 int /* always succeeds */
459 Node
*n
, /* global node pointer */
460 double t
/* node time */
466 * Advance client clock (ntp_time). Advance server clock
467 * (clk_time) adjusted for systematic and random frequency
468 * errors. The random error is a random walk computed as the
469 * integral of samples from a Gaussian distribution.
471 dtemp
= t
- n
->ntp_time
;
473 n
->ntp_time
+= dtemp
;
474 n
->ferr
+= gauss(0, dtemp
* n
->fnse
);
475 n
->clk_time
+= dtemp
* (1 + n
->ferr
);
478 * Perform the adjtime() function. If the adjustment completed
479 * in the previous interval, amortize the entire amount; if not,
480 * carry the leftover to the next interval.
483 if (dtemp
< fabs(n
->adj
)) {
486 n
->ntp_time
-= dtemp
;
489 n
->ntp_time
+= dtemp
;
492 n
->ntp_time
+= n
->adj
;
500 * gauss() - returns samples from a gaussion distribution
502 double /* Gaussian sample */
504 double m
, /* sample mean */
505 double s
/* sample standard deviation (sigma) */
511 * Roll a sample from a Gaussian distribution with mean m and
512 * standard deviation s. For m = 0, s = 1, mean(y) = 0,
517 while ((q1
= drand48()) == 0);
519 return (m
+ s
* sqrt(-2. * log(q1
)) * cos(2. * PI
* q2
));
524 * poisson() - returns samples from a network delay distribution
526 double /* delay sample (s) */
528 double m
, /* fixed propagation delay (s) */
529 double s
/* exponential parameter (mu) */
535 * Roll a sample from a composite distribution with propagation
536 * delay m and exponential distribution time with parameter s.
537 * For m = 0, s = 1, mean(y) = std(y) = 1.
541 while ((q1
= drand48()) == 0);
542 return (m
- s
* log(q1
* s
));