1 /* $NetBSD: ntp_timer.c,v 1.4 2007/01/06 19:45:23 kardel Exp $ */
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 * These routines provide support for the event timer. The timer is
30 * implemented by an interrupt routine which sets a flag once every
31 * 2**EVENT_TIMEOUT seconds (currently 4), and a timer routine which
32 * is called when the mainline code gets around to seeing the flag.
33 * The timer routine dispatches the clock adjustment code if its time
34 * has come, then searches the timer queue for expiries which are
35 * dispatched to the transmit procedure. Finally, we call the hourly
36 * procedure to do cleanup and print a message.
39 volatile int interface_interval
= 300; /* update interface every 5 minutes as default */
42 * Alarm flag. The mainline code imports this.
44 volatile int alarm_flag
;
49 static u_long adjust_timer
; /* second timer */
50 static u_long keys_timer
; /* minute timer */
51 static u_long stats_timer
; /* stats timer */
52 static u_long huffpuff_timer
; /* huff-n'-puff timer */
53 static u_long interface_timer
; /* interface update timer */
55 static u_long revoke_timer
; /* keys revoke timer */
56 u_char sys_revoke
= KEY_REVOKE
; /* keys revoke timeout (log2 s) */
60 * Statistics counter for the interested.
62 volatile u_long alarm_overflow
;
70 * Stats. Number of overflows and number of calls to transmit().
72 u_long timer_timereset
;
73 u_long timer_overflows
;
74 u_long timer_xmtcalls
;
77 static int vmstimer
[2]; /* time for next timer AST */
78 static int vmsinc
[2]; /* timer increment */
82 static HANDLE WaitableTimerHandle
= NULL
;
84 static RETSIGTYPE alarming
P((int));
85 #endif /* SYS_WINNT */
88 # if !defined SYS_WINNT || defined(SYS_CYGWIN32)
89 # ifndef HAVE_TIMER_SETTIME
90 struct itimerval itimer
;
92 static timer_t ntpd_timerid
;
93 struct itimerspec itimer
;
94 # endif /* HAVE_TIMER_SETTIME */
95 # endif /* SYS_WINNT */
99 * reinit_timer - reinitialize interval timer.
104 #if !defined(SYS_WINNT) && !defined(VMS)
105 # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
106 timer_gettime(ntpd_timerid
, &itimer
);
107 if (itimer
.it_value
.tv_sec
< 0 || itimer
.it_value
.tv_sec
> (1<<EVENT_TIMEOUT
)) {
108 itimer
.it_value
.tv_sec
= (1<<EVENT_TIMEOUT
);
110 if (itimer
.it_value
.tv_nsec
< 0 ) {
111 itimer
.it_value
.tv_nsec
= 0;
113 if (itimer
.it_value
.tv_sec
== 0 && itimer
.it_value
.tv_nsec
== 0) {
114 itimer
.it_value
.tv_sec
= (1<<EVENT_TIMEOUT
);
115 itimer
.it_value
.tv_nsec
= 0;
117 itimer
.it_interval
.tv_sec
= (1<<EVENT_TIMEOUT
);
118 itimer
.it_interval
.tv_nsec
= 0;
119 timer_settime(ntpd_timerid
, 0 /*!TIMER_ABSTIME*/, &itimer
, NULL
);
121 getitimer(ITIMER_REAL
, &itimer
);
122 if (itimer
.it_value
.tv_sec
< 0 || itimer
.it_value
.tv_sec
> (1<<EVENT_TIMEOUT
)) {
123 itimer
.it_value
.tv_sec
= (1<<EVENT_TIMEOUT
);
125 if (itimer
.it_value
.tv_usec
< 0 ) {
126 itimer
.it_value
.tv_usec
= 0;
128 if (itimer
.it_value
.tv_sec
== 0 && itimer
.it_value
.tv_usec
== 0) {
129 itimer
.it_value
.tv_sec
= (1<<EVENT_TIMEOUT
);
130 itimer
.it_value
.tv_usec
= 0;
132 itimer
.it_interval
.tv_sec
= (1<<EVENT_TIMEOUT
);
133 itimer
.it_interval
.tv_usec
= 0;
134 setitimer(ITIMER_REAL
, &itimer
, (struct itimerval
*)0);
140 * init_timer - initialize the timer data structures
145 # if defined SYS_WINNT & !defined(SYS_CYGWIN32)
146 HANDLE hToken
= INVALID_HANDLE_VALUE
;
147 TOKEN_PRIVILEGES tkp
;
148 # endif /* SYS_WINNT */
164 #if !defined(SYS_WINNT)
166 * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT
167 * seconds from now and they continue on every 2**EVENT_TIMEOUT
171 # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
172 if (timer_create (CLOCK_REALTIME
, NULL
, &ntpd_timerid
) ==
180 fprintf (stderr
, "timer create FAILED\n");
183 (void) signal_no_reset(SIGALRM
, alarming
);
184 itimer
.it_interval
.tv_sec
= itimer
.it_value
.tv_sec
= (1<<EVENT_TIMEOUT
);
185 itimer
.it_interval
.tv_nsec
= itimer
.it_value
.tv_nsec
= 0;
186 timer_settime(ntpd_timerid
, 0 /*!TIMER_ABSTIME*/, &itimer
, NULL
);
188 (void) signal_no_reset(SIGALRM
, alarming
);
189 itimer
.it_interval
.tv_sec
= itimer
.it_value
.tv_sec
= (1<<EVENT_TIMEOUT
);
190 itimer
.it_interval
.tv_usec
= itimer
.it_value
.tv_usec
= 0;
191 setitimer(ITIMER_REAL
, &itimer
, (struct itimerval
*)0);
194 vmsinc
[0] = 10000000; /* 1 sec */
196 lib$
emul(&(1<<EVENT_TIMEOUT
), &vmsinc
, &0, &vmsinc
);
198 sys$
gettim(&vmstimer
); /* that's "now" as abstime */
200 lib$
addx(&vmsinc
, &vmstimer
, &vmstimer
);
201 sys$
setimr(0, &vmstimer
, alarming
, alarming
, 0);
203 #else /* SYS_WINNT */
207 * Get privileges needed for fiddling with the clock
210 /* get the current process token handle */
211 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &hToken
)) {
212 msyslog(LOG_ERR
, "OpenProcessToken failed: %m");
215 /* get the LUID for system-time privilege. */
216 LookupPrivilegeValue(NULL
, SE_SYSTEMTIME_NAME
, &tkp
.Privileges
[0].Luid
);
217 tkp
.PrivilegeCount
= 1; /* one privilege to set */
218 tkp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
219 /* get set-time privilege for this process. */
220 AdjustTokenPrivileges(hToken
, FALSE
, &tkp
, 0, (PTOKEN_PRIVILEGES
) NULL
, 0);
221 /* cannot test return value of AdjustTokenPrivileges. */
222 if (GetLastError() != ERROR_SUCCESS
) {
223 msyslog(LOG_ERR
, "AdjustTokenPrivileges failed: %m");
227 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
231 WaitableTimerHandle
= CreateWaitableTimer(NULL
, FALSE
, NULL
);
232 if (WaitableTimerHandle
== NULL
) {
233 msyslog(LOG_ERR
, "CreateWaitableTimer failed: %m");
237 DWORD Period
= (1<<EVENT_TIMEOUT
) * 1000;
238 LARGE_INTEGER DueTime
;
239 DueTime
.QuadPart
= Period
* 10000i64
;
240 if (!SetWaitableTimer(WaitableTimerHandle
, &DueTime
, Period
, NULL
, NULL
, FALSE
) != NO_ERROR
) {
241 msyslog(LOG_ERR
, "SetWaitableTimer failed: %m");
246 #endif /* SYS_WINNT */
249 #if defined(SYS_WINNT)
251 get_timer_handle(void)
253 return WaitableTimerHandle
;
258 * timer - dispatch anyone who needs to be
263 register struct peer
*peer
, *next_peer
;
265 char statstr
[NTP_MAXSTRLEN
]; /* statistics for filegen */
269 current_time
+= (1<<EVENT_TIMEOUT
);
272 * Adjustment timeout first.
274 if (adjust_timer
<= current_time
) {
279 for (n
= 0; n
< NTP_HASH_SIZE
; n
++) {
280 for (peer
= peer_hash
[n
]; peer
!= 0; peer
= next_peer
) {
281 next_peer
= peer
->next
;
282 if (peer
->flags
& FLAG_REFCLOCK
)
283 refclock_timer(peer
);
286 #endif /* REFCLOCK */
290 * Now dispatch any peers whose event timer has expired. Be careful
291 * here, since the peer structure might go away as the result of
294 for (n
= 0; n
< NTP_HASH_SIZE
; n
++) {
295 for (peer
= peer_hash
[n
]; peer
!= 0; peer
= next_peer
) {
296 next_peer
= peer
->next
;
297 if (peer
->action
&& peer
->nextaction
<= current_time
)
299 if (peer
->nextdate
<= current_time
) {
301 if (peer
->flags
& FLAG_REFCLOCK
)
302 refclock_transmit(peer
);
307 #endif /* REFCLOCK */
313 * Garbage collect expired keys.
315 if (keys_timer
<= current_time
) {
316 keys_timer
+= MINUTE
;
321 * Huff-n'-puff filter
323 if (huffpuff_timer
<= current_time
) {
324 huffpuff_timer
+= HUFFPUFF
;
330 * Garbage collect old keys and generate new private value
332 if (revoke_timer
<= current_time
) {
333 revoke_timer
+= RANDPOLL(sys_revoke
);
335 sprintf(statstr
, "refresh ts %u", ntohl(hostval
.tstamp
));
336 record_crypto_stats(NULL
, statstr
);
339 printf("timer: %s\n", statstr
);
345 * interface update timer
347 if (interface_interval
&& interface_timer
<= current_time
) {
349 timer_interfacetimeout(current_time
+ interface_interval
);
350 DPRINTF(1, ("timer: interface update\n"));
351 interface_update(NULL
, NULL
);
355 * Finally, periodically write stats.
357 if (stats_timer
<= current_time
) {
358 if (stats_timer
!= 0)
360 stats_timer
+= stats_write_period
;
367 * alarming - tell the world we've been alarmed
381 #else /* VMS AST routine */
383 if (alarm_flag
) alarm_overflow
++;
384 else alarm_flag
= 1; /* increment is no good */
386 lib$
addx(&vmsinc
,&vmstimer
,&vmstimer
);
387 sys$
setimr(0,&vmstimer
,alarming
,alarming
,0);
390 #endif /* SYS_WINNT */
393 timer_interfacetimeout(u_long timeout
)
395 interface_timer
= timeout
;
400 * timer_clr_stats - clear timer module stat counters
403 timer_clr_stats(void)
407 timer_timereset
= current_time
;