4 * ntp_timer.c - event timer support routines
10 #include "ntp_machine.h"
12 #include "ntp_stdlib.h"
16 #ifdef HAVE_SYS_SIGNAL_H
17 # include <sys/signal.h>
23 #if defined(HAVE_IO_COMPLETION_PORT)
24 # include "ntp_iocompletionport.h"
25 # include "ntp_timer.h"
29 #include "ntp_syscall.h"
30 #endif /* KERNEL_PLL */
33 #include <openssl/rand.h>
37 * These routines provide support for the event timer. The timer is
38 * implemented by an interrupt routine which sets a flag once every
39 * 2**EVENT_TIMEOUT seconds (currently 4), and a timer routine which
40 * is called when the mainline code gets around to seeing the flag.
41 * The timer routine dispatches the clock adjustment code if its time
42 * has come, then searches the timer queue for expiries which are
43 * dispatched to the transmit procedure. Finally, we call the hourly
44 * procedure to do cleanup and print a message.
46 volatile int interface_interval
= 300; /* update interface every 5 minutes as default */
49 * Alarm flag. The mainline code imports this.
51 volatile int alarm_flag
;
54 * The counters and timeouts
56 static u_long interface_timer
; /* interface update timer */
57 static u_long adjust_timer
; /* second timer */
58 static u_long stats_timer
; /* stats timer */
59 static u_long huffpuff_timer
; /* huff-n'-puff timer */
60 u_long leapsec
; /* leapseconds countdown */
61 l_fp sys_time
; /* current system time */
63 static u_long revoke_timer
; /* keys revoke timer */
64 static u_long keys_timer
; /* session key timer */
65 u_long sys_revoke
= KEY_REVOKE
; /* keys revoke timeout (log2 s) */
66 u_long sys_automax
= NTP_AUTOMAX
; /* key list timeout (log2 s) */
70 * Statistics counter for the interested.
72 volatile u_long alarm_overflow
;
75 #define HOUR (60 * MINUTE)
76 #define DAY (24 * HOUR)
78 u_long current_time
; /* seconds since startup */
81 * Stats. Number of overflows and number of calls to transmit().
83 u_long timer_timereset
;
84 u_long timer_overflows
;
85 u_long timer_xmtcalls
;
88 static int vmstimer
[2]; /* time for next timer AST */
89 static int vmsinc
[2]; /* timer increment */
93 static HANDLE WaitableTimerHandle
= NULL
;
95 static RETSIGTYPE
alarming (int);
96 #endif /* SYS_WINNT */
99 # if !defined SYS_WINNT || defined(SYS_CYGWIN32)
100 # ifndef HAVE_TIMER_SETTIME
101 struct itimerval itimer
;
103 static timer_t ntpd_timerid
;
104 struct itimerspec itimer
;
105 # endif /* HAVE_TIMER_SETTIME */
106 # endif /* SYS_WINNT */
110 * reinit_timer - reinitialize interval timer.
115 #if !defined(SYS_WINNT) && !defined(VMS)
116 # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
117 timer_gettime(ntpd_timerid
, &itimer
);
118 if (itimer
.it_value
.tv_sec
< 0 || itimer
.it_value
.tv_sec
> (1<<EVENT_TIMEOUT
)) {
119 itimer
.it_value
.tv_sec
= (1<<EVENT_TIMEOUT
);
121 if (itimer
.it_value
.tv_nsec
< 0 ) {
122 itimer
.it_value
.tv_nsec
= 0;
124 if (itimer
.it_value
.tv_sec
== 0 && itimer
.it_value
.tv_nsec
== 0) {
125 itimer
.it_value
.tv_sec
= (1<<EVENT_TIMEOUT
);
126 itimer
.it_value
.tv_nsec
= 0;
128 itimer
.it_interval
.tv_sec
= (1<<EVENT_TIMEOUT
);
129 itimer
.it_interval
.tv_nsec
= 0;
130 timer_settime(ntpd_timerid
, 0 /*!TIMER_ABSTIME*/, &itimer
, NULL
);
132 getitimer(ITIMER_REAL
, &itimer
);
133 if (itimer
.it_value
.tv_sec
< 0 || itimer
.it_value
.tv_sec
> (1<<EVENT_TIMEOUT
)) {
134 itimer
.it_value
.tv_sec
= (1<<EVENT_TIMEOUT
);
136 if (itimer
.it_value
.tv_usec
< 0 ) {
137 itimer
.it_value
.tv_usec
= 0;
139 if (itimer
.it_value
.tv_sec
== 0 && itimer
.it_value
.tv_usec
== 0) {
140 itimer
.it_value
.tv_sec
= (1<<EVENT_TIMEOUT
);
141 itimer
.it_value
.tv_usec
= 0;
143 itimer
.it_interval
.tv_sec
= (1<<EVENT_TIMEOUT
);
144 itimer
.it_interval
.tv_usec
= 0;
145 setitimer(ITIMER_REAL
, &itimer
, (struct itimerval
*)0);
151 * init_timer - initialize the timer data structures
170 #if !defined(SYS_WINNT)
172 * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT
173 * seconds from now and they continue on every 2**EVENT_TIMEOUT
177 # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
178 if (timer_create (CLOCK_REALTIME
, NULL
, &ntpd_timerid
) ==
186 fprintf (stderr
, "timer create FAILED\n");
189 (void) signal_no_reset(SIGALRM
, alarming
);
190 itimer
.it_interval
.tv_sec
= itimer
.it_value
.tv_sec
= (1<<EVENT_TIMEOUT
);
191 itimer
.it_interval
.tv_nsec
= itimer
.it_value
.tv_nsec
= 0;
192 timer_settime(ntpd_timerid
, 0 /*!TIMER_ABSTIME*/, &itimer
, NULL
);
194 (void) signal_no_reset(SIGALRM
, alarming
);
195 itimer
.it_interval
.tv_sec
= itimer
.it_value
.tv_sec
= (1<<EVENT_TIMEOUT
);
196 itimer
.it_interval
.tv_usec
= itimer
.it_value
.tv_usec
= 0;
197 setitimer(ITIMER_REAL
, &itimer
, (struct itimerval
*)0);
200 vmsinc
[0] = 10000000; /* 1 sec */
202 lib$
emul(&(1<<EVENT_TIMEOUT
), &vmsinc
, &0, &vmsinc
);
204 sys$
gettim(&vmstimer
); /* that's "now" as abstime */
206 lib$
addx(&vmsinc
, &vmstimer
, &vmstimer
);
207 sys$
setimr(0, &vmstimer
, alarming
, alarming
, 0);
209 #else /* SYS_WINNT */
211 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
215 WaitableTimerHandle
= CreateWaitableTimer(NULL
, FALSE
, NULL
);
216 if (WaitableTimerHandle
== NULL
) {
217 msyslog(LOG_ERR
, "CreateWaitableTimer failed: %m");
221 DWORD Period
= (1<<EVENT_TIMEOUT
) * 1000;
222 LARGE_INTEGER DueTime
;
223 DueTime
.QuadPart
= Period
* 10000i64
;
224 if (!SetWaitableTimer(WaitableTimerHandle
, &DueTime
, Period
, NULL
, NULL
, FALSE
) != NO_ERROR
) {
225 msyslog(LOG_ERR
, "SetWaitableTimer failed: %m");
230 #endif /* SYS_WINNT */
233 #if defined(SYS_WINNT)
235 get_timer_handle(void)
237 return WaitableTimerHandle
;
242 * timer - event timer
247 register struct peer
*peer
, *next_peer
;
251 * The basic timerevent is one second. This is used to adjust
252 * the system clock in time and frequency, implement the
253 * kiss-o'-deatch function and implement the association
257 get_systime(&sys_time
);
258 if (adjust_timer
<= current_time
) {
262 for (n
= 0; n
< NTP_HASH_SIZE
; n
++) {
263 for (peer
= peer_hash
[n
]; peer
!= 0; peer
= next_peer
) {
264 next_peer
= peer
->next
;
265 if (peer
->flags
& FLAG_REFCLOCK
)
266 refclock_timer(peer
);
269 #endif /* REFCLOCK */
273 * Now dispatch any peers whose event timer has expired. Be
274 * careful here, since the peer structure might go away as the
275 * result of the call.
277 for (n
= 0; n
< NTP_HASH_SIZE
; n
++) {
278 for (peer
= peer_hash
[n
]; peer
!= 0; peer
= next_peer
) {
279 next_peer
= peer
->next
;
280 if (peer
->action
&& peer
->nextaction
<=
285 * Restrain the non-burst packet rate not more
286 * than one packet every 16 seconds. This is
287 * usually tripped using iburst and minpoll of
290 if (peer
->throttle
> 0)
292 if (peer
->nextdate
<= current_time
) {
294 if (peer
->flags
& FLAG_REFCLOCK
)
295 refclock_transmit(peer
);
300 #endif /* REFCLOCK */
306 * Orphan mode is active when enabled and when no servers less
307 * than the orphan statum are available. A server with no other
308 * synchronization source is an orphan It shows offset zero and
309 * reference ID the loopback address.
311 if (sys_orphan
< STRATUM_UNSPEC
&& sys_peer
== NULL
) {
312 if (sys_leap
== LEAP_NOTINSYNC
) {
313 sys_leap
= LEAP_NOWARNING
;
319 sys_stratum
= (u_char
)sys_orphan
;
321 sys_refid
= htonl(LOOPBACKADR
);
323 memcpy(&sys_refid
, "LOOP", 4);
330 * Leapseconds. If a leap is pending, decrement the time
331 * remaining. If less than one day remains, set the leap bits.
332 * When no time remains, clear the leap bits and increment the
333 * TAI. If kernel suppport is not available, do the leap
334 * crudely. Note a leap cannot be pending unless the clock is
340 sys_leap
= LEAP_NOWARNING
;
343 if (!(pll_control
&& kern_enable
))
345 #else /* KERNEL_PLL */
346 #ifndef SYS_WINNT /* WinNT port has its own leap second handling */
348 #endif /* SYS_WINNT */
349 #endif /* KERNEL_PLL */
350 report_event(EVNT_LEAP
, NULL
, NULL
);
353 sys_leap
= LEAP_ADDSECOND
;
355 sys_tai
= leap_tai
- 1;
360 * Update huff-n'-puff filter.
362 if (huffpuff_timer
<= current_time
) {
363 huffpuff_timer
+= HUFFPUFF
;
369 * Garbage collect expired keys.
371 if (keys_timer
<= current_time
) {
372 keys_timer
+= 1 << sys_automax
;
377 * Garbage collect key list and generate new private value. The
378 * timer runs only after initial synchronization and fires about
381 if (revoke_timer
<= current_time
&& sys_leap
!=
383 revoke_timer
+= 1 << sys_revoke
;
384 RAND_bytes((u_char
*)&sys_private
, 4);
389 * Interface update timer
391 if (interface_interval
&& interface_timer
<= current_time
) {
393 timer_interfacetimeout(current_time
+
395 DPRINTF(2, ("timer: interface update\n"));
396 interface_update(NULL
, NULL
);
400 * Finally, write hourly stats.
402 if (stats_timer
<= current_time
) {
405 if (sys_tai
!= 0 && sys_time
.l_ui
> leap_expire
)
406 report_event(EVNT_LEAPVAL
, NULL
, NULL
);
413 * alarming - tell the world we've been alarmed
427 #else /* VMS AST routine */
429 if (alarm_flag
) alarm_overflow
++;
430 else alarm_flag
= 1; /* increment is no good */
432 lib$
addx(&vmsinc
,&vmstimer
,&vmstimer
);
433 sys$
setimr(0,&vmstimer
,alarming
,alarming
,0);
436 #endif /* SYS_WINNT */
439 timer_interfacetimeout(u_long timeout
)
441 interface_timer
= timeout
;
446 * timer_clr_stats - clear timer module stat counters
449 timer_clr_stats(void)
453 timer_timereset
= current_time
;