/src/ntp-dev/ntpd/ntp_timer.c
Line | Count | Source |
1 | | /* |
2 | | * ntp_timer.c - event timer support routines |
3 | | */ |
4 | | #ifdef HAVE_CONFIG_H |
5 | | # include <config.h> |
6 | | #endif |
7 | | |
8 | | #include "ntp_machine.h" |
9 | | #include "ntpd.h" |
10 | | #include "ntp_stdlib.h" |
11 | | #include "ntp_calendar.h" |
12 | | #include "ntp_leapsec.h" |
13 | | |
14 | | #if defined(HAVE_IO_COMPLETION_PORT) |
15 | | # include "ntp_iocompletionport.h" |
16 | | # include "ntp_timer.h" |
17 | | #endif |
18 | | |
19 | | #include <stdio.h> |
20 | | #include <signal.h> |
21 | | #ifdef HAVE_SYS_SIGNAL_H |
22 | | # include <sys/signal.h> |
23 | | #endif |
24 | | #ifdef HAVE_UNISTD_H |
25 | | # include <unistd.h> |
26 | | #endif |
27 | | |
28 | | #ifdef KERNEL_PLL |
29 | | #include "ntp_syscall.h" |
30 | | #endif /* KERNEL_PLL */ |
31 | | |
32 | | #ifdef AUTOKEY |
33 | | #include <openssl/rand.h> |
34 | | #endif /* AUTOKEY */ |
35 | | |
36 | | |
37 | | /* TC_ERR represents the timer_create() error return value. */ |
38 | | #ifdef SYS_VXWORKS |
39 | | #define TC_ERR ERROR |
40 | | #else |
41 | | #define TC_ERR (-1) |
42 | | #endif |
43 | | |
44 | | |
45 | | static void check_leapsec(u_int32, const time_t*, int/*BOOL*/); |
46 | | |
47 | | /* |
48 | | * These routines provide support for the event timer. The timer is |
49 | | * implemented by a signal routine which sets a flag once every |
50 | | * second, and a timer routine which is called when the mainline code |
51 | | * gets around to seeing the flag. The timer routine dispatches the |
52 | | * clock adjustment code if its time has come, then searches the timer |
53 | | * queue for expiries which are dispatched to the transmit procedure. |
54 | | * Finally, we call the hourly procedure to do cleanup and print a |
55 | | * message. |
56 | | */ |
57 | | |
58 | | /* |
59 | | * Initializing flag. All async routines watch this and only do their |
60 | | * thing when it is clear. |
61 | | */ |
62 | | int initializing; |
63 | | |
64 | | /* |
65 | | * Alarm flag. The mainline code imports this. |
66 | | */ |
67 | | volatile int alarm_flag; |
68 | | |
69 | | /* |
70 | | * The counters and timeouts |
71 | | */ |
72 | | u_long endpt_scan_timer; /* interface update timer */ |
73 | | static u_long adjust_timer; /* second timer */ |
74 | | static u_long stats_timer; /* stats timer */ |
75 | | static u_long leapf_timer; /* Report leapfile problems once/day */ |
76 | | static u_long huffpuff_timer; /* huff-n'-puff timer */ |
77 | | static u_long worker_idle_timer;/* next check for idle intres */ |
78 | | int endpt_scan_period; /* init_io() sets def. 301s */ |
79 | | u_long leapsec; /* seconds to next leap (proximity class) */ |
80 | | int leapdif; /* TAI difference step at next leap second*/ |
81 | | u_long orphwait; /* orphan wait time */ |
82 | | #ifdef AUTOKEY |
83 | | static u_long revoke_timer; /* keys revoke timer */ |
84 | | static u_long keys_timer; /* session key timer */ |
85 | | u_char sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */ |
86 | | u_char sys_automax = NTP_AUTOMAX; /* key list timeout (log2 s) */ |
87 | | #endif /* AUTOKEY */ |
88 | | |
89 | | /* |
90 | | * Statistics counter for the interested. |
91 | | */ |
92 | | volatile u_long alarm_overflow; |
93 | | |
94 | | u_long current_time; /* seconds since startup */ |
95 | | |
96 | | /* |
97 | | * Stats. Number of overflows and number of calls to transmit(). |
98 | | */ |
99 | | u_long timer_timereset; |
100 | | u_long timer_overflows; |
101 | | u_long timer_xmtcalls; |
102 | | |
103 | | #if defined(VMS) |
104 | | static int vmstimer[2]; /* time for next timer AST */ |
105 | | static int vmsinc[2]; /* timer increment */ |
106 | | #endif /* VMS */ |
107 | | |
108 | | #ifdef SYS_WINNT |
109 | | HANDLE WaitableTimerHandle; |
110 | | #else |
111 | | static RETSIGTYPE alarming (int); |
112 | | #endif /* SYS_WINNT */ |
113 | | |
114 | | #if !defined(VMS) |
115 | | # if !defined SYS_WINNT || defined(SYS_CYGWIN32) |
116 | | # ifdef HAVE_TIMER_CREATE |
117 | | static timer_t timer_id; |
118 | | typedef struct itimerspec intervaltimer; |
119 | | # define itv_frac tv_nsec |
120 | | # else |
121 | | typedef struct itimerval intervaltimer; |
122 | 2 | # define itv_frac tv_usec |
123 | | # endif |
124 | | intervaltimer itimer; |
125 | | # endif |
126 | | #endif |
127 | | |
128 | | #if !defined(SYS_WINNT) && !defined(VMS) |
129 | | void set_timer_or_die(const intervaltimer *); |
130 | | #endif |
131 | | |
132 | | |
133 | | #if !defined(SYS_WINNT) && !defined(VMS) |
134 | | void |
135 | | set_timer_or_die( |
136 | | const intervaltimer * ptimer |
137 | | ) |
138 | 1 | { |
139 | 1 | const char * setfunc; |
140 | 1 | int rc; |
141 | | |
142 | | # ifdef HAVE_TIMER_CREATE |
143 | | setfunc = "timer_settime"; |
144 | | rc = timer_settime(timer_id, 0, &itimer, NULL); |
145 | | # else |
146 | 1 | setfunc = "setitimer"; |
147 | 1 | rc = setitimer(ITIMER_REAL, &itimer, NULL); |
148 | 1 | # endif |
149 | 1 | if (-1 == rc) { |
150 | 0 | msyslog(LOG_ERR, "interval timer %s failed, %m", |
151 | 0 | setfunc); |
152 | 0 | exit(1); |
153 | 0 | } |
154 | 1 | } |
155 | | #endif /* !SYS_WINNT && !VMS */ |
156 | | |
157 | | |
158 | | /* |
159 | | * reinit_timer - reinitialize interval timer after a clock step. |
160 | | */ |
161 | | void |
162 | | reinit_timer(void) |
163 | 0 | { |
164 | 0 | #if !defined(SYS_WINNT) && !defined(VMS) |
165 | 0 | ZERO(itimer); |
166 | | # ifdef HAVE_TIMER_CREATE |
167 | | timer_gettime(timer_id, &itimer); |
168 | | # else |
169 | 0 | getitimer(ITIMER_REAL, &itimer); |
170 | 0 | # endif |
171 | 0 | if (itimer.it_value.tv_sec < 0 || |
172 | 0 | itimer.it_value.tv_sec > (1 << EVENT_TIMEOUT)) |
173 | 0 | itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT); |
174 | 0 | if (itimer.it_value.itv_frac < 0) |
175 | 0 | itimer.it_value.itv_frac = 0; |
176 | 0 | if (0 == itimer.it_value.tv_sec && |
177 | 0 | 0 == itimer.it_value.itv_frac) |
178 | 0 | itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT); |
179 | 0 | itimer.it_interval.tv_sec = (1 << EVENT_TIMEOUT); |
180 | 0 | itimer.it_interval.itv_frac = 0; |
181 | 0 | set_timer_or_die(&itimer); |
182 | 0 | # endif /* VMS */ |
183 | 0 | } |
184 | | |
185 | | |
186 | | /* |
187 | | * init_timer - initialize the timer data structures |
188 | | */ |
189 | | void |
190 | | init_timer(void) |
191 | 1 | { |
192 | | /* |
193 | | * Initialize... |
194 | | */ |
195 | 1 | alarm_flag = FALSE; |
196 | 1 | alarm_overflow = 0; |
197 | 1 | adjust_timer = 1; |
198 | 1 | stats_timer = SECSPERHR; |
199 | 1 | leapf_timer = SECSPERDAY; |
200 | 1 | huffpuff_timer = 0; |
201 | 1 | endpt_scan_timer = 0; |
202 | 1 | current_time = 0; |
203 | 1 | timer_overflows = 0; |
204 | 1 | timer_xmtcalls = 0; |
205 | 1 | timer_timereset = 0; |
206 | | |
207 | 1 | #ifndef SYS_WINNT |
208 | | /* |
209 | | * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT |
210 | | * seconds from now and they continue on every 2**EVENT_TIMEOUT |
211 | | * seconds. |
212 | | */ |
213 | 1 | # ifndef VMS |
214 | | # ifdef HAVE_TIMER_CREATE |
215 | | if (TC_ERR == timer_create(CLOCK_REALTIME, NULL, &timer_id)) { |
216 | | msyslog(LOG_ERR, "timer_create failed, %m"); |
217 | | exit(1); |
218 | | } |
219 | | # endif |
220 | 1 | signal_no_reset(SIGALRM, alarming); |
221 | 1 | itimer.it_interval.tv_sec = |
222 | 1 | itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT); |
223 | 1 | itimer.it_interval.itv_frac = itimer.it_value.itv_frac = 0; |
224 | 1 | set_timer_or_die(&itimer); |
225 | | # else /* VMS follows */ |
226 | | vmsinc[0] = 10000000; /* 1 sec */ |
227 | | vmsinc[1] = 0; |
228 | | lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc); |
229 | | |
230 | | sys$gettim(&vmstimer); /* that's "now" as abstime */ |
231 | | |
232 | | lib$addx(&vmsinc, &vmstimer, &vmstimer); |
233 | | sys$setimr(0, &vmstimer, alarming, alarming, 0); |
234 | | # endif /* VMS */ |
235 | | #else /* SYS_WINNT follows */ |
236 | | /* |
237 | | * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds |
238 | | * Under Windows/NT, |
239 | | */ |
240 | | |
241 | | WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL); |
242 | | if (WaitableTimerHandle == NULL) { |
243 | | msyslog(LOG_ERR, "CreateWaitableTimer failed: %m"); |
244 | | exit(1); |
245 | | } |
246 | | else { |
247 | | DWORD Period; |
248 | | LARGE_INTEGER DueTime; |
249 | | BOOL rc; |
250 | | |
251 | | Period = (1 << EVENT_TIMEOUT) * 1000; |
252 | | DueTime.QuadPart = Period * 10000ll; |
253 | | rc = SetWaitableTimer(WaitableTimerHandle, &DueTime, |
254 | | Period, NULL, NULL, FALSE); |
255 | | if (!rc) { |
256 | | msyslog(LOG_ERR, "SetWaitableTimer failed: %m"); |
257 | | exit(1); |
258 | | } |
259 | | } |
260 | | |
261 | | #endif /* SYS_WINNT */ |
262 | 1 | } |
263 | | |
264 | | |
265 | | /* |
266 | | * intres_timeout_req(s) is invoked in the parent to schedule an idle |
267 | | * timeout to fire in s seconds, if not reset earlier by a call to |
268 | | * intres_timeout_req(0), which clears any pending timeout. When the |
269 | | * timeout expires, worker_idle_timer_fired() is invoked (again, in the |
270 | | * parent). |
271 | | * |
272 | | * sntp and ntpd each provide implementations adapted to their timers. |
273 | | */ |
274 | | void |
275 | | intres_timeout_req( |
276 | | u_int seconds /* 0 cancels */ |
277 | | ) |
278 | 0 | { |
279 | | #if defined(HAVE_DROPROOT) && defined(NEED_EARLY_FORK) |
280 | | if (droproot) { |
281 | | worker_idle_timer = 0; |
282 | | return; |
283 | | } |
284 | | #endif |
285 | 0 | if (0 == seconds) { |
286 | 0 | worker_idle_timer = 0; |
287 | 0 | return; |
288 | 0 | } |
289 | 0 | worker_idle_timer = current_time + seconds; |
290 | 0 | } |
291 | | |
292 | | |
293 | | /* |
294 | | * timer - event timer |
295 | | */ |
296 | | void |
297 | | timer(void) |
298 | 0 | { |
299 | 0 | struct peer* p; |
300 | 0 | struct peer* next_peer; |
301 | 0 | l_fp now; |
302 | 0 | time_t tnow; |
303 | | |
304 | | /* |
305 | | * The basic timerevent is one second. This is used to adjust the |
306 | | * system clock in time and frequency, implement the kiss-o'-death |
307 | | * function and the association polling function. |
308 | | */ |
309 | 0 | current_time++; |
310 | 0 | if (adjust_timer <= current_time) { |
311 | 0 | adjust_timer += 1; |
312 | 0 | adj_host_clock(); |
313 | 0 | #ifdef REFCLOCK |
314 | 0 | for (p = peer_list; p != NULL; p = next_peer) { |
315 | 0 | next_peer = p->p_link; |
316 | 0 | if (FLAG_REFCLOCK & p->flags) |
317 | 0 | refclock_timer(p); |
318 | 0 | } |
319 | 0 | #endif /* REFCLOCK */ |
320 | 0 | } |
321 | | |
322 | | /* |
323 | | * Now dispatch any peers whose event timer has expired. Be |
324 | | * careful here, since the peer structure might go away as the |
325 | | * result of the call. |
326 | | */ |
327 | 0 | for (p = peer_list; p != NULL; p = next_peer) { |
328 | 0 | next_peer = p->p_link; |
329 | | |
330 | | /* |
331 | | * Restrain the non-burst packet rate not more |
332 | | * than one packet every 16 seconds. This is |
333 | | * usually tripped using iburst and minpoll of |
334 | | * 128 s or less. |
335 | | */ |
336 | 0 | if (p->throttle > 0) { |
337 | 0 | p->throttle--; |
338 | 0 | } |
339 | 0 | if (p->nextdate <= current_time) { |
340 | 0 | #ifdef REFCLOCK |
341 | 0 | if (FLAG_REFCLOCK & p->flags) { |
342 | 0 | refclock_transmit(p); |
343 | 0 | } else |
344 | 0 | #endif /* REFCLOCK */ |
345 | 0 | { |
346 | 0 | transmit(p); |
347 | 0 | } |
348 | 0 | } |
349 | 0 | } |
350 | | |
351 | | /* |
352 | | * Orphan mode is active when enabled and when no servers less |
353 | | * than the orphan stratum are available. A server with no other |
354 | | * synchronization source is an orphan. It shows offset zero and |
355 | | * reference ID the loopback address. |
356 | | * |
357 | | * [bug 3644] If the orphan stratum is >= STRATUM_UNSPEC, we |
358 | | * have to do it a bit different. 'clock_select()' simply |
359 | | * tiptoed home, but since we're unsync'd and have no peer, we |
360 | | * should eventually declare we're out of sync. Otherwise we |
361 | | * would persistently claim we're good, and we're everything but |
362 | | * that... |
363 | | * |
364 | | * XXX: do we want to log an event about this? |
365 | | */ |
366 | 0 | if (sys_peer == NULL && current_time > orphwait) { |
367 | 0 | if (sys_orphan < STRATUM_UNSPEC) { |
368 | 0 | if (sys_leap == LEAP_NOTINSYNC) { |
369 | 0 | set_sys_leap(LEAP_NOWARNING); |
370 | 0 | #ifdef AUTOKEY |
371 | 0 | if (crypto_flags) |
372 | 0 | crypto_update(); |
373 | 0 | #endif /* AUTOKEY */ |
374 | 0 | } |
375 | 0 | sys_stratum = (u_char)sys_orphan; |
376 | 0 | } |
377 | 0 | else { |
378 | 0 | if (sys_leap != LEAP_NOTINSYNC) { |
379 | 0 | set_sys_leap(LEAP_NOTINSYNC); |
380 | 0 | msyslog(LOG_WARNING, "%s", |
381 | 0 | "no peer for too long, server running free now"); |
382 | 0 | } |
383 | 0 | sys_stratum = STRATUM_UNSPEC; |
384 | 0 | } |
385 | 0 | if (sys_stratum > 1) |
386 | 0 | sys_refid = htonl(LOOPBACKADR); |
387 | 0 | else |
388 | 0 | memcpy(&sys_refid, "ORPH", 4); |
389 | 0 | sys_offset = 0; |
390 | 0 | sys_rootdelay = 0; |
391 | 0 | sys_rootdisp = 0; |
392 | 0 | } |
393 | |
|
394 | 0 | get_systime(&now); |
395 | 0 | time(&tnow); |
396 | | |
397 | | /* |
398 | | * Leapseconds. Get time and defer to worker if either something |
399 | | * is imminent or every 8th second. |
400 | | */ |
401 | 0 | if (leapsec > LSPROX_NOWARN || 0 == (current_time & 7)) |
402 | 0 | check_leapsec( now.l_ui |
403 | 0 | , &tnow |
404 | 0 | , (sys_leap == LEAP_NOTINSYNC)); |
405 | 0 | if (sys_leap != LEAP_NOTINSYNC) { |
406 | 0 | if (leapsec >= LSPROX_ANNOUNCE && leapdif) { |
407 | 0 | if (leapdif > 0) { |
408 | 0 | set_sys_leap(LEAP_ADDSECOND); |
409 | 0 | } else { |
410 | 0 | set_sys_leap(LEAP_DELSECOND); |
411 | 0 | } |
412 | 0 | } else { |
413 | 0 | set_sys_leap(LEAP_NOWARNING); |
414 | 0 | } |
415 | 0 | } |
416 | | |
417 | | /* |
418 | | * Update huff-n'-puff filter. |
419 | | */ |
420 | 0 | if (huffpuff_timer <= current_time) { |
421 | 0 | huffpuff_timer += HUFFPUFF; |
422 | 0 | huffpuff(); |
423 | 0 | } |
424 | |
|
425 | 0 | #ifdef AUTOKEY |
426 | | /* |
427 | | * Garbage collect expired keys. |
428 | | */ |
429 | 0 | if (keys_timer <= current_time) { |
430 | 0 | keys_timer += (1UL << sys_automax); |
431 | 0 | auth_agekeys(); |
432 | 0 | } |
433 | | |
434 | | /* |
435 | | * Generate new private value. This causes all associations |
436 | | * to regenerate cookies. |
437 | | */ |
438 | 0 | if (revoke_timer && revoke_timer <= current_time) { |
439 | 0 | revoke_timer += (1UL << sys_revoke); |
440 | 0 | RAND_bytes((u_char *)&sys_private, sizeof(sys_private)); |
441 | 0 | } |
442 | 0 | #endif /* AUTOKEY */ |
443 | | |
444 | | /* |
445 | | * Network interface rescan timer |
446 | | */ |
447 | 0 | if (endpt_scan_timer && endpt_scan_timer <= current_time) { |
448 | 0 | if (no_periodic_scan) { |
449 | 0 | endpt_scan_timer = 0; |
450 | 0 | DPRINTF(2, ("timer: network interface rescan disabled\n")); |
451 | 0 | } else { |
452 | 0 | endpt_scan_timer = current_time |
453 | 0 | + endpt_scan_period; |
454 | 0 | DPRINTF(2, ("timer: network interface rescan in %d seconds\n", endpt_scan_period)); |
455 | 0 | } |
456 | 0 | interface_update(NULL, NULL); |
457 | 0 | } |
458 | |
|
459 | 0 | if (worker_idle_timer && worker_idle_timer <= current_time) { |
460 | 0 | worker_idle_timer_fired(); |
461 | 0 | } |
462 | | /* |
463 | | * Finally, write hourly stats and do the hourly |
464 | | * and daily leapfile checks. |
465 | | */ |
466 | 0 | if (stats_timer <= current_time) { |
467 | 0 | stats_timer += SECSPERHR; |
468 | 0 | write_stats(); |
469 | 0 | if (leapf_timer <= current_time) { |
470 | 0 | leapf_timer += SECSPERDAY; |
471 | 0 | check_leap_file(TRUE, now.l_ui, &tnow); |
472 | 0 | } else { |
473 | 0 | check_leap_file(FALSE, now.l_ui, &tnow); |
474 | 0 | } |
475 | 0 | } |
476 | 0 | } |
477 | | |
478 | | |
479 | | #ifndef SYS_WINNT |
480 | | /* |
481 | | * alarming - tell the world we've been alarmed |
482 | | */ |
483 | | static RETSIGTYPE |
484 | | alarming( |
485 | | int sig |
486 | | ) |
487 | 0 | { |
488 | 0 | # ifdef DEBUG |
489 | 0 | const char *msg = "alarming: initializing TRUE\n"; |
490 | 0 | # endif |
491 | |
|
492 | 0 | if (!initializing) { |
493 | 0 | if (alarm_flag) { |
494 | 0 | alarm_overflow++; |
495 | 0 | # ifdef DEBUG |
496 | 0 | msg = "alarming: overflow\n"; |
497 | 0 | # endif |
498 | 0 | } else { |
499 | 0 | # ifndef VMS |
500 | 0 | alarm_flag++; |
501 | | # else |
502 | | /* VMS AST routine, increment is no good */ |
503 | | alarm_flag = 1; |
504 | | # endif |
505 | 0 | # ifdef DEBUG |
506 | 0 | msg = "alarming: normal\n"; |
507 | 0 | # endif |
508 | 0 | } |
509 | 0 | } |
510 | | # ifdef VMS |
511 | | lib$addx(&vmsinc, &vmstimer, &vmstimer); |
512 | | sys$setimr(0, &vmstimer, alarming, alarming, 0); |
513 | | # endif |
514 | 0 | # ifdef DEBUG |
515 | 0 | if (debug >= 4) |
516 | 0 | (void)(-1 == write(1, msg, strlen(msg))); |
517 | 0 | # endif |
518 | 0 | } |
519 | | #endif /* SYS_WINNT */ |
520 | | |
521 | | |
522 | | /* |
523 | | * timer_clr_stats - clear timer module stat counters |
524 | | */ |
525 | | void |
526 | | timer_clr_stats(void) |
527 | 0 | { |
528 | 0 | timer_overflows = 0; |
529 | 0 | timer_xmtcalls = 0; |
530 | 0 | timer_timereset = current_time; |
531 | 0 | } |
532 | | |
533 | | |
534 | | static void |
535 | | check_leap_sec_in_progress( |
536 | | const leap_result_t *lsdata |
537 | | ) |
538 | 0 | { |
539 | 0 | int prv_leap_sec_in_progress = leap_sec_in_progress; |
540 | |
|
541 | 0 | leap_sec_in_progress = lsdata->tai_diff && (lsdata->ddist < 3); |
542 | | |
543 | | /* if changed we have to update the leap bits sent to clients */ |
544 | 0 | if (leap_sec_in_progress != prv_leap_sec_in_progress) { |
545 | 0 | set_sys_leap(sys_leap); |
546 | 0 | } |
547 | 0 | } |
548 | | |
549 | | |
550 | | static void |
551 | | check_leapsec( |
552 | | u_int32 now, |
553 | | const time_t * tpiv, |
554 | | int/*BOOL*/ reset |
555 | | ) |
556 | 0 | { |
557 | 0 | static const char leapmsg_p_step[] = |
558 | 0 | "Positive leap second, stepped backward."; |
559 | 0 | static const char leapmsg_p_slew[] = |
560 | 0 | "Positive leap second, no step correction. " |
561 | 0 | "System clock will be inaccurate for a long time."; |
562 | |
|
563 | 0 | static const char leapmsg_n_step[] = |
564 | 0 | "Negative leap second, stepped forward."; |
565 | 0 | static const char leapmsg_n_slew[] = |
566 | 0 | "Negative leap second, no step correction. " |
567 | 0 | "System clock will be inaccurate for a long time."; |
568 | |
|
569 | 0 | leap_result_t lsdata; |
570 | 0 | u_int32 lsprox; |
571 | 0 | #ifdef AUTOKEY |
572 | 0 | int/*BOOL*/ update_autokey = FALSE; |
573 | 0 | #endif |
574 | |
|
575 | 0 | #ifndef SYS_WINNT /* WinNT port has its own leap second handling */ |
576 | 0 | # ifdef KERNEL_PLL |
577 | 0 | leapsec_electric(pll_control && kern_enable); |
578 | | # else |
579 | | leapsec_electric(0); |
580 | | # endif |
581 | 0 | #endif /* !SYS_WINNT */ |
582 | |
|
583 | | #ifdef LEAP_SMEAR |
584 | | leap_smear.enabled = leap_smear_intv != 0; |
585 | | #endif |
586 | 0 | if (reset) { |
587 | 0 | lsprox = LSPROX_NOWARN; |
588 | 0 | leapsec_reset_frame(); |
589 | 0 | ZERO(lsdata); |
590 | 0 | } else { |
591 | 0 | int fired; |
592 | |
|
593 | 0 | fired = leapsec_query(&lsdata, now, tpiv); |
594 | |
|
595 | 0 | DPRINTF(3, ("*** leapsec_query: fired %i, now %u (0x%08X)," |
596 | 0 | " tai_diff %i, ddist %u\n", |
597 | 0 | fired, now, now, lsdata.tai_diff, lsdata.ddist)); |
598 | |
|
599 | | #ifdef LEAP_SMEAR |
600 | | leap_smear.in_progress = FALSE; |
601 | | leap_smear.doffset = 0.0; |
602 | | |
603 | | if (leap_smear.enabled) { |
604 | | if (lsdata.tai_diff) { |
605 | | if (0 == leap_smear.interval) { |
606 | | leap_smear.interval = leap_smear_intv; |
607 | | leap_smear.intv_end = lsdata.ttime.Q_s; |
608 | | leap_smear.intv_start = leap_smear.intv_end - leap_smear.interval; |
609 | | DPRINTF(1, ("*** leapsec_query: setting leap_smear interval %li, begin %.0f, end %.0f\n", |
610 | | leap_smear.interval, leap_smear.intv_start, leap_smear.intv_end)); |
611 | | } |
612 | | } else { |
613 | | if (leap_smear.interval) { |
614 | | DPRINTF(1, ("*** leapsec_query: clearing leap_smear interval\n")); |
615 | | leap_smear.interval = 0; |
616 | | } |
617 | | } |
618 | | |
619 | | if (leap_smear.interval) { |
620 | | double dtemp = now; |
621 | | |
622 | | if (dtemp >= leap_smear.intv_start && dtemp <= leap_smear.intv_end) { |
623 | | double leap_smear_time = dtemp - leap_smear.intv_start; |
624 | | #if 0 |
625 | | /* linear interpolation */ |
626 | | leap_smear.doffset = -(leap_smear_time * lsdata.tai_diff / leap_smear.interval); |
627 | | #else |
628 | | /* Google approach : lie(t) = (1.0 - cos(pi * t / w)) / 2.0 */ |
629 | | leap_smear.doffset = -((double) lsdata.tai_diff - cos( M_PI * leap_smear_time / leap_smear.interval)) / 2.0; |
630 | | #endif |
631 | | /* |
632 | | * TODO see if we're inside an inserted leap second, so we need to compute |
633 | | * leap_smear.doffset = 1.0 - leap_smear.doffset |
634 | | */ |
635 | | leap_smear.in_progress = TRUE; |
636 | | DPRINTF(1, ("*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f ms\n", |
637 | | leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval, |
638 | | now, leap_smear_time, leap_smear.doffset)); |
639 | | |
640 | | } |
641 | | } |
642 | | } else { |
643 | | leap_smear.interval = 0; |
644 | | } |
645 | | /* |
646 | | * Update the current leap smear offset, eventually 0.0 if outside smear interval. |
647 | | */ |
648 | | DTOLFP(leap_smear.doffset, &leap_smear.offset); |
649 | | #endif /* LEAP_SMEAR */ |
650 | |
|
651 | 0 | if (fired) { |
652 | | /* Full hit. Eventually step the clock, but always |
653 | | * announce the leap event has happened. |
654 | | */ |
655 | 0 | const char *leapmsg = NULL; |
656 | 0 | double lswarp = lsdata.warped; |
657 | 0 | if (lswarp < 0.0) { |
658 | 0 | if (clock_max_back > 0.0 && |
659 | 0 | clock_max_back < -lswarp) { |
660 | 0 | step_systime(lswarp); |
661 | 0 | leapmsg = leapmsg_p_step; |
662 | 0 | } else { |
663 | 0 | leapmsg = leapmsg_p_slew; |
664 | 0 | } |
665 | 0 | } else if (lswarp > 0.0) { |
666 | 0 | if (clock_max_fwd > 0.0 && |
667 | 0 | clock_max_fwd < lswarp) { |
668 | 0 | step_systime(lswarp); |
669 | 0 | leapmsg = leapmsg_n_step; |
670 | 0 | } else { |
671 | 0 | leapmsg = leapmsg_n_slew; |
672 | 0 | } |
673 | 0 | } |
674 | 0 | if (leapmsg) { |
675 | 0 | msyslog(LOG_NOTICE, "%s", leapmsg); |
676 | 0 | } |
677 | 0 | report_event(EVNT_LEAP, NULL, NULL); |
678 | 0 | #ifdef AUTOKEY |
679 | 0 | update_autokey = TRUE; |
680 | 0 | #endif |
681 | 0 | lsprox = LSPROX_NOWARN; |
682 | 0 | leapsec = LSPROX_NOWARN; |
683 | 0 | sys_tai = lsdata.tai_offs; |
684 | 0 | } else { |
685 | 0 | #ifdef AUTOKEY |
686 | 0 | update_autokey = (sys_tai != (u_int)lsdata.tai_offs); |
687 | 0 | #endif |
688 | 0 | lsprox = lsdata.proximity; |
689 | 0 | sys_tai = lsdata.tai_offs; |
690 | 0 | } |
691 | 0 | } |
692 | | |
693 | | /* We guard against panic alarming during the red alert phase. |
694 | | * Strange and evil things might happen if we go from stone cold |
695 | | * to piping hot in one step. If things are already that wobbly, |
696 | | * we let the normal clock correction take over, even if a jump |
697 | | * is involved. |
698 | | * Also make sure the alarming events are edge-triggered, that is, |
699 | | * created only when the threshold is crossed. |
700 | | */ |
701 | 0 | if ( (leapsec > 0 || lsprox < LSPROX_ALERT) |
702 | 0 | && leapsec < lsprox) { |
703 | 0 | if ( leapsec < LSPROX_SCHEDULE |
704 | 0 | && lsprox >= LSPROX_SCHEDULE) { |
705 | 0 | if (lsdata.dynamic) |
706 | 0 | report_event(PEVNT_ARMED, sys_peer, NULL); |
707 | 0 | else |
708 | 0 | report_event(EVNT_ARMED, NULL, NULL); |
709 | 0 | } |
710 | 0 | leapsec = lsprox; |
711 | 0 | } |
712 | 0 | if (leapsec > lsprox) { |
713 | 0 | if ( leapsec >= LSPROX_SCHEDULE |
714 | 0 | && lsprox < LSPROX_SCHEDULE) { |
715 | 0 | report_event(EVNT_DISARMED, NULL, NULL); |
716 | 0 | } |
717 | 0 | leapsec = lsprox; |
718 | 0 | } |
719 | |
|
720 | 0 | if (leapsec >= LSPROX_SCHEDULE) { |
721 | 0 | leapdif = lsdata.tai_diff; |
722 | 0 | } else { |
723 | 0 | leapdif = 0; |
724 | 0 | } |
725 | 0 | check_leap_sec_in_progress(&lsdata); |
726 | |
|
727 | 0 | #ifdef AUTOKEY |
728 | 0 | if (update_autokey) { |
729 | 0 | crypto_update_taichange(); |
730 | 0 | } |
731 | 0 | #endif |
732 | 0 | } |