static char *RCSid
= "$Header: /f/osi/others/ntp/RCS/ntp_adjust.c,v 7.1 91/02/22 09:33:46 mrose Interim $";
* This module implemenets the logical Local Clock, as described in section
* 5. of the NTP specification.
* based on the ntp 3.4 code, but modified for OSI etc.
* Revision 7.1 91/02/22 09:33:46 mrose
* Revision 7.0 90/12/10 17:21:27 mrose
* *** empty log message ***
* Revision 1.1 89/06/15 20:36:55 jpo
extern struct sysdata sys
;
#define abs(x) ((x) < 0 ? -(x) : (x))
adj_precision
= kern_tickadj
;
* If you have the "fix" for adjtime() installed in you kernel, you'll
* have to make sure that adj_precision is set to 1 here.
* 5.0 Logical clock procedure
* Only paramter is an offset to vary the clock by, in seconds. We'll either
* arrange for the clock to slew to accomodate the adjustment, or just preform
* a step adjustment if the offset is too large.
* The update which is to be performed is left in the external
* Returns non-zero if clock was reset rather than slewed.
* Many thanks for Dennis Ferguson <dennis@gw.ccie.utoronto.ca> for his
* corrections to my code.
struct timeval delta
, olddelta
;
* Now adjust the logical clock
if (offset
> CLOCK_MAX
|| offset
< -CLOCK_MAX
) {
double steptime
= offset
;
(void) gettimeofday(&tv2
, (struct timezone
*) 0);
steptime
+= tv2
.tv_usec
/ 1000000.0;
tv1
.tv_usec
= (steptime
- tv1
.tv_sec
) * 1000000;
steptime
= (tv1
.tv_sec
+ tv1
.tv_usec
/1000000.0) -
(tv2
.tv_sec
+ tv2
.tv_usec
/1000000.0);
TRACE (2, ("adj_logical: %f %f", offset
, steptime
));
if (settimeofday(&tv1
, (struct timezone
*) 0) < 0) {
advise (LLOG_EXCEPTIONS
, NULLCP
, "Can't set time: %m");
TRACE (1, ("set time of day"));
return (1); /* indicate that step adjustment was done */
* If this is our very first adjustment, don't touch
* the drift compensation (this is f in the spec
* equations), else update using the *old* value
else if (update_timer
> 0) {
ai
= (double)(1<<CLOCK_COMP
) -
(double)(1<<CLOCK_FACTOR
) * ai
;
if (ai
< 1.0) /* max(... , 1.0) */
drift_comp
+= offset
/ (ai
* (double)update_timer
);
* Set the timer to zero. adj_host_clock() increments it
* so we can tell the period between updates.
* Now update the compliance. The compliance is h in the
compliance
+= (offset
- compliance
)/(double)(1<<CLOCK_TRACK
);
delta
.tv_usec
= (offset
- delta
.tv_sec
) * 1000;
(void) adjtime2(&delta
, &olddelta
);
* This is that routine that performs the periodic clock adjustment.
* The procedure is best described in the the NTP document. In a
* nutshell, we prefer to do lots of small evenly spaced adjustments.
* The alternative, one large adjustment, creates two much of a
* clock disruption and as a result oscillation.
* This function is called every 2**CLOCK_ADJ seconds.
struct timeval delta
, olddelta
;
* Add update period into timer so we know how long it
* took between the last update and the next one.
* Should check to see if update_timer > 1 day here?
* Compute phase part of adjustment here and update clock_adjust.
* Note that the equations used here are implicit in the last
* two equations in the spec (in particular, look at the equation
* for g and figure out how to find the k==1 term given the k==0 term.)
adjustment
= clock_adjust
/ (double)(1<<CLOCK_PHASE
);
clock_adjust
-= adjustment
;
* Now add in the frequency component. Be careful to note that
* the ni occurs in the last equation since those equations take
* you from 64 second update to 64 second update (ei is the total
* adjustment done over 64 seconds) and we're only deal in the
* little 4 second adjustment interval here.
adjustment
+= drift_comp
/ (double)(1<<CLOCK_FREQ
);
* Add in old adjustment residual
adjustment
+= adj_residual
;
* Simplify. Adjustment shouldn't be bigger than 2 ms. Hope
* writer of spec was truth telling.
delta
.tv_sec
= adjustment
;
if (debug
&& delta
.tv_sec
) abort();
delta
.tv_usec
= ((long)(adjustment
* 1000000.0) / adj_precision
)
adj_residual
= adjustment
- (double) delta
.tv_usec
/ 1000000.0;
if (adjtime(&delta
, &olddelta
) < 0)
advise (LLOG_EXCEPTIONS
, NULLCP
, "Can't adjust time: %m");
TRACE (2, ("adj: %ld us %f %f",
delta
.tv_usec
, drift_comp
, clock_adjust
));