ntp_timer.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright (c) 1996 by Sun Microsystems, Inc.
* All Rights Reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* ntp_timer.c - event timer support routines
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include "ntpd.h"
#include "ntp_stdlib.h"
/*
* These routines provide support for the event timer. The timer is
* implemented by an interrupt routine which sets a flag once every
* 2**EVENT_TIMEOUT seconds (currently 4), and a timer routine which
* is called when the mainline code gets around to seeing the flag.
* The timer routine dispatches the clock adjustment code if its time
* has come, then searches the timer queue for expiries which are
* dispatched to the transmit procedure. Finally, we call the hourly
* procedure to do cleanup and print a message.
*/
/*
* Alarm flag. The mainline code imports this.
*/
volatile int alarm_flag;
/*
* adjust and hourly counters
*/
static u_long adjust_timer;
static u_long hourly_timer;
/*
* Imported from the leap module. The leap timer.
*/
extern u_long leap_timer;
/*
* Statistics counter for the interested.
*/
volatile u_long alarm_overflow;
/*
* Current_time holds the number of seconds since we started, in
* increments of 2**EVENT_TIMEOUT seconds. The timer queue is the
* hash into which we sort timer entries.
*/
/*
* Stats. Number of overflows and number of calls to transmit().
*/
#ifndef SYS_WINNT
static RETSIGTYPE alarming P((int));
#else
#endif /* SYS_WINNT */
#if defined(VMS)
#endif /* VMS */
/*
* init_timer - initialize the timer data structures
*/
void
{
register int i;
#if !defined(VMS)
# ifndef SYS_WINNT
#ifndef HAVE_TIMER_SETTIME
#else
timer without rebooting ... */
struct itimerspec itimer;
#endif
# else /* SYS_WINNT */
# endif /* SYS_WINNT */
#endif /* VMS */
/*
* Initialize...
*/
alarm_flag = 0;
alarm_overflow = 0;
adjust_timer = 1;
hourly_timer = HOUR;
current_time = 0;
timer_overflows = 0;
timer_xmtcalls = 0;
timer_timereset = 0;
for (i = 0; i < TIMER_NSLOTS; i++) {
/*
* Queue pointers should point at themselves. Event
* times must be set to 0 since this is used to
* detect the queue end.
*/
timerqueue[i].event_time = 0;
}
#ifndef SYS_WINNT
/*
* Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT
* seconds from now and they continue on every 2**EVENT_TIMEOUT
* seconds.
*/
# if !defined(VMS)
#if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
#ifdef SYS_VXWORKS
#else
-1
#endif
)
{
exit (0);
}
#else
#endif
# else /* VMS */
vmsinc[1] = 0;
# endif /* VMS */
#else /* SYS_WINNT */
_tzset();
/*
* Get privileges needed for fiddling with the clock
*/
/* get the current process token handle */
exit(1);
}
/* get the LUID for system-time privilege. */
/* get set-time privilege for this process. */
/* cannot test return value of AdjustTokenPrivileges. */
if (GetLastError() != ERROR_SUCCESS)
/*
* Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
* of a callback function (on a different thread) rather than
* generating an alarm signal
*/
/* determine max and min resolution supported */
exit(1);
}
/* establish the minimum timer resolution that we'll use */
NULL, /* no security attributes */
FALSE, /* initially not owned */
"MutexForNTP"); /* name of mutex */
exit(1);
}
/* start the timer event */
wTimerRes, /* Resolution */
(DWORD) 0, /* User data */
TIME_PERIODIC); /* Event type (periodic) */
if (wTimerID == 0) {
exit(1);
}
#endif /* SYS_WINNT */
}
#ifdef TIMERQUEUE_DEBUG
/* Timer queue sanity checking routines */
{
if ( ! ev )
}
{
if ( ! ev )
}
#else /* TIMERQUEUE_DEBUG */
# define EV_ASSERT() {}
# define EV_LINKCHK() {}
#endif /* TIMERQUEUE_DEBUG */
/*
* timer - dispatch anyone who needs to be
*/
void
timer()
{
#ifdef SYS_WINNT
#endif
/*
* Adjustment timeout first
*/
if (adjust_timer <= current_time) {
adjust_timer += 1;
}
#ifdef SYS_WINNT
if (!ReleaseMutex(hMutex)) {
exit(1);
}
#endif /* SYS_WINNT */
/*
* Leap timer next.
*/
leap_process();
/*
* Now dispatch any peers whose event timer has expired.
*/
/* Added mutex to prevent race condition among threads under Windows NT */
#ifdef SYS_WINNT
#endif /* SYS_WINNT */
#ifdef TIMERQUEUE_DEBUG
{
int i;
int j;
for (i = 0; i < TIMER_NSLOTS; ++i)
{
if (qh->event_time != 0) {
i, timerqueue[i].event_time);
abort();
}
j = 0;
do
{
i, j);
abort();
}
i, j);
abort();
}
++j;
}
}
}
#endif /* TIMERQUEUE_DEBUG */
if (tq) {
while (ev
&& ev->event_time != 0
}
if (!ev) {
abort();
}
} else {
abort();
}
/* Added mutex to prevent race condition among threads under Windows NT */
#ifdef SYS_WINNT
#endif /* SYS_WINNT */
/*
* Finally, call the hourly routine
*/
if (hourly_timer <= current_time) {
hourly_timer += HOUR;
hourly_stats();
}
}
#ifndef SYS_WINNT
/*
* alarming - tell the world we've been alarmed
*/
static RETSIGTYPE
int sig;
{
extern int initializing; /* from main line code */
#if !defined(VMS)
if (initializing)
return;
if (alarm_flag)
else
alarm_flag++;
#else /* VMS AST routine */
if (!initializing) {
if (alarm_flag) alarm_overflow++;
}
#endif /* VMS */
}
#else /* SYS_WINNT */
/*
* alarming for WinNT - invoke the timer() routine after grabbing the mutex
*/
{
extern int debug;
static int initializing2 = 1;
extern HANDLE TimerThreadHandle;
#ifdef DEBUG
#endif
/*
* set the priority for timer() thread to be higher than the main thread
*/
if (initializing2) {
initializing2 = 0;
}
#ifdef DEBUG
if (debug > 9) {
GetSystemTime(&st);
printf("thread %u (timer callback): time %02u:%02u:%02u:%03u\n",
}
#endif
hMutex, /* handle of mutex */
5000L); /* five-second time-out interval */
switch (dwWaitResult) {
case WAIT_OBJECT_0:
/* The thread got mutex ownership. */
/* the mutex is released in the timer() routine */
timer();
break;
default:
/* Cannot get mutex ownership due to time-out. */
exit(1);
}
}
#endif /* SYS_WINNT */
/*
* timer_clr_stats - clear timer module stat counters
*/
void
{
timer_overflows = 0;
timer_xmtcalls = 0;
}
#ifdef TIMERQUEUE_DEBUG
# ifdef SYS_WINNT /* WindowsNT apparently needs mutex locking around here */
# else
# define WINNT_WAIT() {}
# define WINNT_RELS() {}
# endif
/*
* TIMER_ENQUEUE() puts stuff on the timer queue. It takes as
* arguments (ea), an array of event slots, and (iev), the event
* to be inserted. This one searches the hash bucket from the
* end, and is about optimum for the timing requirements of
* NTP peers.
*/
{
WINNT_WAIT();
}
WINNT_RELS();
}
/*
* TIMER_INSERT() also puts stuff on the timer queue, but searches the
* bucket from the top. This is better for things that do very short
* time outs, like clock support.
*/
{
WINNT_WAIT();
while (ev->event_time != 0 &&
}
WINNT_RELS();
}
/*
* Remove an event from the queue.
*/
{
WINNT_WAIT();
}
WINNT_RELS();
}
#endif /* TIMERQUEUE_DEBUG */