Start development on 386BSD 0.0
[unix-history] / .ref-BSD-4_3_Net_2 / usr / src / contrib / isode / others / ntp / ntp_adjust.c
CommitLineData
9e8e5516
C
1#ifndef lint
2static char *RCSid = "$Header: /f/osi/others/ntp/RCS/ntp_adjust.c,v 7.1 91/02/22 09:33:46 mrose Interim $";
3#endif
4
5/*
6 * This module implemenets the logical Local Clock, as described in section
7 * 5. of the NTP specification.
8 * based on the ntp 3.4 code, but modified for OSI etc.
9 *
10 * $Log: ntp_adjust.c,v $
11 * Revision 7.1 91/02/22 09:33:46 mrose
12 * Interim 6.8
13 *
14 * Revision 7.0 90/12/10 17:21:27 mrose
15 * *** empty log message ***
16 *
17 * Revision 1.1 89/06/15 20:36:55 jpo
18 * Initial revision
19 *
20 *
21 */
22
23#include "ntp.h"
24
25#ifdef DEBUG
26extern int debug;
27#endif
28
29extern int doset;
30extern int kern_tickadj;
31extern char *ntoa();
32extern struct sysdata sys;
33extern LLog *pgm_log;
34
35double drift_comp = 0.0,
36 compliance,
37 clock_adjust;
38long update_timer = 0;
39
40int adj_precision;
41double adj_residual;
42int firstpass = 1;
43
44#define abs(x) ((x) < 0 ? -(x) : (x))
45
46void
47init_logical_clock()
48{
49 if (kern_tickadj)
50 adj_precision = kern_tickadj;
51 else
52 adj_precision = 1;
53 /*
54 * If you have the "fix" for adjtime() installed in you kernel, you'll
55 * have to make sure that adj_precision is set to 1 here.
56 */
57}
58
59
60/*
61 * 5.0 Logical clock procedure
62 *
63 * Only paramter is an offset to vary the clock by, in seconds. We'll either
64 * arrange for the clock to slew to accomodate the adjustment, or just preform
65 * a step adjustment if the offset is too large.
66 *
67 * The update which is to be performed is left in the external
68 * clock_adjust.
69 *
70 * Returns non-zero if clock was reset rather than slewed.
71 *
72 * Many thanks for Dennis Ferguson <dennis@gw.ccie.utoronto.ca> for his
73 * corrections to my code.
74 */
75
76int
77adj_logical(offset)
78 double offset;
79{
80 struct timeval tv1, tv2;
81#ifdef XADJTIME2
82 struct timeval delta, olddelta;
83#endif
84
85 /*
86 * Now adjust the logical clock
87 */
88 if (!doset)
89 return 0;
90
91 adj_residual = 0.0;
92 if (offset > CLOCK_MAX || offset < -CLOCK_MAX) {
93 double steptime = offset;
94
95 (void) gettimeofday(&tv2, (struct timezone *) 0);
96 steptime += tv2.tv_sec;
97 steptime += tv2.tv_usec / 1000000.0;
98 tv1.tv_sec = steptime;
99 tv1.tv_usec = (steptime - tv1.tv_sec) * 1000000;
100#ifdef DEBUG
101 if (debug > 2) {
102 steptime = (tv1.tv_sec + tv1.tv_usec/1000000.0) -
103 (tv2.tv_sec + tv2.tv_usec/1000000.0);
104 TRACE (2, ("adj_logical: %f %f", offset, steptime));
105 }
106#endif
107 if (settimeofday(&tv1, (struct timezone *) 0) < 0) {
108 advise (LLOG_EXCEPTIONS, NULLCP, "Can't set time: %m");
109 return(-1);
110 }
111 else {
112 TRACE (1, ("set time of day"));
113 }
114 clock_adjust = 0.0;
115 firstpass = 1;
116 update_timer = 0;
117 return (1); /* indicate that step adjustment was done */
118 } else {
119 double ai;
120
121 /*
122 * If this is our very first adjustment, don't touch
123 * the drift compensation (this is f in the spec
124 * equations), else update using the *old* value
125 * of the compliance.
126 */
127 clock_adjust = offset;
128 if (firstpass)
129 firstpass = 0;
130 else if (update_timer > 0) {
131 ai = abs(compliance);
132 ai = (double)(1<<CLOCK_COMP) -
133 (double)(1<<CLOCK_FACTOR) * ai;
134 if (ai < 1.0) /* max(... , 1.0) */
135 ai = 1.0;
136 drift_comp += offset / (ai * (double)update_timer);
137 }
138
139 /*
140 * Set the timer to zero. adj_host_clock() increments it
141 * so we can tell the period between updates.
142 */
143 update_timer = 0;
144
145 /*
146 * Now update the compliance. The compliance is h in the
147 * equations.
148 */
149 compliance += (offset - compliance)/(double)(1<<CLOCK_TRACK);
150
151#ifdef XADJTIME2
152 delta.tv_sec = offset;
153 delta.tv_usec = (offset - delta.tv_sec) * 1000;
154 (void) adjtime2(&delta, &olddelta);
155#endif
156 return(0);
157 }
158}
159
160#ifndef XADJTIME2
161extern int adjtime();
162
163/*
164 * This is that routine that performs the periodic clock adjustment.
165 * The procedure is best described in the the NTP document. In a
166 * nutshell, we prefer to do lots of small evenly spaced adjustments.
167 * The alternative, one large adjustment, creates two much of a
168 * clock disruption and as a result oscillation.
169 *
170 * This function is called every 2**CLOCK_ADJ seconds.
171 *
172 */
173
174/*
175 * global for debugging?
176 */
177double adjustment;
178
179void
180adj_host_clock(n)
181int n;
182{
183
184 struct timeval delta, olddelta;
185
186 if (!doset)
187 return;
188
189 /*
190 * Add update period into timer so we know how long it
191 * took between the last update and the next one.
192 */
193 update_timer += n;
194 /*
195 * Should check to see if update_timer > 1 day here?
196 */
197
198 /*
199 * Compute phase part of adjustment here and update clock_adjust.
200 * Note that the equations used here are implicit in the last
201 * two equations in the spec (in particular, look at the equation
202 * for g and figure out how to find the k==1 term given the k==0 term.)
203 */
204 adjustment = clock_adjust / (double)(1<<CLOCK_PHASE);
205 clock_adjust -= adjustment;
206
207 /*
208 * Now add in the frequency component. Be careful to note that
209 * the ni occurs in the last equation since those equations take
210 * you from 64 second update to 64 second update (ei is the total
211 * adjustment done over 64 seconds) and we're only deal in the
212 * little 4 second adjustment interval here.
213 */
214 adjustment += drift_comp / (double)(1<<CLOCK_FREQ);
215
216 /*
217 * Add in old adjustment residual
218 */
219 adjustment += adj_residual;
220
221 /*
222 * Simplify. Adjustment shouldn't be bigger than 2 ms. Hope
223 * writer of spec was truth telling.
224 */
225#ifdef DEBUG
226 delta.tv_sec = adjustment;
227 if (debug && delta.tv_sec) abort();
228#else
229 delta.tv_sec = 0;
230#endif
231 delta.tv_usec = ((long)(adjustment * 1000000.0) / adj_precision)
232 * adj_precision;
233
234 adj_residual = adjustment - (double) delta.tv_usec / 1000000.0;
235
236 if (delta.tv_usec == 0)
237 return;
238
239 if (adjtime(&delta, &olddelta) < 0)
240 advise (LLOG_EXCEPTIONS, NULLCP, "Can't adjust time: %m");
241
242 TRACE (2, ("adj: %ld us %f %f",
243 delta.tv_usec, drift_comp, clock_adjust));
244}
245#endif