Annotation of embedaddon/ntp/ntpd/ntp_timer.c, revision 1.1
1.1 ! misho 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:
! 12: #include <stdio.h>
! 13: #include <signal.h>
! 14: #ifdef HAVE_SYS_SIGNAL_H
! 15: # include <sys/signal.h>
! 16: #endif
! 17: #ifdef HAVE_UNISTD_H
! 18: # include <unistd.h>
! 19: #endif
! 20:
! 21: #if defined(HAVE_IO_COMPLETION_PORT)
! 22: # include "ntp_iocompletionport.h"
! 23: # include "ntp_timer.h"
! 24: #endif
! 25:
! 26: #ifdef KERNEL_PLL
! 27: #include "ntp_syscall.h"
! 28: #endif /* KERNEL_PLL */
! 29:
! 30: #ifdef OPENSSL
! 31: #include <openssl/rand.h>
! 32: #endif /* OPENSSL */
! 33:
! 34: /*
! 35: * These routines provide support for the event timer. The timer is
! 36: * implemented by an interrupt routine which sets a flag once every
! 37: * 2**EVENT_TIMEOUT seconds (currently 4), and a timer routine which
! 38: * is called when the mainline code gets around to seeing the flag.
! 39: * The timer routine dispatches the clock adjustment code if its time
! 40: * has come, then searches the timer queue for expiries which are
! 41: * dispatched to the transmit procedure. Finally, we call the hourly
! 42: * procedure to do cleanup and print a message.
! 43: */
! 44: volatile int interface_interval = 300; /* update interface every 5 minutes as default */
! 45:
! 46: /*
! 47: * Alarm flag. The mainline code imports this.
! 48: */
! 49: volatile int alarm_flag;
! 50:
! 51: /*
! 52: * The counters and timeouts
! 53: */
! 54: static u_long interface_timer; /* interface update timer */
! 55: static u_long adjust_timer; /* second timer */
! 56: static u_long stats_timer; /* stats timer */
! 57: static u_long huffpuff_timer; /* huff-n'-puff timer */
! 58: u_long leapsec; /* leapseconds countdown */
! 59: l_fp sys_time; /* current system time */
! 60: #ifdef OPENSSL
! 61: static u_long revoke_timer; /* keys revoke timer */
! 62: static u_long keys_timer; /* session key timer */
! 63: u_long sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */
! 64: u_long sys_automax = NTP_AUTOMAX; /* key list timeout (log2 s) */
! 65: #endif /* OPENSSL */
! 66:
! 67: /*
! 68: * Statistics counter for the interested.
! 69: */
! 70: volatile u_long alarm_overflow;
! 71:
! 72: #define MINUTE 60
! 73: #define HOUR (60 * MINUTE)
! 74: #define DAY (24 * HOUR)
! 75:
! 76: u_long current_time; /* seconds since startup */
! 77:
! 78: /*
! 79: * Stats. Number of overflows and number of calls to transmit().
! 80: */
! 81: u_long timer_timereset;
! 82: u_long timer_overflows;
! 83: u_long timer_xmtcalls;
! 84:
! 85: #if defined(VMS)
! 86: static int vmstimer[2]; /* time for next timer AST */
! 87: static int vmsinc[2]; /* timer increment */
! 88: #endif /* VMS */
! 89:
! 90: #if defined SYS_WINNT
! 91: static HANDLE WaitableTimerHandle = NULL;
! 92: #else
! 93: static RETSIGTYPE alarming (int);
! 94: #endif /* SYS_WINNT */
! 95:
! 96: #if !defined(VMS)
! 97: # if !defined SYS_WINNT || defined(SYS_CYGWIN32)
! 98: # ifndef HAVE_TIMER_SETTIME
! 99: struct itimerval itimer;
! 100: # else
! 101: static timer_t ntpd_timerid;
! 102: struct itimerspec itimer;
! 103: # endif /* HAVE_TIMER_SETTIME */
! 104: # endif /* SYS_WINNT */
! 105: #endif /* VMS */
! 106:
! 107: /*
! 108: * reinit_timer - reinitialize interval timer.
! 109: */
! 110: void
! 111: reinit_timer(void)
! 112: {
! 113: #if !defined(SYS_WINNT) && !defined(VMS)
! 114: # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
! 115: timer_gettime(ntpd_timerid, &itimer);
! 116: if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
! 117: itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
! 118: }
! 119: if (itimer.it_value.tv_nsec < 0 ) {
! 120: itimer.it_value.tv_nsec = 0;
! 121: }
! 122: if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_nsec == 0) {
! 123: itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
! 124: itimer.it_value.tv_nsec = 0;
! 125: }
! 126: itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
! 127: itimer.it_interval.tv_nsec = 0;
! 128: timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
! 129: # else
! 130: getitimer(ITIMER_REAL, &itimer);
! 131: if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
! 132: itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
! 133: }
! 134: if (itimer.it_value.tv_usec < 0 ) {
! 135: itimer.it_value.tv_usec = 0;
! 136: }
! 137: if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_usec == 0) {
! 138: itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
! 139: itimer.it_value.tv_usec = 0;
! 140: }
! 141: itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
! 142: itimer.it_interval.tv_usec = 0;
! 143: setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
! 144: # endif
! 145: # endif /* VMS */
! 146: }
! 147:
! 148: /*
! 149: * init_timer - initialize the timer data structures
! 150: */
! 151: void
! 152: init_timer(void)
! 153: {
! 154: /*
! 155: * Initialize...
! 156: */
! 157: alarm_flag = 0;
! 158: alarm_overflow = 0;
! 159: adjust_timer = 1;
! 160: stats_timer = 0;
! 161: huffpuff_timer = 0;
! 162: interface_timer = 0;
! 163: current_time = 0;
! 164: timer_overflows = 0;
! 165: timer_xmtcalls = 0;
! 166: timer_timereset = 0;
! 167:
! 168: #if !defined(SYS_WINNT)
! 169: /*
! 170: * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT
! 171: * seconds from now and they continue on every 2**EVENT_TIMEOUT
! 172: * seconds.
! 173: */
! 174: # if !defined(VMS)
! 175: # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
! 176: if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) ==
! 177: # ifdef SYS_VXWORKS
! 178: ERROR
! 179: # else
! 180: -1
! 181: # endif
! 182: )
! 183: {
! 184: fprintf (stderr, "timer create FAILED\n");
! 185: exit (0);
! 186: }
! 187: (void) signal_no_reset(SIGALRM, alarming);
! 188: itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
! 189: itimer.it_interval.tv_nsec = itimer.it_value.tv_nsec = 0;
! 190: timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
! 191: # else
! 192: (void) signal_no_reset(SIGALRM, alarming);
! 193: itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
! 194: itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0;
! 195: setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
! 196: # endif
! 197: # else /* VMS */
! 198: vmsinc[0] = 10000000; /* 1 sec */
! 199: vmsinc[1] = 0;
! 200: lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);
! 201:
! 202: sys$gettim(&vmstimer); /* that's "now" as abstime */
! 203:
! 204: lib$addx(&vmsinc, &vmstimer, &vmstimer);
! 205: sys$setimr(0, &vmstimer, alarming, alarming, 0);
! 206: # endif /* VMS */
! 207: #else /* SYS_WINNT */
! 208: /*
! 209: * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
! 210: * Under Windows/NT,
! 211: */
! 212:
! 213: WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
! 214: if (WaitableTimerHandle == NULL) {
! 215: msyslog(LOG_ERR, "CreateWaitableTimer failed: %m");
! 216: exit(1);
! 217: }
! 218: else {
! 219: DWORD Period = (1<<EVENT_TIMEOUT) * 1000;
! 220: LARGE_INTEGER DueTime;
! 221: DueTime.QuadPart = Period * 10000i64;
! 222: if (!SetWaitableTimer(WaitableTimerHandle, &DueTime, Period, NULL, NULL, FALSE) != NO_ERROR) {
! 223: msyslog(LOG_ERR, "SetWaitableTimer failed: %m");
! 224: exit(1);
! 225: }
! 226: }
! 227:
! 228: #endif /* SYS_WINNT */
! 229: }
! 230:
! 231: #if defined(SYS_WINNT)
! 232: extern HANDLE
! 233: get_timer_handle(void)
! 234: {
! 235: return WaitableTimerHandle;
! 236: }
! 237: #endif
! 238:
! 239: /*
! 240: * timer - event timer
! 241: */
! 242: void
! 243: timer(void)
! 244: {
! 245: register struct peer *peer, *next_peer;
! 246: u_int n;
! 247:
! 248: /*
! 249: * The basic timerevent is one second. This is used to adjust
! 250: * the system clock in time and frequency, implement the
! 251: * kiss-o'-deatch function and implement the association
! 252: * polling function..
! 253: */
! 254: current_time++;
! 255: get_systime(&sys_time);
! 256: if (adjust_timer <= current_time) {
! 257: adjust_timer += 1;
! 258: adj_host_clock();
! 259: #ifdef REFCLOCK
! 260: for (n = 0; n < NTP_HASH_SIZE; n++) {
! 261: for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
! 262: next_peer = peer->next;
! 263: if (peer->flags & FLAG_REFCLOCK)
! 264: refclock_timer(peer);
! 265: }
! 266: }
! 267: #endif /* REFCLOCK */
! 268: }
! 269:
! 270: /*
! 271: * Now dispatch any peers whose event timer has expired. Be
! 272: * careful here, since the peer structure might go away as the
! 273: * result of the call.
! 274: */
! 275: for (n = 0; n < NTP_HASH_SIZE; n++) {
! 276: for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
! 277: next_peer = peer->next;
! 278: if (peer->action && peer->nextaction <=
! 279: current_time)
! 280: peer->action(peer);
! 281:
! 282: /*
! 283: * Restrain the non-burst packet rate not more
! 284: * than one packet every 16 seconds. This is
! 285: * usually tripped using iburst and minpoll of
! 286: * 128 s or less.
! 287: */
! 288: if (peer->throttle > 0)
! 289: peer->throttle--;
! 290: if (peer->nextdate <= current_time) {
! 291: #ifdef REFCLOCK
! 292: if (peer->flags & FLAG_REFCLOCK)
! 293: refclock_transmit(peer);
! 294: else
! 295: transmit(peer);
! 296: #else /* REFCLOCK */
! 297: transmit(peer);
! 298: #endif /* REFCLOCK */
! 299: }
! 300: }
! 301: }
! 302:
! 303: /*
! 304: * Orphan mode is active when enabled and when no servers less
! 305: * than the orphan stratum are available. A server with no other
! 306: * synchronization source is an orphan. It shows offset zero and
! 307: * reference ID the loopback address.
! 308: */
! 309: if (sys_orphan < STRATUM_UNSPEC && sys_peer == NULL) {
! 310: if (sys_leap == LEAP_NOTINSYNC) {
! 311: sys_leap = LEAP_NOWARNING;
! 312: #ifdef OPENSSL
! 313: if (crypto_flags)
! 314: crypto_update();
! 315: #endif /* OPENSSL */
! 316: }
! 317: sys_stratum = (u_char)sys_orphan;
! 318: if (sys_stratum > 1)
! 319: sys_refid = htonl(LOOPBACKADR);
! 320: else
! 321: memcpy(&sys_refid, "LOOP", 4);
! 322: sys_offset = 0;
! 323: sys_rootdelay = 0;
! 324: sys_rootdisp = 0;
! 325: }
! 326:
! 327: /*
! 328: * Leapseconds. If a leap is pending, decrement the time
! 329: * remaining. If less than one day remains, set the leap bits.
! 330: * When no time remains, clear the leap bits and increment the
! 331: * TAI. If kernel suppport is not available, do the leap
! 332: * crudely. Note a leap cannot be pending unless the clock is
! 333: * set.
! 334: */
! 335: if (leapsec > 0) {
! 336: leapsec--;
! 337: if (leapsec == 0) {
! 338: sys_leap = LEAP_NOWARNING;
! 339: sys_tai = leap_tai;
! 340: #ifdef KERNEL_PLL
! 341: if (!(pll_control && kern_enable))
! 342: step_systime(-1.0);
! 343: #else /* KERNEL_PLL */
! 344: #ifndef SYS_WINNT /* WinNT port has its own leap second handling */
! 345: step_systime(-1.0);
! 346: #endif /* SYS_WINNT */
! 347: #endif /* KERNEL_PLL */
! 348: report_event(EVNT_LEAP, NULL, NULL);
! 349: } else {
! 350: if (leapsec < DAY)
! 351: sys_leap = LEAP_ADDSECOND;
! 352: if (leap_tai > 0)
! 353: sys_tai = leap_tai - 1;
! 354: }
! 355: }
! 356:
! 357: /*
! 358: * Update huff-n'-puff filter.
! 359: */
! 360: if (huffpuff_timer <= current_time) {
! 361: huffpuff_timer += HUFFPUFF;
! 362: huffpuff();
! 363: }
! 364:
! 365: #ifdef OPENSSL
! 366: /*
! 367: * Garbage collect expired keys.
! 368: */
! 369: if (keys_timer <= current_time) {
! 370: keys_timer += 1 << sys_automax;
! 371: auth_agekeys();
! 372: }
! 373:
! 374: /*
! 375: * Garbage collect key list and generate new private value. The
! 376: * timer runs only after initial synchronization and fires about
! 377: * once per day.
! 378: */
! 379: if (revoke_timer <= current_time && sys_leap !=
! 380: LEAP_NOTINSYNC) {
! 381: revoke_timer += 1 << sys_revoke;
! 382: RAND_bytes((u_char *)&sys_private, 4);
! 383: }
! 384: #endif /* OPENSSL */
! 385:
! 386: /*
! 387: * Interface update timer
! 388: */
! 389: if (interface_interval && interface_timer <= current_time) {
! 390:
! 391: timer_interfacetimeout(current_time +
! 392: interface_interval);
! 393: DPRINTF(2, ("timer: interface update\n"));
! 394: interface_update(NULL, NULL);
! 395: }
! 396:
! 397: /*
! 398: * Finally, write hourly stats.
! 399: */
! 400: if (stats_timer <= current_time) {
! 401: stats_timer += HOUR;
! 402: write_stats();
! 403: if (sys_tai != 0 && sys_time.l_ui > leap_expire)
! 404: report_event(EVNT_LEAPVAL, NULL, NULL);
! 405: }
! 406: }
! 407:
! 408:
! 409: #ifndef SYS_WINNT
! 410: /*
! 411: * alarming - tell the world we've been alarmed
! 412: */
! 413: static RETSIGTYPE
! 414: alarming(
! 415: int sig
! 416: )
! 417: {
! 418: #if !defined(VMS)
! 419: if (initializing)
! 420: return;
! 421: if (alarm_flag)
! 422: alarm_overflow++;
! 423: else
! 424: alarm_flag++;
! 425: #else /* VMS AST routine */
! 426: if (!initializing) {
! 427: if (alarm_flag) alarm_overflow++;
! 428: else alarm_flag = 1; /* increment is no good */
! 429: }
! 430: lib$addx(&vmsinc,&vmstimer,&vmstimer);
! 431: sys$setimr(0,&vmstimer,alarming,alarming,0);
! 432: #endif /* VMS */
! 433: }
! 434: #endif /* SYS_WINNT */
! 435:
! 436: void
! 437: timer_interfacetimeout(u_long timeout)
! 438: {
! 439: interface_timer = timeout;
! 440: }
! 441:
! 442:
! 443: /*
! 444: * timer_clr_stats - clear timer module stat counters
! 445: */
! 446: void
! 447: timer_clr_stats(void)
! 448: {
! 449: timer_overflows = 0;
! 450: timer_xmtcalls = 0;
! 451: timer_timereset = current_time;
! 452: }
! 453:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>