2 * ntp_timer.c - event timer support routines
8 #include "ntp_machine.h"
10 #include "ntp_stdlib.h"
14 #include <sys/signal.h>
19 #if defined(HAVE_IO_COMPLETION_PORT)
20 # include "ntp_iocompletionport.h"
21 # include "ntp_timer.h"
25 #include "ntp_crypto.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.
40 * Alarm flag. The mainline code imports this.
42 volatile int alarm_flag;
47 static u_long adjust_timer; /* second timer */
48 static u_long keys_timer; /* minute timer */
49 static u_long hourly_timer; /* hour timer */
50 static u_long huffpuff_timer; /* huff-n'-puff timer */
52 static u_long revoke_timer; /* keys revoke timer */
53 u_long sys_revoke = 1 << KEY_REVOKE; /* keys revoke timeout */
57 * Statistics counter for the interested.
59 volatile u_long alarm_overflow;
67 * Stats. Number of overflows and number of calls to transmit().
69 u_long timer_timereset;
70 u_long timer_overflows;
71 u_long timer_xmtcalls;
74 static int vmstimer[2]; /* time for next timer AST */
75 static int vmsinc[2]; /* timer increment */
79 static HANDLE WaitableTimerHandle = NULL;
81 static RETSIGTYPE alarming P((int));
82 #endif /* SYS_WINNT */
86 * init_timer - initialize the timer data structures
92 # if !defined SYS_WINNT || defined(SYS_CYGWIN32)
93 # ifndef HAVE_TIMER_SETTIME
94 struct itimerval itimer;
96 static timer_t ntpd_timerid; /* should be global if we ever want */
97 /* to kill timer without rebooting ... */
98 struct itimerspec itimer;
99 # endif /* HAVE_TIMER_SETTIME */
100 # else /* SYS_WINNT */
102 TOKEN_PRIVILEGES tkp;
103 # endif /* SYS_WINNT */
119 #if !defined(SYS_WINNT)
121 * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT
122 * seconds from now and they continue on every 2**EVENT_TIMEOUT
126 # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
127 if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) ==
135 fprintf (stderr, "timer create FAILED\n");
138 (void) signal_no_reset(SIGALRM, alarming);
139 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
140 itimer.it_interval.tv_nsec = itimer.it_value.tv_nsec = 0;
141 timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
143 (void) signal_no_reset(SIGALRM, alarming);
144 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
145 itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0;
146 setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
149 vmsinc[0] = 10000000; /* 1 sec */
151 lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);
153 sys$gettim(&vmstimer); /* that's "now" as abstime */
155 lib$addx(&vmsinc, &vmstimer, &vmstimer);
156 sys$setimr(0, &vmstimer, alarming, alarming, 0);
158 #else /* SYS_WINNT */
162 * Get privileges needed for fiddling with the clock
165 /* get the current process token handle */
166 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
167 msyslog(LOG_ERR, "OpenProcessToken failed: %m");
170 /* get the LUID for system-time privilege. */
171 LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
172 tkp.PrivilegeCount = 1; /* one privilege to set */
173 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
174 /* get set-time privilege for this process. */
175 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
176 /* cannot test return value of AdjustTokenPrivileges. */
177 if (GetLastError() != ERROR_SUCCESS) {
178 msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
182 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
186 WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
187 if (WaitableTimerHandle == NULL) {
188 msyslog(LOG_ERR, "CreateWaitableTimer failed: %m");
192 DWORD Period = (1<<EVENT_TIMEOUT) * 1000;
193 LARGE_INTEGER DueTime;
194 DueTime.QuadPart = Period * 10000i64;
195 if (!SetWaitableTimer(WaitableTimerHandle, &DueTime, Period, NULL, NULL, FALSE) != NO_ERROR) {
196 msyslog(LOG_ERR, "SetWaitableTimer failed: %m");
201 #endif /* SYS_WINNT */
204 #if defined(SYS_WINNT)
206 get_timer_handle(void)
208 return WaitableTimerHandle;
213 * timer - dispatch anyone who needs to be
218 register struct peer *peer, *next_peer;
221 current_time += (1<<EVENT_TIMEOUT);
224 * Adjustment timeout first.
226 if (adjust_timer <= current_time) {
232 * Now dispatch any peers whose event timer has expired. Be careful
233 * here, since the peer structure might go away as the result of
236 for (n = 0; n < HASH_SIZE; n++) {
237 for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
238 next_peer = peer->next;
239 if (peer->action && peer->nextaction <= current_time)
241 if (peer->nextdate <= current_time) {
243 if (peer->flags & FLAG_REFCLOCK)
244 refclock_transmit(peer);
249 #endif /* REFCLOCK */
255 * Garbage collect expired keys.
257 if (keys_timer <= current_time) {
258 keys_timer += MINUTE;
263 * Huff-n'-puff filter
265 if (huffpuff_timer <= current_time) {
266 huffpuff_timer += HUFFPUFF;
272 * Garbage collect old keys and generate new private value
274 if (revoke_timer <= current_time) {
275 revoke_timer += sys_revoke;
279 printf("key expire: at %lu next %lu\n",
280 current_time, revoke_timer);
286 * Finally, call the hourly routine.
288 if (hourly_timer <= current_time) {
289 hourly_timer += HOUR;
297 * alarming - tell the world we've been alarmed
311 #else /* VMS AST routine */
313 if (alarm_flag) alarm_overflow++;
314 else alarm_flag = 1; /* increment is no good */
316 lib$addx(&vmsinc,&vmstimer,&vmstimer);
317 sys$setimr(0,&vmstimer,alarming,alarming,0);
320 #endif /* SYS_WINNT */
324 * timer_clr_stats - clear timer module stat counters
327 timer_clr_stats(void)
331 timer_timereset = current_time;