]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
new Windows interpolation knocks out 1ms jitter in previous
authorDave Hart <hart@ntp.org>
Fri, 3 Apr 2009 03:49:05 +0000 (03:49 +0000)
committerDave Hart <hart@ntp.org>
Fri, 3 Apr 2009 03:49:05 +0000 (03:49 +0000)
remove dead code
thin #ifdef SYS_WINNT forest
64-bit time_t truncation fixes, warnings silenced
do not set hardware clock on exit unless system is shutting down

bk: 49d587313HSb-bCQSZOdBzqjB2vsdA

43 files changed:
ChangeLog
include/ntp_machine.h
include/ntp_stdlib.h
include/ntp_types.h
include/ntp_unixtime.h
libntp/Makefile.am
libntp/buftvtots.c
libntp/humandate.c
libntp/prettydate.c
libntp/systime.c
ntpd/ntp_config.c
ntpd/ntp_crypto.c
ntpd/ntp_intres.c
ntpd/ntp_timer.c
ntpd/ntpd.c
ntpd/refclock_dumbclock.c
ntpdate/ntpdate.c
ntpdc/ntpdc.c
ntpq/ntpq.c
ports/winnt/include/clockstuff.h
ports/winnt/include/config.h
ports/winnt/include/ntservice.h
ports/winnt/include/sys/resource.h
ports/winnt/include/sys/time.h
ports/winnt/libntp/SetSystemTime.c
ports/winnt/libntp/getclock.c [new file with mode: 0644]
ports/winnt/libntp/libntp.dsp
ports/winnt/libntp/libntp.vcproj
ports/winnt/libntp/randfile.c
ports/winnt/libntp/setpriority.c [new file with mode: 0644]
ports/winnt/libntp/syslog.c
ports/winnt/libntp/util_clockstuff.c
ports/winnt/ntp-keygen/ntp-keygen.vcproj
ports/winnt/ntp-keygen/ntpkeygen.vcproj [deleted file]
ports/winnt/ntpd/nt_clockstuff.c
ports/winnt/ntpd/ntp_iocompletionport.c
ports/winnt/ntpd/ntservice.c
ports/winnt/ntpd/win32_io.c
ports/winnt/ntpdate/ntpdate.vcproj
ports/winnt/ntpdc/ntpdc.vcproj
ports/winnt/ntpq/ntpq.vcproj
ports/winnt/scripts/mkver.bat
util/ntp-keygen.c

index 91466ac2cb272ca5d41bcf13fa9c14b4f556243e..18405829c870b169379c98768f07f65aa4cc782b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+* [Bug 216] New interpolation scheme for Windows eliminates 1ms jitter
+* remove a bunch of #ifdef SYS_WINNT from portable code
+* 64-bit time_t cleanup for building on newer Windows compilers
+* Only set CMOS clock during ntpd exit on Windows if the computer is
+  shutting down or restarting.
 (4.2.5p161) 2009/03/31 Released by Harlan Stenn <stenn@ntp.org>
 * Documentation updates from Dave Mills.
 (4.2.5p160) 2009/03/30 Released by Harlan Stenn <stenn@ntp.org>
index 1a28cd7d17dd45d1911cffa08a08dbabfc1f0a3a..cfe5258384ff5047ae5151d16fd1ea79a9615a37 100644 (file)
@@ -227,53 +227,11 @@ typedef unsigned long u_long;
  * make them macros for everyone else
  */
 #ifndef SYS_WINNT
-# define SOCKET        int
+typedef int SOCKET;
 # define INVALID_SOCKET        -1
 # define SOCKET_ERROR  -1
-# define closesocket close
+# define closesocket(fd)       close(fd)
 #endif
-/*
- * Windows NT
- */
-#if defined(SYS_WINNT)
-# if !defined(HAVE_CONFIG_H)  || !defined(__config)
-# include <config.h>
-# endif /* HAVE_CONFIG_H) */
-# include <windows.h>
-# include <ws2tcpip.h>
-# include <winsock2.h>
-
-# define ifreq _INTERFACE_INFO
-# define ifr_flags iiFlags
-# define ifr_addr iiAddress.AddressIn
-# define ifr_broadaddr iiBroadcastAddress.AddressIn
-# define ifr_mask iiNetmask.AddressIn
-# define zz_family sin_family
-
-# define S_IFREG _S_IFREG
-# define stat _stat
-# define isascii __isascii
-# define isatty _isatty
-# define mktemp _mktemp
-# define unlink _unlink
-# define fileno _fileno
-# define write _write
-#ifndef close
-# define close _close
-#endif
-# undef interface
-# include <process.h>
-#define getpid _getpid
-/*
- * Defining registers are not a good idea on Windows
- * This gets rid of the usage
- */
-#ifndef register
-# define register
-#endif
- typedef char *caddr_t;
-# define vsnprintf _vsnprintf
-#endif /* SYS_WINNT */
 
 int ntp_set_tod (struct timeval *tvp, void *tzp);
 
@@ -503,8 +461,7 @@ extern char *strdup(const char *);
 
 #if !defined(HAVE_ATT_NICE) \
        && !defined(HAVE_BSD_NICE) \
-       && !defined(HAVE_NO_NICE) \
-       && !defined(SYS_WINNT)
+       && !defined(HAVE_NO_NICE)
 #include "ERROR: You must define one of the HAVE_xx_NICE defines!"
 #endif
 
index 0c8834427ee1ec5922b66757831319176048be90..bfff4597ac37a4fcc7892250fa0a84bbfe32f29a 100644 (file)
@@ -65,7 +65,6 @@ extern        u_int32 addr2refid      (struct sockaddr_storage *);
 extern int     atoint          (const char *, long *);
 extern int     atouint         (const char *, u_long *);
 extern int     hextoint        (const char *, u_long *);
-extern char *  humandate       (u_long);
 extern char *  humanlogtime    (void);
 extern char *  inttoa          (long);
 extern char *  mfptoa          (u_long, u_long, short);
index 0f96027fe9462136961386d96d0270752b093751..580cf23aa0a435fb45844b14d21c535827a3a579 100644 (file)
 #undef mac
 #endif
 
+/*
+ * used to quiet compiler warnings
+ */
+#ifndef UNUSED_ARG
+#define UNUSED_ARG(arg)        ((void)(arg))
+#endif
+
 /*
  * VMS DECC (v4.1), {u_char,u_short,u_long} are only in SOCKET.H,
  *                     and u_int isn't defined anywhere
@@ -65,5 +72,16 @@ typedef unsigned short associd_t; /* association ID */
 typedef u_int32 keyid_t;       /* cryptographic key ID */
 typedef u_int32 tstamp_t;      /* NTP seconds timestamp */
 
+/*
+ * On Unix struct sock_timeval is equivalent to struct timeval.
+ * On Windows built with 64-bit time_t, sock_timeval.tv_sec is a long
+ * as required by Windows' socket() interface timeout argument, while
+ * timeval.tv_sec is time_t for the more common use as a UTC time 
+ * within NTP.
+ */
+#ifndef SYS_WINNT
+#define        sock_timeval    timeval
+#endif
+
 #endif /* _NTP_TYPES_ */
 
index f5fe546d101af06b379ba2037de9f9f4688551ad..8c43f1cea0372bf97561e24cf3fc03d40b319b65 100644 (file)
@@ -136,6 +136,3 @@ extern u_long msutotsfhi[];
 
 #define        MSUTOTSF(msu, tsf) \
        (tsf) = msutotsfhi[((msu) >> 5) & 0x1f] + msutotsflo[(msu) & 0x1f]
-
-extern char *  tvtoa           (const struct timeval *);
-extern char *  utvtoa          (const struct timeval *);
index 9b266214bcde80c8bff76434dceed6db1cc88ff3..5da1af1fda3b9c502f3d32ebffb7892ab42e6de2 100644 (file)
@@ -13,8 +13,8 @@ libntp_a_SRCS = a_md5encrypt.c adjtime.c atoint.c atolfp.c atouint.c \
        ntp_rfc2553.c numtoa.c numtohost.c octtoint.c prettydate.c \
        ntp_random.c recvbuff.c refnumtoa.c snprintf.c socktoa.c socktohost.c \
        statestr.c strdup.c strerror.c strstr.c \
-       syssignal.c tsftomsu.c tstotv.c tvtoa.c tvtots.c \
-       uglydate.c uinttoa.c utvtoa.c ymd2yd.c \
+       syssignal.c tsftomsu.c tstotv.c tvtots.c \
+       uglydate.c uinttoa.c ymd2yd.c \
        $(srcdir)/../libisc/assertions.c $(srcdir)/../libisc/error.c \
        $(srcdir)/../libisc/interfaceiter.c $(srcdir)/../libisc/lib.c \
        $(srcdir)/../libisc/log.c $(srcdir)/../libisc/md5.c \
index bfceb35da219a0b8f30a6e68cf5c3b6b039141ef..d6d9300f1241a0b17809fabca5be25d30100daea 100644 (file)
@@ -11,6 +11,7 @@
 #include "ntp_string.h"
 #include "ntp_unixtime.h"
 
+#ifndef SYS_WINNT
 int
 buftvtots(
        const char *bufp,
@@ -33,3 +34,20 @@ buftvtots(
        TVUTOTSF(tv.tv_usec, ts->l_uf);
        return 1;
 }
+#else  /* SYS_WINNT */
+/*
+ * Windows doesn't have the tty_clock line discipline, so
+ * don't look for a timestamp where there is none.
+ */
+int
+buftvtots(
+       const char *bufp,
+       l_fp *ts
+       )
+{
+       UNUSED_ARG(bufp);
+       UNUSED_ARG(ts);
+
+       return 0;
+}
+#endif /* SYS_WINNT */
index 630c8713347ee33d73363a24df1fa6f682220d50..e3614cf20a18c784c0383128f9e1809b2b558d0c 100644 (file)
@@ -7,36 +7,7 @@
 #include "lib_strbuf.h"
 #include "ntp_stdlib.h"
 
-static const char *months[] = {
-       "Jan", "Feb", "Mar", "Apr", "May", "Jun",
-       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-};
-static const char *days[] = {
-       "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
-};
-
-char *
-humandate(
-       u_long ntptime
-       )
-{
-       char *bp;
-       struct tm *tm;
-
-       tm = ntp2unix_tm(ntptime, 1);
-
-       if (!tm)
-               return "--- --- -- ---- --:--:--";
-
-       LIB_GETBUF(bp);
-       
-       (void) sprintf(bp, "%s, %s %2d %4d %2d:%02d:%02d",
-                      days[tm->tm_wday], months[tm->tm_mon], tm->tm_mday,
-                      1900+tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec);
-       
-       return bp;
-}
-
+extern const char *months[];   /* prettydate.c */
 
 /* This is used in msyslog.c; we don't want to clutter up the log with
    the year and day of the week, etc.; just the minimal date and time.  */
index 8ab1dbb0423731ed10a1986ab21da6d0a1d40e74..77458f00b303c6b4211683e577eb100b60430427 100644 (file)
@@ -9,7 +9,7 @@
 #include "ntp_stdlib.h"
 #include "ntp_assert.h"
 
-static const char *months[] = {
+const char *months[] = {
   "Jan", "Feb", "Mar", "Apr", "May", "Jun",
   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
 };
@@ -150,14 +150,16 @@ ntp2unix_tm(
        return tm;
 }
 
+
 char *
-prettydate(
-       l_fp *ts
+common_prettydate(
+       l_fp *ts,
+       int local
        )
 {
        char *bp;
        struct tm *tm;
-       time_t sec;
+       u_long sec;
        u_long msec;
 
        LIB_GETBUF(bp);
@@ -165,7 +167,7 @@ prettydate(
        sec = ts->l_ui;
        msec = ts->l_uf / 4294967;      /* fract / (2 ** 32 / 1000) */
 
-       tm = ntp2unix_tm(sec, 1);
+       tm = ntp2unix_tm(sec, local);
        if (!tm) {
                (void) sprintf(bp, "%08lx.%08lx  --- --- -- ---- --:--:--",
                       (u_long)ts->l_ui, (u_long)ts->l_uf);
@@ -180,32 +182,20 @@ prettydate(
        return bp;
 }
 
+
 char *
-gmprettydate(
+prettydate(
        l_fp *ts
        )
 {
-       char *bp;
-       struct tm *tm;
-       time_t sec;
-       u_long msec;
+       return common_prettydate(ts, 1);
+}
 
-       LIB_GETBUF(bp);
-       
-       sec = ts->l_ui;
-       msec = ts->l_uf / 4294967;      /* fract / (2 ** 32 / 1000) */
 
-       tm = ntp2unix_tm(sec, 0);
-       if (!tm) {
-               (void) sprintf(bp, "%08lx.%08lx  --- --- -- ---- --:--:--",
-                      (u_long)ts->l_ui, (u_long)ts->l_uf);
-       }
-       else {
-               (void) sprintf(bp, "%08lx.%08lx  %s, %s %2d %4d %2d:%02d:%02d.%03lu",
-                      (u_long)ts->l_ui, (u_long)ts->l_uf, days[tm->tm_wday],
-                      months[tm->tm_mon], tm->tm_mday, 1900 + tm->tm_year,
-                      tm->tm_hour,tm->tm_min, tm->tm_sec, msec);
-       }
-
-       return bp;
+char *
+gmprettydate(
+       l_fp *ts
+       )
+{
+       return common_prettydate(ts, 0);
 }
index c1ddd3d8ce52b7e83553b29b979ed0f04e5bd730..0dfe3eeed0ca840ec0d03f68f65d898ec2d58541 100644 (file)
@@ -76,7 +76,7 @@ get_systime(
 # else
        getclock(TIMEOFDAY, &ts);
 # endif
-       now->l_i = ts.tv_sec + JAN_1970;
+       now->l_i = (int32)ts.tv_sec + JAN_1970;
        dtemp = ts.tv_nsec + (ntp_random() * 2. / FRAC) * sys_tick *
            1e6;
        dtemp = dtemp / 1e9 + sys_residual;
index 5d448f2bc4497d4cef953fdc13a640ab42f48769..105e6a03471d114cb677ed6e7474ec32e3e5133d 100644 (file)
@@ -953,7 +953,7 @@ config_other_modes(void)
                            dequeue(my_config.manycastserver);
 
                        memset((char *)&addr_sock, 0, sizeof(addr_sock));
-                       addr_sock.ss_family = addr_node->type;
+                       addr_sock.ss_family = (u_short)addr_node->type;
 
                        if (getnetnum(addr_node->address, &addr_sock, 1, t_UNK)  == 1)
                                proto_config(PROTO_MULTICAST_ADD, 0, 0., &addr_sock);
@@ -971,7 +971,7 @@ config_other_modes(void)
                            dequeue(my_config.multicastclient);
 
                        memset((char *)&addr_sock, 0, sizeof(addr_sock));
-                       addr_sock.ss_family = addr_node->type;
+                       addr_sock.ss_family = (u_short)addr_node->type;
 
                        if (getnetnum(addr_node->address, &addr_sock, 1, t_UNK)  == 1)
                                proto_config(PROTO_MULTICAST_ADD, 0, 0., &addr_sock);
@@ -1226,7 +1226,7 @@ config_access(void)
                /* Check if the user specified a default rule */
                if (my_node->addr) {
                        /* Resolve the specified address */
-                       addr_sock.ss_family = my_node->addr->type;
+                       addr_sock.ss_family = (u_short)my_node->addr->type;
 
                        if (getnetnum(my_node->addr->address,
                                      &addr_sock, 1,t_UNK) != 1) {
@@ -1247,7 +1247,7 @@ config_access(void)
                        /* Resolve the mask */
                        if (my_node->mask) {
                                memset((char *)&addr_mask, 0, sizeof(addr_mask));
-                               addr_mask.ss_family = my_node->mask->type;
+                               addr_mask.ss_family = (u_short)my_node->mask->type;
                                if (getnetnum(my_node->mask->address, &addr_mask, 1, t_MSK) != 1) {
                                        /* Error in mask !!!
                                         * Free the node memory and move onto the next
@@ -1476,7 +1476,7 @@ config_trap(void)
 
                                /* Resolve the interface address */
                                memset((char *)&addr_sock, 0, sizeof(addr_sock));
-                               addr_sock.ss_family = addr_node->type;
+                               addr_sock.ss_family = (u_short)addr_node->type;
 
                                if (getnetnum(addr_node->address,
                                              &addr_sock, 1, t_UNK) != 1) {
@@ -1817,7 +1817,7 @@ config_peers(void)
 
                /* Attempt to resolve the address */
                memset((char *)&peeraddr, 0, sizeof(peeraddr));
-               peeraddr.ss_family = curr_peer->addr->type;
+               peeraddr.ss_family = (u_short)curr_peer->addr->type;
 
                status = get_multiple_netnums(curr_peer->addr->address, &peeraddr, &res, 0, t_UNK);
 
index 57f2572de21c52771110425b08318f8a068e8b4d..43211b3317d874fef1411229287c4c38af80c7f2 100644 (file)
@@ -1934,7 +1934,7 @@ asn2ntp   (
        tm.tm_wday = 0;
        tm.tm_yday = 0;
        tm.tm_isdst = 0;
-       return (timegm(&tm) + JAN_1970);
+       return ((u_long)timegm(&tm) + JAN_1970);
 }
 
 
index 2bba8caafb5d3148f967a98ea1bae0babf166f62..7d2e96df7dd923279941b36d1247fabb375cda86 100644 (file)
@@ -651,7 +651,7 @@ request(
        )
 {
        fd_set fdset;
-       struct timeval tvout;
+       struct sock_timeval tvout;
        struct req_pkt reqpkt;
        l_fp ts;
        int n;
index be3bfb0510325033cb1db7ba8e9d4af281177973..a384746bb438fbc0f64637117b49d16ed9c97fe0 100644 (file)
@@ -150,11 +150,6 @@ reinit_timer(void)
 void
 init_timer(void)
 {
-# if defined SYS_WINNT & !defined(SYS_CYGWIN32)
-       HANDLE hToken = INVALID_HANDLE_VALUE;
-       TOKEN_PRIVILEGES tkp;
-# endif /* SYS_WINNT */
-
        /*
         * Initialize...
         */
@@ -209,28 +204,6 @@ init_timer(void)
        sys$setimr(0, &vmstimer, alarming, alarming, 0);
 # endif /* VMS */
 #else /* SYS_WINNT */
-       _tzset();
-
-       /*
-        * Get privileges needed for fiddling with the clock
-        */
-
-       /* get the current process token handle */
-       if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
-               msyslog(LOG_ERR, "OpenProcessToken failed: %m");
-               exit(1);
-       }
-       /* get the LUID for system-time privilege. */
-       LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
-       tkp.PrivilegeCount = 1;  /* one privilege to set */
-       tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
-       /* get set-time privilege for this process. */
-       AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
-       /* cannot test return value of AdjustTokenPrivileges. */
-       if (GetLastError() != ERROR_SUCCESS) {
-               msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
-       }
-
        /*
         * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
         * Under Windows/NT, 
index 9c08c3b02864a915cfbf018edba2e7b725f2b267..d37448766c18362285631d456185d9b57b6efa74 100644 (file)
@@ -380,10 +380,6 @@ set_process_priority(void)
                        priority_done);
 #endif /* DEBUG */
 
-#ifdef SYS_WINNT
-       priority_done += NT_set_process_priority();
-#endif
-
 #if defined(HAVE_SCHED_SETSCHEDULER)
        if (!priority_done) {
                extern int config_priority_override, config_priority;
index a8d5e8d9a79de17cdef5f9543f0f9dc55d01ab3a..e0ab669ed0e990ad36ce8486385f115e5182c415 100644 (file)
@@ -249,7 +249,7 @@ dumbclock_receive(
            struct tm  asserted_tm;          /* the struct tm of the same */
            int        adjyear;
            int        adjmon;
-           int        reality_delta;
+           time_t     reality_delta;
            time_t     now;
 
 
index 734c06b0cbca01e528bd8d7785cbac3f2c40bf38..8307b13b8f01ca51fb8b1890ec8bf9f1ee0bc810 100644 (file)
@@ -65,7 +65,7 @@ struct timeval timeout = {0,0};
  * Windows does not abort a select select call if SIGALRM goes off
  * so a 200 ms timeout is needed
  */
-struct timeval timeout = {0,1000000/TIMER_HZ};
+struct sock_timeval timeout = {0,1000000/TIMER_HZ};
 #else
 struct timeval timeout = {60,0};
 #endif
@@ -239,7 +239,6 @@ static      void    printserver (struct server *, FILE *);
 int    on = 1;
 WORD   wVersionRequested;
 WSADATA        wsaData;
-HANDLE TimerThreadHandle = NULL;
 #endif /* SYS_WINNT */
 
 #ifdef NO_MAIN_ALLOWED
@@ -463,12 +462,7 @@ ntpdatemain (
        if (debug || simple_query) {
 #ifdef HAVE_SETVBUF
                static char buf[BUFSIZ];
-#ifdef SYS_WINNT
-               /* Win32 does not implement line buffering */
-               setvbuf(stdout, NULL, _IONBF, BUFSIZ);
-#else
                setvbuf(stdout, buf, _IOLBF, BUFSIZ);
-#endif /* SYS_WINNT */
 #else
                setlinebuf(stdout);
 #endif
@@ -561,13 +555,6 @@ ntpdatemain (
 #if defined(HAVE_BSD_NICE)
        (void) setpriority(PRIO_PROCESS, 0, NTPDATE_PRIO);
 #endif
-#ifdef SYS_WINNT
-       process_handle = GetCurrentProcess();
-       if (!SetPriorityClass(process_handle, (DWORD) REALTIME_PRIORITY_CLASS)) {
-               msyslog(LOG_ERR, "SetPriorityClass failed: %m");
-       }
-#endif /* SYS_WINNT */
-
 
 
        initializing = 0;
@@ -1530,12 +1517,12 @@ alarming(
 void CALLBACK 
 alarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
 {
+       UNUSED_ARG(uTimerID); UNUSED_ARG(uMsg); UNUSED_ARG(dwUser);
+       UNUSED_ARG(dw1); UNUSED_ARG(dw2);
+
        alarm_flag++;
 }
-#endif /* SYS_WINNT */
 
-
-#ifdef SYS_WINNT
 static void
 callTimeEndPeriod(void)
 {
@@ -1910,7 +1897,7 @@ input_handler(void)
 {
        register int n;
        register struct recvbuf *rb;
-       struct timeval tvzero;
+       struct sock_timeval tvzero;
        int fromlen;
        l_fp ts;
        int i;
index 0e7b395ec2d6408d28ae7dd721d9b2d3443567dc..8034b1e40350ad7de4f251ad398e47eff006a840 100644 (file)
@@ -177,8 +177,8 @@ static      struct xcmd builtins[] = {
 /*
  * Some variables used and manipulated locally
  */
-static struct timeval tvout = { DEFTIMEOUT, 0 };       /* time out for reads */
-static struct timeval tvsout = { DEFSTIMEOUT, 0 };     /* secondary time out */
+static struct sock_timeval tvout = { DEFTIMEOUT, 0 };  /* time out for reads */
+static struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */
 static l_fp delay_time;                                /* delay time */
 static char currenthost[LENHOSTNAME];                  /* current host name */
 int showhostnames = 1;                                 /* show host names by default */
@@ -189,18 +189,6 @@ static     SOCKET sockfd;                                  /* fd socket is opened on */
 static int havehost = 0;                               /* set to 1 when host open */
 int s_port = 0;
 
-#if defined (SYS_WINNT) || defined (SYS_VXWORKS)
-char password[9];
-#endif /* SYS_WINNT || SYS_VXWORKS */
-
-#ifdef SYS_WINNT
-DWORD NumberOfBytesWritten;
-
-HANDLE TimerThreadHandle = NULL;       /* 1998/06/03 - Used in ntplib/machines.c */
-void timer(void)       {  ; }; /* 1998/06/03 - Used in ntplib/machines.c */
-
-#endif /* SYS_WINNT */
-
 /*
  * Holds data returned from queries.  We allocate INITDATASIZE
  * octets to begin with, increasing this as we need to.
@@ -684,7 +672,7 @@ getresponse(
        )
 {
        struct resp_pkt rpkt;
-       struct timeval tvo;
+       struct sock_timeval tvo;
        int items;
        int i;
        int size;
@@ -1015,7 +1003,7 @@ doquery(
        int res;
        char junk[512];
        fd_set fds;
-       struct timeval tvzero;
+       struct sock_timeval tvzero;
 
        /*
         * Check to make sure host is open
index 54d265f5e0a674aa91880ca384171cfb5f06089f..7a62e8d2936a4e8d28490688b87b33bfeb2ad961 100644 (file)
@@ -383,8 +383,8 @@ struct xcmd builtins[] = {
 /*
  * Some variables used and manipulated locally
  */
-struct timeval tvout = { DEFTIMEOUT, 0 };      /* time out for reads */
-struct timeval tvsout = { DEFSTIMEOUT, 0 };    /* secondary time out */
+struct sock_timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */
+struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */
 l_fp delay_time;                               /* delay time */
 char currenthost[LENHOSTNAME];                 /* current host name */
 struct sockaddr_in hostaddr = { 0 };           /* host address */
@@ -846,7 +846,7 @@ getresponse(
        )
 {
        struct ntp_control rpkt;
-       struct timeval tvo;
+       struct sock_timeval tvo;
        u_short offsets[MAXFRAGS+1];
        u_short counts[MAXFRAGS+1];
        u_short offset;
@@ -2218,11 +2218,11 @@ timeout(
        int val;
 
        if (pcmd->nargs == 0) {
-               val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
+               val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
                (void) fprintf(fp, "primary timeout %d ms\n", val);
        } else {
                tvout.tv_sec = pcmd->argval[0].uval / 1000;
-               tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000))
+               tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000))
                        * 1000;
        }
 }
index d578664889e3eed89ecf1ec218c2def2cf77fa9d..64f3a8088735d2111d4e208d32a604a62bb68dae 100644 (file)
@@ -7,14 +7,8 @@
 
 #include "ntp_syslog.h"
 
-/* Windows NT versions of gettimeofday and settimeofday
- *
- * ftime() has internal DayLightSavings related BUGS
- * therefore switched to GetSystemTimeAsFileTime()
- */
 
 void init_winnt_time(void);
-void shutdown_winnt_time(void);
 void reset_winnt_time(void);
 
 /* 100ns intervals between 1/1/1601 and 1/1/1970 as reported by
@@ -22,7 +16,7 @@ void reset_winnt_time(void);
  */
 
 #define FILETIME_1970     0x019db1ded53e8000
-#define HECTONANOSECONDS  10000000ui64
+#define HECTONANOSECONDS  10000000
 
 /*
  * Multimedia Timer
@@ -34,4 +28,35 @@ enum {
        MM_TIMER_LORES,
        MM_TIMER_HIRES
 };
+
+/*
+ * Optional callback from libntp ntp_set_tod() to Windows ntpd code
+ * in nt_clockstuff that needs to know.  Optional because other
+ * libntp clients like ntpdate don't use it.
+ */
+
+typedef void (*time_stepped_callback)(void);
+extern time_stepped_callback   step_callback;
+
+/*
+ * get_sys_time_as_filetime is a function pointer to
+ * either GetSystemTimeAsFileTime provided by Windows
+ * or ntpd's interpolating replacement.
+ */
+
+typedef void (WINAPI *PGSTAFT)(LPFILETIME pft);
+extern PGSTAFT get_sys_time_as_filetime;
+
+void lock_thread_to_processor(HANDLE);
+
+#ifdef HAVE_PPSAPI
+/*
+ * ntp_timestamp_from_counter provides an interface for 
+ * serialpps.sys counterstamps to be converted to 
+ * interpolated timestamps.
+ */
+
+extern void ntp_timestamp_from_counter(l_fp *, ULONGLONG, ULONGLONG);
+#endif
+
 #endif
index 749e0b0eb79202ea271fd43407b3eed3ffc6a869..69e7c47952447349f9359c28ec963977112884c4 100644 (file)
 /* #define _WSPIAPI_H_ */ /* need these wrappers for ntpd.exe to load on w2k */
 #endif
 
+/*
+ * On Unix struct sock_timeval is equivalent to struct timeval.
+ * On Windows built with 64-bit time_t, sock_timeval.tv_sec is a long
+ * as required by Windows' socket() interface timeout argument, while
+ * timeval.tv_sec is time_t for the more common use as a UTC time 
+ * within NTP.
+ *
+ * winsock.h unconditionally defines struct timeval with long tv_sec
+ * instead of time_t tv_sec.  We redirect its declaration to struct 
+ * sock_timeval instead of struct timeval with a #define.
+ */
+#define        timeval sock_timeval
+
 /* Include Windows headers */
 #include <windows.h>
 #include <winsock.h>
 #include <ws2tcpip.h>
 
+
 /*
  * Some definitions we are using are missing in the headers
  * shipping with VC6. However, if the SDK is installed then the 
  * needed before including headers.
  */
 
+#undef timeval /* see sock_timeval #define and comment above */
+struct timeval {
+       time_t  tv_sec;
+       long    tv_usec;
+};
+
 /*
  * IPv6 requirements
  */
@@ -148,8 +168,8 @@ typedef int socklen_t;
  */
 #define FORCE_DNSRETRY 1 
 
-#define OPEN_BCAST_SOCKET      1 /* for        ntp_io.c */
-#define TYPEOF_IP_MULTICAST_LOOP BOOL                                                                                          
+#define OPEN_BCAST_SOCKET      1 /* for ntp_io.c */
+#define TYPEOF_IP_MULTICAST_LOOP BOOL
 #define SETSOCKOPT_ARG_CAST (const char *)
 #define HAVE_RANDOM 
 #define MAXHOSTNAMELEN 64
@@ -217,8 +237,6 @@ typedef __int32 int32_t;    /* define a typedef for int32_t */
 # define strerror      NTstrerror
 char *NTstrerror(int errnum);
 
-int NT_set_process_priority(void);     /* Define this function */
-
 # define MCAST                         /* Enable Multicast Support */
 # define MULTICAST_NONEWSOCKET         /* Don't create a new socket for mcast address */
 
@@ -243,7 +261,7 @@ int NT_set_process_priority(void);  /* Define this function */
 # define NTP_POSIX_SOURCE
 
 # define SYSLOG_FILE                   /* from libntp.mak */
-# define SYSV_TIMEOFDAY                        /* for ntp_unixtime.h */
+# define HAVE_GETCLOCK
 
 # define SIZEOF_SIGNED_CHAR    1
 # define SIZEOF_INT            4       /* for ntp_types.h */
@@ -270,6 +288,10 @@ int NT_set_process_priority(void); /* Define this function */
 #define HAVE_STRDUP    1
 #define HAVE_STRCHR    1
 #define HAVE_FCNTL_H   1
+#define HAVE_SYS_RESOURCE_H
+#define HAVE_BSD_NICE                  /* emulate BSD setpriority() */
+
+typedef char *caddr_t;
 
 #ifndef _INTPTR_T_DEFINED
 typedef long intptr_t;
index 550300cc680fe74697820b7466a6aa24f56b2fd7..c5e5f42c3e3fcb5249dc7011e3b7e1c16833a576 100644 (file)
 
 void ntservice_init();
 void UpdateSCM(DWORD);
-void ServiceControl(DWORD dwCtrlCode);
+void WINAPI ServiceControl(DWORD dwCtrlCode);
 void ntservice_shutdown();
 BOOL ntservice_isservice();
+BOOL ntservice_systemisshuttingdown();
 BOOL WINAPI OnConsoleEvent(DWORD dwCtrlType);
 
 #endif
\ No newline at end of file
index 5e1599737300d0528dfcadd045ae4ce7ff2cfc63..01f4c810ff7f98036b7f99c7a56d5bfeaaa5375c 100644 (file)
@@ -1,4 +1,10 @@
-/**************************************************************
- * Dummy Header for Unix to Windows NT portability
- * Created for NTP package
- **************************************************************/
+/*
+ * ports/winnt/include/sys/resource.h
+ *
+ * routines declared in Unix systems' sys/resource.h
+ */
+
+#define        PRIO_PROCESS    0
+#define        NTP_PRIO        (-12)
+
+int setpriority(int, int, int);                /* winnt\libntp\setpriority.c */
index e27cce692d54f1d4bf8f30f452ed2ecd69e4e6a5..d8f734c76980813e8007b74d56d3dd1c2446b73b 100644 (file)
@@ -1,7 +1,8 @@
-/**************************************************************
- * Dummy Header for Unix to Windows NT portability
- * Created for NTP package
- **************************************************************/
+/*
+ * ports/winnt/include/sys/time.h
+ *
+ * routines declared in Unix systems' sys/time.h
+ */
 
 #ifndef SYS_TIME_H
 #define SYS_TIME_H
 #include <time.h>
 #include <sys/timeb.h>
 
-extern int gettimeofday (struct timeval *);
-extern int settimeofday (struct timeval *);
+typedef struct timespec {
+       time_t  tv_sec;
+       long    tv_nsec;
+} timespec_t;
+
+#define TIMEOFDAY      0       /* getclock() clktyp arg */
+extern int getclock(int, struct timespec *ts);
+extern int gettimeofday(struct timeval *, int);
+extern int settimeofday(struct timeval *);
 
 #endif /* SYS_TIME_H */
index 1465719ce9f06f4b2b55a91d1b39d8ea48426751..b4c2288bb32253c24afbe1bbb2d80039e4aa1cce 100644 (file)
@@ -2,7 +2,9 @@
 #include "clockstuff.h"
 #include "ntp_stdlib.h"
 
-const char *   set_tod_using = "SetSystemTime";
+const char *set_tod_using = "SetSystemTime";
+
+time_stepped_callback  step_callback = NULL;
 
 int
 ntp_set_tod(
@@ -11,24 +13,24 @@ ntp_set_tod(
        )
 {
        SYSTEMTIME st;
-       struct tm *gmtm;
-       const time_t x = tv->tv_sec;
-       long y = tv->tv_usec;
-       (void) tzp;
-
-       gmtm = gmtime(&x);
-       st.wSecond              = (WORD) gmtm->tm_sec;
-       st.wMinute              = (WORD) gmtm->tm_min;
-       st.wHour                = (WORD) gmtm->tm_hour;
-       st.wDay                 = (WORD) gmtm->tm_mday;
-       st.wMonth               = (WORD) (gmtm->tm_mon  + 1);
-       st.wYear                = (WORD) (gmtm->tm_year + 1900);
-       st.wDayOfWeek           = (WORD) gmtm->tm_wday;
-       st.wMilliseconds        = (WORD) (y / 1000);
-
-       if (!SetSystemTime(&st)) {
+       union {
+               FILETIME ft;
+               ULONGLONG ull;
+       } t;
+
+       UNUSED_ARG(tzp);
+
+       t.ull = FILETIME_1970 +
+               (ULONGLONG)tv->tv_sec * 10 * 1000 * 1000 +
+               (ULONGLONG)tv->tv_usec * 10;
+
+       if (!FileTimeToSystemTime(&t.ft, &st) || !SetSystemTime(&st)) {
                msyslog(LOG_ERR, "SetSystemTime failed: %m\n");
                return -1;
        }
+
+       if (step_callback)
+               (*step_callback)();
+
        return 0;
 }
diff --git a/ports/winnt/libntp/getclock.c b/ports/winnt/libntp/getclock.c
new file mode 100644 (file)
index 0000000..a53a5c9
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * getclock.c - Emulate Unix getclock(3) nanosecond interface for libntp/ntpd
+ */
+#include "config.h"
+#include "clockstuff.h"
+#include "ntp_stdlib.h"
+
+/*
+ * getclock() is in libntp.  To use interpolation, 
+ * ports/winnt/ntpd/nt_clockstuff.c overrides GetSystemTimeAsFileTime 
+ * via the pointer get_sys_time_as_filetime.
+ */
+PGSTAFT get_sys_time_as_filetime;
+
+int
+getclock(
+       int             clktyp,
+       struct timespec *ts
+       )
+{
+       union {
+               FILETIME ft;
+               ULONGLONG ull;
+       } uNow;
+
+       if (clktyp != TIMEOFDAY) {
+#ifdef DEBUG
+               if (debug) {
+                       printf("getclock() supports only TIMEOFDAY clktyp\n");
+               }
+#endif
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (! get_sys_time_as_filetime)
+               get_sys_time_as_filetime = GetSystemTimeAsFileTime;
+
+       (*get_sys_time_as_filetime)(&uNow.ft);
+
+       /* 
+        * Convert the hecto-nano second time to timespec format
+        */
+       uNow.ull -= FILETIME_1970;
+       ts->tv_sec = (time_t)( uNow.ull / HECTONANOSECONDS);
+       ts->tv_nsec = (long)(( uNow.ull % HECTONANOSECONDS) * 100);
+
+       return 0;
+}
index 78b2a6ca39dd3584b405063e8e9f430abad6b01c..4e29403f63338365f2fadc1d243476497c4664aa 100644 (file)
@@ -86,6 +86,14 @@ LIB32=link.exe -lib
 # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
 # Begin Source File
 
+SOURCE=.\getclock.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\setpriority.c
+# End Source File
+# Begin Source File
+
 SOURCE=..\..\..\libntp\a_md5encrypt.c
 # End Source File
 # Begin Source File
index 322db117ed2311384872702bf639c6ef4524a475..85f5983d178ad8b206815dea82f51dca09276941 100644 (file)
                                        />
                                </FileConfiguration>
                        </File>
+                       <File
+                               RelativePath=".\getclock.c"
+                               >
+                       </File>
                        <File
                                RelativePath="..\..\..\libntp\getopt.c"
                                >
                        <File
                                RelativePath="..\..\..\libntp\humandate.c"
                                >
-                               <FileConfiguration
-                                       Name="Debug|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                               <FileConfiguration
-                                       Name="Release|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
                        </File>
                        <File
                                RelativePath="..\..\..\libisc\inet_aton.c"
                                        />
                                </FileConfiguration>
                        </File>
+                       <File
+                               RelativePath=".\setpriority.c"
+                               >
+                       </File>
                        <File
                                RelativePath="SetSystemTime.c"
                                >
                                        />
                                </FileConfiguration>
                        </File>
-                       <File
-                               RelativePath="..\..\..\libntp\tvtoa.c"
-                               >
-                               <FileConfiguration
-                                       Name="Debug|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                               <FileConfiguration
-                                       Name="Release|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                       </File>
                        <File
                                RelativePath="..\..\..\libntp\tvtots.c"
                                >
                                </FileConfiguration>
                        </File>
                        <File
-                               RelativePath="..\..\..\libntp\utvtoa.c"
+                               RelativePath=".\util_clockstuff.c"
                                >
-                               <FileConfiguration
-                                       Name="Debug|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                               <FileConfiguration
-                                       Name="Release|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
                        </File>
                        <File
                                RelativePath="..\libisc\win32os.c"
                                RelativePath="..\..\..\include\recvbuff.h"
                                >
                        </File>
+                       <File
+                               RelativePath="..\include\sys\resource.h"
+                               >
+                       </File>
                        <File
                                RelativePath="..\include\sys\signal.h"
                                >
index 80689174df1be66f9cd3a310908b0d9a9a51aff7..75a184b052775b16bbf40cc318b914cfcf268679 100644 (file)
@@ -44,8 +44,9 @@ init_randfile()
         * a .rnd file is in there.
         */
        homedir = getenv("HOME");
-       if (homedir != NULL) {
-               strcpy(tmp, homedir);
+       if (homedir != NULL &&
+           (strlen(homedir) + 5 /* \.rnd */) < sizeof(tmp)) {
+               strncpy(tmp, homedir, sizeof(tmp));
                strcat(tmp, "\\.rnd");
                rf = fopen(tmp, "rb");
                if (rf != NULL) {
diff --git a/ports/winnt/libntp/setpriority.c b/ports/winnt/libntp/setpriority.c
new file mode 100644 (file)
index 0000000..31cfc8a
--- /dev/null
@@ -0,0 +1,79 @@
+#include <config.h>
+#include <windows.h>
+#include <stdio.h>
+#include <sys/resource.h>      /* our private version */
+#include "ntp_machine.h"
+#include "ntp_stdlib.h"
+#include "ntp_syslog.h"
+#include "ntp_debug.h"
+#include "ntp_fp.h"
+#include "ntp.h"
+#include "clockstuff.h"
+
+
+/*
+ * setpriority
+ *
+ * to reduce the #ifdef forest in the portable code,
+ * we emulate the BSD setpriority interface:
+ *
+ *             if (-1 == setpriority(PRIO_PROCESS, 0, NTP_PRIO))
+ *                     msyslog(LOG_ERR, "setpriority() error: %m");
+ *
+ * However, since the Windows port of ntpd has always raised its
+ * priority (to realtime if allowed, or silently downgraded to 
+ * high by the system if not) with or without -N.  Changing that
+ * now would endanger users who upgrade the binary without adding
+ * -N to its invocation.  Instsrv assumes ntpd.exe is installed
+ * with no command-line arguments.
+ *
+ * This routine is used by utilities as well as ntpd itself, so
+ * it checks if the priority is already high or realtime and 
+ * logs no complaints in that case, to avoid duplicating.  ntpd
+ * will have raised the priority to one of those in
+ * init_winnt_time, while the utilities will rely on this
+ * code.
+ *
+ */
+
+int setpriority(
+               int which,
+               int who,
+               int prio
+               )
+{
+       BOOL success;
+       DWORD prio_class;
+
+       if (PRIO_PROCESS != which || who || NTP_PRIO != prio) {
+               DPRINTF(1,("windows setpriority() clone needs work.\n"));
+       }
+
+       prio_class = GetPriorityClass(GetCurrentProcess());
+       
+       if (HIGH_PRIORITY_CLASS == prio_class ||
+           REALTIME_PRIORITY_CLASS == prio_class)
+               return 0;
+
+       success = SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
+
+       if (!success) {
+               msyslog(LOG_ERR, "Unable to raise priority: %m"); 
+               errno = EPERM;
+               return -1;
+       }
+
+       prio_class = GetPriorityClass(GetCurrentProcess());
+
+       if (REALTIME_PRIORITY_CLASS == prio_class)
+               msyslog(LOG_INFO, "Raised to realtime priority class");
+       else if (HIGH_PRIORITY_CLASS == prio_class)
+               msyslog(LOG_ERR,  "Raised to high priority class, realtime "
+                                 "requires Increase Scheduling Priority "
+                                 "privilege (enabled with secpol.msc).");
+       else
+               msyslog(LOG_ERR,  "Unexpected process priority class %d",
+                                prio_class);
+
+       return 0; 
+}
index ad1ff93df5148144f7a2aead5781eff76045de94..ad492324f05c110c5ee6386498c4a78543587caa 100644 (file)
@@ -131,7 +131,8 @@ void
 openlog(const char *name, int flags, ...) {
        /* Get a handle to the Application event log */
        hAppLog = RegisterEventSource(NULL, progname);
-       strcpy(progname, name);
+       strncpy(progname, name, sizeof(progname));
+       progname[sizeof(progname) - 1] = 0;
 }
 
 /*
index b6c593ae1435b7941857c99b30319ee45ffdf4c1..3b1dc39c829981bf43aab2019ea8dce85ec87c73 100644 (file)
@@ -2,32 +2,24 @@
 #include "config.h"
 #endif
 
+#include "ntp_syslog.h"
+#include "ntp_stdlib.h"
 #include "clockstuff.h"
 
-DWORD units_per_tick = 0;
-DOUBLE ppm_per_adjust_unit = 0.0; /* to satisfy libntp */
-
 int
 gettimeofday(
-       struct timeval *tv
+       struct timeval *tv,
+       int ignored
        )
 {
-       /*  Use the system time (roughly synchronised to the tick, and
-        *  extrapolated using the system performance counter.
-        */
+       struct timespec ts;
 
-       FILETIME StartTime;
-       ULONGLONG Time;
+       UNUSED_ARG(ignored);
 
-       GetSystemTimeAsFileTime(&StartTime);
-       Time = (((ULONGLONG) StartTime.dwHighDateTime) << 32) + 
-               (ULONGLONG) StartTime.dwLowDateTime;
+       getclock(TIMEOFDAY, &ts);
 
-       /* Convert the hecto-nano second time to tv format
-        */
-       Time -= FILETIME_1970;
-       tv->tv_sec = (LONG) ( Time / 10000000ui64);
-       tv->tv_usec = (LONG) (( Time % 10000000ui64) / 10);
+       tv->tv_sec = ts.tv_sec;
+       tv->tv_usec = ts.tv_nsec / 10;
 
        return 0;
 }
index 892d13a7cf16c139392b62a8fde557da2b0e0d32..6dc6147c4d4d111508470b2fa6261c7925ca0cdd 100644 (file)
                                        />
                                </FileConfiguration>
                        </File>
-                       <File
-                               RelativePath="..\libntp\util_clockstuff.c"
-                               >
-                               <FileConfiguration
-                                       Name="Debug|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                               <FileConfiguration
-                                       Name="Release|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                       </File>
                        <File
                                RelativePath="version.c"
                                >
diff --git a/ports/winnt/ntp-keygen/ntpkeygen.vcproj b/ports/winnt/ntp-keygen/ntpkeygen.vcproj
deleted file mode 100644 (file)
index 892d13a..0000000
+++ /dev/null
@@ -1,419 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
-       ProjectType="Visual C++"
-       Version="9.00"
-       Name="ntp-keygen"
-       ProjectGUID="{C88C1FBF-59D2-447F-BF57-0BCA8889028F}"
-       RootNamespace="ntp-keygen"
-       TargetFrameworkVersion="0"
-       >
-       <Platforms>
-               <Platform
-                       Name="Win32"
-               />
-       </Platforms>
-       <ToolFiles>
-       </ToolFiles>
-       <Configurations>
-               <Configuration
-                       Name="Debug|Win32"
-                       OutputDirectory=".\Debug"
-                       IntermediateDirectory=".\Debug"
-                       ConfigurationType="1"
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
-                       UseOfMFC="0"
-                       ATLMinimizesCRunTimeLibraryUsage="false"
-                       CharacterSet="2"
-                       DeleteExtensionsOnClean="version.c,*.obj;*.ilk;*.tlb;*.tli;*.tlh;*.tmp;*.rsp;*.pgc;*.pgd;*.meta;$(TargetPath)"
-                       >
-                       <Tool
-                               Name="VCPreBuildEventTool"
-                       />
-                       <Tool
-                               Name="VCCustomBuildTool"
-                       />
-                       <Tool
-                               Name="VCXMLDataGeneratorTool"
-                       />
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"
-                       />
-                       <Tool
-                               Name="VCMIDLTool"
-                               TypeLibraryName=".\Debug/ntpkeygen.tlb"
-                               HeaderFileName=""
-                       />
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="0"
-                               WholeProgramOptimization="true"
-                               AdditionalIncludeDirectories=".,..\include,..\..\..\include,$(OPENSSL)\include,$(OPENSSL)\inc32,..\..\..\libopts"
-                               PreprocessorDefinitions="_DEBUG;_CONSOLE;WIN32;__STDC__;SYS_WINNT;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS"
-                               MinimalRebuild="true"
-                               ExceptionHandling="0"
-                               BasicRuntimeChecks="3"
-                               SmallerTypeCheck="true"
-                               RuntimeLibrary="1"
-                               PrecompiledHeaderFile=".\Debug/ntpkeygen.pch"
-                               AssemblerListingLocation=".\Debug/"
-                               ObjectFile=".\Debug/"
-                               ProgramDataBaseFileName="..\bin\Debug\ntp-keygen-vc90"
-                               BrowseInformation="1"
-                               WarningLevel="4"
-                               SuppressStartupBanner="true"
-                               DebugInformationFormat="3"
-                               CompileAs="1"
-                       />
-                       <Tool
-                               Name="VCManagedResourceCompilerTool"
-                       />
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               PreprocessorDefinitions="_DEBUG"
-                               Culture="1033"
-                       />
-                       <Tool
-                               Name="VCPreLinkEventTool"
-                       />
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalDependencies="ws2_32.lib $(OPENSSL)\lib\vc\libeay32MDd.lib"
-                               OutputFile="../bin/Debug/ntp-keygen.exe"
-                               Version="0x0400"
-                               LinkIncremental="1"
-                               SuppressStartupBanner="true"
-                               GenerateManifest="false"
-                               GenerateDebugInformation="true"
-                               ProgramDatabaseFile="..\bin\Debug\ntp-keygen.pdb"
-                               SubSystem="1"
-                               LinkTimeCodeGeneration="1"
-                               RandomizedBaseAddress="1"
-                               DataExecutionPrevention="0"
-                               TargetMachine="1"
-                       />
-                       <Tool
-                               Name="VCALinkTool"
-                       />
-                       <Tool
-                               Name="VCManifestTool"
-                       />
-                       <Tool
-                               Name="VCXDCMakeTool"
-                       />
-                       <Tool
-                               Name="VCBscMakeTool"
-                               SuppressStartupBanner="true"
-                               OutputFile=".\Debug/ntpkeygen.bsc"
-                       />
-                       <Tool
-                               Name="VCFxCopTool"
-                       />
-                       <Tool
-                               Name="VCAppVerifierTool"
-                       />
-                       <Tool
-                               Name="VCPostBuildEventTool"
-                       />
-               </Configuration>
-               <Configuration
-                       Name="Release|Win32"
-                       OutputDirectory=".\Release"
-                       IntermediateDirectory=".\Release"
-                       ConfigurationType="1"
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
-                       UseOfMFC="0"
-                       ATLMinimizesCRunTimeLibraryUsage="false"
-                       CharacterSet="2"
-                       DeleteExtensionsOnClean="version.c,*.obj;*.ilk;*.tlb;*.tli;*.tlh;*.tmp;*.rsp;*.pgc;*.pgd;*.meta;$(TargetPath)"
-                       >
-                       <Tool
-                               Name="VCPreBuildEventTool"
-                       />
-                       <Tool
-                               Name="VCCustomBuildTool"
-                       />
-                       <Tool
-                               Name="VCXMLDataGeneratorTool"
-                       />
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"
-                       />
-                       <Tool
-                               Name="VCMIDLTool"
-                               TypeLibraryName=".\Release/ntpkeygen.tlb"
-                               HeaderFileName=""
-                       />
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="2"
-                               InlineFunctionExpansion="1"
-                               AdditionalIncludeDirectories=".,..\include,..\..\..\include,$(OPENSSL)\include,$(OPENSSL)\inc32,..\..\..\libopts"
-                               PreprocessorDefinitions="NDEBUG;_CONSOLE;WIN32;__STDC__;SYS_WINNT;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS"
-                               StringPooling="true"
-                               RuntimeLibrary="0"
-                               EnableFunctionLevelLinking="true"
-                               PrecompiledHeaderFile=".\Release/ntpkeygen.pch"
-                               AssemblerListingLocation=".\Release/"
-                               ObjectFile=".\Release/"
-                               ProgramDataBaseFileName="..\bin\Release\ntp-keygen-vc90"
-                               WarningLevel="4"
-                               SuppressStartupBanner="true"
-                               DebugInformationFormat="3"
-                               CompileAs="1"
-                       />
-                       <Tool
-                               Name="VCManagedResourceCompilerTool"
-                       />
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               PreprocessorDefinitions="NDEBUG"
-                               Culture="1033"
-                       />
-                       <Tool
-                               Name="VCPreLinkEventTool"
-                       />
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalDependencies="ws2_32.lib $(OPENSSL)\lib\vc\libeay32MD.lib ..\libntp\Release\libntp.lib"
-                               OutputFile="../bin/Release/ntp-keygen.exe"
-                               Version="0x0400"
-                               LinkIncremental="1"
-                               SuppressStartupBanner="true"
-                               GenerateManifest="false"
-                               GenerateDebugInformation="true"
-                               ProgramDatabaseFile="..\bin\Release\ntp-keygen.pdb"
-                               SubSystem="1"
-                               LinkTimeCodeGeneration="0"
-                               RandomizedBaseAddress="1"
-                               DataExecutionPrevention="0"
-                               TargetMachine="1"
-                       />
-                       <Tool
-                               Name="VCALinkTool"
-                       />
-                       <Tool
-                               Name="VCManifestTool"
-                       />
-                       <Tool
-                               Name="VCXDCMakeTool"
-                       />
-                       <Tool
-                               Name="VCBscMakeTool"
-                               SuppressStartupBanner="true"
-                               OutputFile=".\Release/ntpkeygen.bsc"
-                       />
-                       <Tool
-                               Name="VCFxCopTool"
-                       />
-                       <Tool
-                               Name="VCAppVerifierTool"
-                       />
-                       <Tool
-                               Name="VCPostBuildEventTool"
-                       />
-               </Configuration>
-       </Configurations>
-       <References>
-       </References>
-       <Files>
-               <Filter
-                       Name="Source Files"
-                       Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-                       >
-                       <File
-                               RelativePath="..\..\..\libntp\getopt.c"
-                               >
-                               <FileConfiguration
-                                       Name="Debug|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                               <FileConfiguration
-                                       Name="Release|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                       </File>
-                       <File
-                               RelativePath="..\..\..\util\ntp-keygen-opts.c"
-                               >
-                               <FileConfiguration
-                                       Name="Debug|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                               WarningLevel="3"
-                                       />
-                               </FileConfiguration>
-                               <FileConfiguration
-                                       Name="Release|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                               WarningLevel="3"
-                                       />
-                               </FileConfiguration>
-                       </File>
-                       <File
-                               RelativePath="..\..\..\util\ntp-keygen.c"
-                               >
-                               <FileConfiguration
-                                       Name="Debug|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                               <FileConfiguration
-                                       Name="Release|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                       </File>
-                       <File
-                               RelativePath="..\..\..\libntp\ntp_random.c"
-                               >
-                               <FileConfiguration
-                                       Name="Debug|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                               <FileConfiguration
-                                       Name="Release|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                       </File>
-                       <File
-                               RelativePath="..\libntp\randfile.c"
-                               >
-                               <FileConfiguration
-                                       Name="Debug|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                               <FileConfiguration
-                                       Name="Release|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                       </File>
-                       <File
-                               RelativePath="..\libntp\util_clockstuff.c"
-                               >
-                               <FileConfiguration
-                                       Name="Debug|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                               <FileConfiguration
-                                       Name="Release|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                       </File>
-                       <File
-                               RelativePath="version.c"
-                               >
-                               <FileConfiguration
-                                       Name="Debug|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                               <FileConfiguration
-                                       Name="Release|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Header Files"
-                       Filter="h;hpp;hxx;hm;inl"
-                       >
-                       <File
-                               RelativePath="..\include\config.h"
-                               >
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Resource Files"
-                       Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
-                       >
-               </Filter>
-               <File
-                       RelativePath="..\..\..\configure"
-                       >
-                       <FileConfiguration
-                               Name="Debug|Win32"
-                               >
-                               <Tool
-                                       Name="VCCustomBuildTool"
-                                       CommandLine="echo Using NT Shell Script to generate version.c&#x0D;&#x0A;..\scripts\mkver.bat -P ntpkeygen&#x0D;&#x0A;"
-                                       Outputs="$(ProjectDir)version.c"
-                               />
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Release|Win32"
-                               >
-                               <Tool
-                                       Name="VCCustomBuildTool"
-                                       CommandLine="echo Using NT Shell Script to generate version.c&#x0D;&#x0A;..\scripts\mkver.bat -P ntpkeygen&#x0D;&#x0A;"
-                                       Outputs="$(ProjectDir)version.c"
-                               />
-                       </FileConfiguration>
-               </File>
-       </Files>
-       <Globals>
-       </Globals>
-</VisualStudioProject>
index 74a40ce1fe42398671538cbc79040b3e7b72464d..d7fc5370001c82e3462845ce048cbbb5e6b52191 100644 (file)
@@ -1,43 +1,10 @@
 /* Windows NT Clock Routines
- *
- *
- * Revision History:
- * $Log$
- * Revision 1.9  2000/11/19 09:02:12  dietrich
- * From: Ron Thornton [rthornto@pictel.com]
- * Sent: Thu 11/16/00 8:51 AM
- * On Windows 2000 it requires a privilege on the current process token
- * that is disabled by default on Windows 2000.
- *
- * I set the token by adding the following code at the beginning of the
- * init_winnt_time() function in nt_clockstuff.c.
- *
- * Revision 1.8  2000/11/19 08:03:20  dietrich
- * From: "Colin Dancer" <colin.dancer@pyrochrome.net>
- * To: <bugs@ntp.org>
- * Sent: 10 November 2000 12:59
- * Subject: NT bug in NTP 4.0.99j
- *
- * I've found a bug in (and produced a fix for) the NT clock interpolation
- * code in NTP 4.0.99j.
- *
- * The symptoms of the problem are that gettimeofday() function on NT
- * can be wrong by hundreds of seconds if, while a gettimeofday() call
- * is being processed, an APC completes after the query of the performance
- * counter but before the lock is grabbed.  The most obvious fix is to move
- * the lock to include the querying of the performance counter, but this
- * could affect the predictability of the timestamp so I have instead
- * tweaked the code to detect and sidestep the duff calculation.
- *
- * I've also found that on a loaded system the execution of the APC can be
- * delayed, leading to errors of upto 10ms.  There is no easy fix to this,
- * but I do have code for an alternative interpolation scheme which avoids
- * the problem on single processor systems. I'm currently integrating this
- * along with code for deciding which algorithm to use based on whether
- * the system is SP or MP.
  *
  * Created by Sven Dietrich  sven@inter-yacht.com
  *
+ * New interpolation scheme by Dave Hart <davehart@davehart.com> February 2009
+ * overcomes 500us-1ms inherent jitter with the older scheme, first identified
+ * by Peter Rosin (nee Ekberg) <peda@lysator.liu.se> in 2003 [Bug 216].
  */
 
 
 #include "config.h"
 #endif
 
+#include <sys/resource.h>      /* our private version */
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400      /* VS 2005 */
+#include <intrin.h>                            /* for __rdtsc() */
+#endif
+
+#ifdef HAVE_PPSAPI
+#include <timepps.h>
+#endif
+
 #include "ntp_stdlib.h"
+#include "ntp_unixtime.h"
+#include "ntp_timer.h"
 #include "clockstuff.h"
 #include "ntservice.h"
-#include "ntp_timer.h"
 #include "ntpd.h"
 
+extern double sys_residual;    /* residual from previous adjustment */
+
 /*
  * Include code to possibly modify the MM timer while the service is active. 
  */
 
-  /*
-   * Whether or not MM timer modifications takes place is still controlled 
-   * by the variable below which is initialized by a default value but 
-   * might be changed depending on a command line switch.
-   */
-  int modify_mm_timer = MM_TIMER_LORES;
-
-  #define MM_TIMER_INTV   1  /* the interval we'd want to set the MM timer to [ms] */
+/*
+ * Whether or not MM timer modifications takes place is still controlled 
+ * by the variable below which is initialized by a default value but 
+ * might be changed depending on a command line switch.
+ */
+static int modify_mm_timer = MM_TIMER_LORES;
 
-  static UINT wTimerRes;
-  static TIMECAPS tc;
+#define MM_TIMER_INTV   1  /* the interval we'd want to set the MM timer to [ms] */
 
+static UINT wTimerRes;
 
-extern double sys_residual;    /* residual from previous adjustment */
-
-char szMsgPath[255];
 BOOL init_randfile();
 
 static long last_Adj = 0;
@@ -79,47 +54,256 @@ static long last_Adj = 0;
 #define LS_CORR_INTV   ( (LONGLONG) HECTONANOSECONDS * LS_CORR_INTV_SECS )  
 #define LS_CORR_LIMIT  ( (LONGLONG) HECTONANOSECONDS / 2 )  // half a second
 
-typedef union
-{
+typedef union ft_ull {
        FILETIME ft;
        ULONGLONG ull;
+       LONGLONG ll;
+       LARGE_INTEGER li;
 } FT_ULL;
 
+/* leap second stuff */
 static FT_ULL ls_ft;
 static DWORD ls_time_adjustment;
-static LARGE_INTEGER ls_ref_perf_cnt;
+static ULONGLONG ls_ref_perf_cnt;
 static LONGLONG ls_elapsed;
 
+static BOOL winnt_time_initialized = FALSE;
+static BOOL winnt_use_interpolation = FALSE;
+static ULONGLONG last_interp_time;
+static unsigned clock_thread_id;
+
+
+void WINAPI GetInterpTimeAsFileTime(LPFILETIME pft);
 static void StartClockThread(void);
-static void StopClockThread(void);
-void lock_thread_to_processor(HANDLE);
+static void tune_ctr_freq(LONGLONG, LONGLONG);
+void StopClockThread(void);
+void atexit_revert_mm_timer(void);
+void time_stepped(void);
 
+static HANDLE clock_thread = NULL;
+static HANDLE TimerThreadExitRequest = NULL;
 
-static CRITICAL_SECTION TimerCritialSection; /* lock for LastTimerCount & LastTimerTime */
+/*
+ * interp_time estimates time in 100ns units
+ * based on a performance counter value given.
+ * The 2nd parameter indicates if this is
+ * part of a current time-of-day calculation.
+ */
+ULONGLONG interp_time(ULONGLONG, BOOL);
 
-static ULONGLONG RollOverCount = 0;
-static ULONGLONG LastTimerCount = 0;
-static ULONGLONG LastTimerTime = 0;
+/*
+ * add_counter_time_pair is called by the
+ * high priority clock thread with a new
+ * sample.
+ */
+void add_counter_time_pair(ULONGLONG, LONGLONG);
 
-static HANDLE ClockThreadHandle = NULL;
-static HANDLE TimerThreadExitRequest = NULL;
+/*
+ * globals used by the above two functions to 
+ * implement the counter/time history
+ */
+#define BASELINES_TOT  256
+#define BASELINES_USED 64
+
+static volatile int    newest_baseline = 0;
+static volatile int    newest_baseline_gen = 0;
+static ULONGLONG       baseline_counts[BASELINES_TOT] = {0};
+static LONGLONG                baseline_times[BASELINES_TOT] = {0};
 
-static DWORD every = 0;
-static DWORD initial_units_per_tick = 0;
-static DWORD lastLowTimer = 0;
+static int             clock_backward_count;
+static ULONGLONG       clock_backward_max;
 
-ULONGLONG PerfFrequency = 0;
-static DWORD units_per_tick = 0;
+
+/*
+ * clockperiod is the period used for SetSystemTimeAdjustment 
+ * slewing calculations but does not necessarily correspond
+ * to the precision of the OS clock.  Prior to Windows Vista
+ * (6.0) the two were identical.  In 100ns units.
+ */
+static DWORD clockperiod;
+
+/*
+ * os_clock_precision is the observed precision of the OS
+ * clock, meaning the increment between discrete values. This
+ * is currently calculated once at startup.  100ns units.
+ */
+static ULONGLONG os_clock_precision;
+
+/*
+ * NomPerfCtrFreq is from QueryPerformanceFrequency and is the 
+ * number of performance counter beats per second.  PerfCtrFreq
+ * starts from NomPerfCtrFreq but is maintained using a sliding
+ * window average based on actual performance counter behavior,
+ * to allow us to better tolerate powersaving measures that
+ * alter the effective frequency of the processor cycle counter
+ * (TSC) which sometimes underlies QueryPerformanceCounter.
+ *
+ * Note that the OS is unlikely to be so subtle in its internal
+ * scheduling of waitable timers, presumably done using the
+ * performance counter.  Therefore our calculations for
+ * interpolated time should be based on PerfCtrFreq but our
+ * calculations for SetWaitableTimer should assume the OS will
+ * convert from FILETIME 100ns units to performance counter
+ * beats using the nominal frequency.
+ */
+
+volatile ULONGLONG PerfCtrFreq = 0;
+        ULONGLONG NomPerfCtrFreq = 0;
+
+/* 
+ * If we're using RDTSC beating at the same rate as
+ * QueryPerformanceCounter, there is a systemic
+ * offset we need to account for when using
+ * counterstamps from serialpps.sys, which are
+ * always from QPC (actually KeQueryPerformanceCounter).
+ */
+static LONGLONG QPC_offset = 0;
+
+/*
+ * use_pcc could be a local static in perf_ctr but
+ * lock_thread_to_processor cares about it.
+ */
+static int use_pcc = -1;
+
+/*
+ * ppm_per_adjust_unit is parts per million effect on the OS
+ * clock per slewing adjustment unit per second.  Per haps.
+ */
 static DOUBLE ppm_per_adjust_unit = 0.0;
 
+/*
+ * performance counter frequency observations
+ */
+#define TUNE_CTR_DEPTH         3       /* running avg depth */
+
+static HANDLE          ctr_freq_timer = INVALID_HANDLE_VALUE;
+static ULONGLONG       tune_ctr_freq_max_interval;
+static unsigned                tune_ctr_period;
+void start_ctr_freq_timer(ULONGLONG now_time);
+void reset_ctr_freq_timer(ULONGLONG when, ULONGLONG now);
+void reset_ctr_freq_timer_abs(ULONGLONG when);
+
+/* round a Windows time to the next bottom of the second */
+
+#define ROUND_TO_NEXT_SEC_BOTTOM(t)    \
+do {   \
+       (t) += 3 * HECTONANOSECONDS / 2 - 1;    \
+       (t) /= HECTONANOSECONDS;        \
+       (t) *= HECTONANOSECONDS;        \
+       (t) -= HECTONANOSECONDS / 2;    \
+} while (0)
+
+/* there must be a better place for this */
+#define COUNTOF(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+/*
+ * NT native time format is 100's of nanoseconds since 1601-01-01.
+ * Helpers for converting between "hectonanoseconds" and the 
+ * performance counter scale from which interpolated time is
+ * derived.
+ */
+#define HNS2PERF(hns)  ((hns) * PerfCtrFreq / HECTONANOSECONDS)
+#define PERF2HNS(ctr)  ((ctr) * HECTONANOSECONDS / PerfCtrFreq)
+
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400      /* VS 2005 */
+#define        get_pcc()       __rdtsc()
+#else
+/*
+ * something like this can be used for a compiler without __rdtsc()
+ */
+ULONGLONG __forceinline 
+get_pcc(void)
+{
+       /* RDTSC returns in EDX:EAX, same as C compiler */
+       __asm {
+               RDTSC
+       }
+}
+#endif
+
+/*
+ * perf_ctr() returns the current performance counter value, 
+ * from QueryPerformanceCounter or RDTSC.
+ */
+
+ULONGLONG WINAPI 
+perf_ctr(void)
+{
+       FT_ULL ft1;
+
+       if (1 == use_pcc) {
+               return get_pcc();
+       } else if (0 == use_pcc) {
+               QueryPerformanceCounter(&ft1.li);
+               return ft1.ull;
+       } else {
+               FT_ULL ft2;
+               FT_ULL ft3;
+               FT_ULL ft4;
+               FT_ULL ft5;
+               LONGLONG offset;
+               char *ntpd_pcc_freq_text = getenv("NTPD_PCC_FREQ");
+
+               /* one-time initialization */
+#ifdef DEBUG
+               if (!NomPerfCtrFreq) {
+                       msyslog(LOG_ERR, "NomPerfCtrFreq not initialized before first perf_ctr() call");
+                       exit(-1);
+               }
+#endif
+
+               QueryPerformanceCounter(&ft1.li);
+               ft2.ull = get_pcc();
+               Sleep(1);
+               QueryPerformanceCounter(&ft3.li);
+               Sleep(1);
+               ft4.ull = get_pcc();
+               Sleep(1);
+               QueryPerformanceCounter(&ft5.li);
+
+               offset = ft2.ull - ft1.ull;
+               ft3.ull += offset;
+               ft5.ull += offset;
+
+               if (ntpd_pcc_freq_text  ||
+                       (ft2.ull <= ft3.ull &&
+                        ft3.ull <= ft4.ull &&
+                        ft4.ull <= ft5.ull)) {
+
+                       use_pcc = 1;
+                       ft1.ull = ft2.ull;
+                       QPC_offset = offset;
+
+                       if (ntpd_pcc_freq_text)
+                               sscanf(ntpd_pcc_freq_text, 
+                                      "%I64u", 
+                                      &NomPerfCtrFreq);
+
+                       NLOG(NLOG_CLOCKINFO)
+                               msyslog(LOG_INFO, 
+                                       "using processor cycle counter "
+                                       "%.3f MHz", 
+                                       NomPerfCtrFreq / 1e6);
+               } else {
+                       use_pcc = 0;
+               }
+
+               return ft1.ull;
+       }
+}
+
 /*
  * Request Multimedia Timer
  */
 void
-set_mm_timer(int timerres)
+set_mm_timer(
+       int timerres
+       )
 {
        modify_mm_timer = timerres;
 }
+
 /*
  * adj_systime - called once every second to make system time adjustments.
  * Returns 1 if okay, 0 if trouble.
@@ -132,7 +316,7 @@ adj_systime(
        double dtemp;
        u_char isneg = 0;
        int rc;
-       long dwTimeAdjustment;
+       long TimeAdjustment;
 
        /*
         * Add the residual from the previous adjustment to the new
@@ -154,36 +338,40 @@ adj_systime(
        if (isneg)
                dtemp = -dtemp;
 
-       /* dtemp is in micro seconds. NT uses 100 ns units,
-        * so a unit change in dwTimeAdjustment corresponds
-        * to slewing 10 ppm on a 100 Hz system.
-        * Calculate the number of 100ns units to add,
-        * using OS tick frequency as per suggestion from Harry Pyle,
-        * and leave the remainder in dtemp */
-       dwTimeAdjustment = (DWORD)( dtemp / ppm_per_adjust_unit + (isneg ? -0.5 : 0.5)) ;
-       dtemp += (double) -dwTimeAdjustment * ppm_per_adjust_unit;      
+       /* 
+        * dtemp is in micro seconds. NT uses 100 ns units,
+        * so a unit change in TimeAdjustment corresponds
+        * to slewing 10 ppm on a 100 Hz system. Calculate
+        * the number of 100ns units to add, using OS tick
+        * frequency as per suggestion from Harry Pyle,
+        * and leave the remainder in dtemp
+        */
+       TimeAdjustment = (long) (dtemp / ppm_per_adjust_unit + (isneg ? -0.5 : 0.5));
+       dtemp -= (double) TimeAdjustment * ppm_per_adjust_unit; 
 
 
-  /* If a leap second is pending then determine the UTC time stamp 
-        * of when the insertion must take place */
-       if (leap_sec > 0)  
+       /*
+        * If a leap second is pending then determine the UTC time stamp 
+        * of when the insertion must take place 
+        */
+       if (leap_sec > 0)
        {
                if ( ls_ft.ull == 0 )  /* time stamp has not yet been computed */
                {
-                       FT_ULL ft;
                        SYSTEMTIME st;
-                       int itmp;
 
-                       GetSystemTimeAsFileTime(&ft.ft);   
-                       FileTimeToSystemTime(&ft.ft, &st);
+                       GetSystemTime(&st);
 
-                       /* Accept leap announcement only 1 month in advance,
+                       /*
+                        * Accept leap announcement only 1 month in advance,
                         * for end of March, June, September, or December.
                         */
                        if ( ( st.wMonth % 3 ) == 0 )
                        {
-                               /* The comarison time stamp is computed according 
-                                * to 0:00h UTC of the following day */   
+                               /*
+                                * The comparison time stamp is computed according 
+                                * to 0:00h UTC of the following day 
+                                */
                                if ( ++st.wMonth > 12 )
                                {
                                        st.wMonth -= 12;
@@ -197,22 +385,25 @@ adj_systime(
                                st.wMilliseconds = 0;
 
                                SystemTimeToFileTime(&st, &ls_ft.ft);
-                               msyslog(LOG_INFO, "Detected positive leap second announcement "
-                                                 "for %04d-%02d-%02d %02d:%02d:%02d UTC",
-                                                                                                       st.wYear, st.wMonth, st.wDay,
-                                                 st.wHour, st.wMinute, st.wSecond);
+                               msyslog(LOG_NOTICE,
+                                       "Detected positive leap second announcement "
+                                       "for %04d-%02d-%02d %02d:%02d:%02d UTC",
+                                       st.wYear, st.wMonth, st.wDay,
+                                       st.wHour, st.wMinute, st.wSecond);
                        }
                }
-  }
+       }
 
  
-  /* If the time stamp for the next leap second has been set
-        * then check if the leap second must be handled */
+       /*
+        * If the time stamp for the next leap second has been set
+        * then check if the leap second must be handled
+        */
        if ( ls_ft.ull )
        {
-               LARGE_INTEGER this_perf_count;
+               ULONGLONG this_perf_count;
 
-               QueryPerformanceCounter( &this_perf_count );
+               this_perf_count = perf_ctr();
 
                if ( ls_time_adjustment == 0 ) /* has not yet been scheduled */
                {
@@ -221,16 +412,16 @@ adj_systime(
                        GetSystemTimeAsFileTime(&curr_ft.ft);   
                        if ( curr_ft.ull >= ls_ft.ull )
                        {
-                               ls_time_adjustment = every / LS_CORR_INTV_SECS;
+                               ls_time_adjustment = clockperiod / LS_CORR_INTV_SECS;
                                ls_ref_perf_cnt = this_perf_count;
                                ls_elapsed = 0;
-                               msyslog(LOG_INFO, "Inserting positive leap second.");
+                               msyslog(LOG_NOTICE, "Inserting positive leap second.");
                        }
                }
                else  /* leap sec adjustment has been scheduled previously */
                {
-                       ls_elapsed = ( this_perf_count.QuadPart - ls_ref_perf_cnt.QuadPart ) 
-                                      * HECTONANOSECONDS / PerfFrequency;
+                       ls_elapsed = ( this_perf_count - ls_ref_perf_cnt ) 
+                                      * HECTONANOSECONDS / PerfCtrFreq;
                }
 
                if ( ls_time_adjustment )  /* leap second adjustment is currently active */
@@ -241,24 +432,21 @@ adj_systime(
                                ls_ft.ull = 0;
                        }
 
-               /* NOTE: While the system time is slewed during the leap second 
-                * the interpolation function which is based on the performance 
-                * counter does not account for the slew.
-                */
-               dwTimeAdjustment -= ls_time_adjustment;
+                       /* 
+                        * NOTE: While the system time is slewed during the leap second 
+                        * the interpolation function which is based on the performance 
+                        * counter does not account for the slew.
+                       */
+                       TimeAdjustment -= ls_time_adjustment;
                }
        }
 
 
        /* only adjust the clock if adjustment changes */
-       if (last_Adj != dwTimeAdjustment) {     
-                       last_Adj = dwTimeAdjustment;
-# ifdef DEBUG
-               if (debug > 1)
-                       printf("SetSystemTimeAdjustment( %ld) + (%ld)\n", dwTimeAdjustment, units_per_tick);                    
-# endif
-                       dwTimeAdjustment += units_per_tick;
-                       rc = !SetSystemTimeAdjustment(dwTimeAdjustment, FALSE);
+       if (last_Adj != TimeAdjustment) {
+               last_Adj = TimeAdjustment;
+               DPRINTF(1, ("SetSystemTimeAdjustment(%+ld)\n", TimeAdjustment));
+               rc = !SetSystemTimeAdjustment(clockperiod + TimeAdjustment, FALSE);
        }
        else rc = 0;
        if (rc)
@@ -267,22 +455,31 @@ adj_systime(
                return 0;
        }
        else {
-               sys_residual = dtemp / 1000000.0;
+               sys_residual = dtemp / 1e6;
        }
 
-#ifdef DEBUG
-       if (debug > 6)
-               printf("adj_systime: adj %.9f -> remaining residual %.9f\n", now, sys_residual);
-#endif
+       DPRINTF(6, ("adj_systime: adj %.9f -> remaining residual %.9f\n", 
+                   now, sys_residual));
+
        return 1;
 }
 
 
-void init_winnt_time(void)
+void 
+init_winnt_time(void)
 {
-       BOOL noslew;
+       char szMsgPath[MAX_PATH+1];
        HANDLE hToken = INVALID_HANDLE_VALUE;
        TOKEN_PRIVILEGES tkp;
+       TIMECAPS tc;
+       BOOL noslew;
+       DWORD adjclockperiod;
+       LARGE_INTEGER Freq;
+       FT_ULL initial_hectonanosecs;
+       FT_ULL next_hectonanosecs;
+
+       if (winnt_time_initialized)
+               return;
 
        /*
         * Make sure the service is initialized
@@ -290,6 +487,12 @@ void init_winnt_time(void)
         */
        ntservice_init();
 
+       /* Set up the Console Handler */
+       if (!SetConsoleCtrlHandler(OnConsoleEvent, TRUE))
+       {
+               msyslog(LOG_ERR, "Can't set console control handler: %m");
+       }
+
        /* Set the Event-ID message-file name. */
        if (!GetModuleFileName(NULL, szMsgPath, sizeof(szMsgPath))) 
        {
@@ -305,14 +508,14 @@ void init_winnt_time(void)
         * Get privileges needed for fiddling with the clock
         */
 
-         /* get the current process token handle */
+       /* get the current process token handle */
        if (!OpenProcessToken(GetCurrentProcess(),
             TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) 
        {
                msyslog(LOG_ERR, "OpenProcessToken failed: %m");
                exit(-1);
        }
-         /* get the LUID for system-time privilege. */
+       /* get the LUID for system-time privilege. */
        LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
        tkp.PrivilegeCount = 1;  /* one privilege to set */
        tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
@@ -329,130 +532,202 @@ void init_winnt_time(void)
                /* later set time call will probably fail */
        }
 
-       /* Reset the Clock to a reasonable increment */
-       if (!GetSystemTimeAdjustment(&initial_units_per_tick, &every,&noslew))
+       CloseHandle(hToken);
+       hToken = INVALID_HANDLE_VALUE;
+
+       /*
+        * ntpd on Windows has always raised its priority, without
+        * requiring -N as on Unix.  Since Windows ntpd doesn't share
+        * the history of unix ntpd of once having no -N and therefore
+        * needing to be invoked under nice, there is no reason to
+        * bring it in line with the Unix version in this regard.
+        * Instsrv assumes ntpd is invoked with no arguments, and
+        * upgrading users would be negatively surprised by the 
+        * poor timekeeping if they failed to add -N as part of 
+        * upgrading were we to correct this platform difference.
+        */
+       if (-1 == setpriority(PRIO_PROCESS, 0, NTP_PRIO))
+               exit(-1);
+
+       /*
+        * register with libntp ntp_set_tod() to call us back
+        * when time is stepped.
+        */
+       step_callback = time_stepped;
+
+       /* 
+        * before we start looking at clock period, do any multimedia
+        * timer manipulation requested via -M option.
+        */
+       if (modify_mm_timer) {
+
+               if (timeGetDevCaps(&tc, sizeof(tc)) == TIMERR_NOERROR) {
+
+                       wTimerRes = min(max(tc.wPeriodMin, MM_TIMER_INTV), tc.wPeriodMax);
+                       timeBeginPeriod(wTimerRes);
+                       atexit(atexit_revert_mm_timer);
+                       
+                       msyslog(LOG_INFO, "MM timer resolution: %u..%u msec, set to %u msec",
+                               tc.wPeriodMin, tc.wPeriodMax, wTimerRes );
+               } else
+                       msyslog(LOG_ERR, "Multimedia timer unavailable");
+       }
+       
+       /* get the performance counter ticks per second */
+       if (!QueryPerformanceFrequency(&Freq) || !Freq.QuadPart)
        {
-               msyslog(LOG_ERR, "GetSystemTimeAdjustment failed: %m\n");
+               msyslog(LOG_ERR, "QueryPerformanceFrequency failed: %m\n");
                exit(-1);
        }
 
-       units_per_tick = initial_units_per_tick;
+       NomPerfCtrFreq = PerfCtrFreq = Freq.QuadPart;
+       msyslog(LOG_INFO, 
+               "Performance counter frequency %.3f MHz", 
+               PerfCtrFreq / 1e6);
 
-       /* Calculate the time adjustment resulting from incrementing
-        * units per tick by 1 unit for 1 second */
-       ppm_per_adjust_unit = 1000000.0 / (double) every;
+       /* Determine the existing system time slewing */
+       if (!GetSystemTimeAdjustment(&adjclockperiod, &clockperiod, &noslew))
+       {
+               msyslog(LOG_ERR, "GetSystemTimeAdjustment failed: %m\n");
+               exit(-1);
+       }
 
-#ifdef DEBUG
-       msyslog(LOG_INFO, "Initial Clock increment %7.1f us",
-                       (float) (units_per_tick / 10));
-       msyslog(LOG_INFO, "Adjustment rate %5.3f ppm/s", ppm_per_adjust_unit);
-#endif
+       /*
+        * If there is no slewing before ntpd, adjclockperiod and clockperiod
+        * will be equal.  Any difference is carried into adj_systime's first
+        * pass as the previous adjustment.
+        */
+       last_Adj = adjclockperiod - clockperiod;
+       
+       if (last_Adj)
+               msyslog(LOG_INFO, 
+                       "Clock interrupt period %.3f msec "
+                       "(startup slew %.1f usec/period)",
+                       clockperiod / 1e4,
+                       last_Adj / 10.);
+       else
+               msyslog(LOG_INFO, 
+                       "Clock interrupt period %.3f msec", 
+                       clockperiod / 1e4);
 
-       StartClockThread();
+       /*
+        * Calculate the time adjustment resulting from incrementing
+        * units per tick by 1 unit for 1 second 
+        */
+       ppm_per_adjust_unit = 1e6 / clockperiod;
 
-       /* Set up the Console Handler */
-       if (!SetConsoleCtrlHandler(OnConsoleEvent, TRUE))
-       {
-               msyslog(LOG_ERR, "Can't set console control handler: %m");
+       /*
+        * Spin on GetSystemTimeAsFileTime to determine its
+        * granularity.  Prior to Windows Vista this is 
+        * typically the same as the clock period.
+        */
+       GetSystemTimeAsFileTime(&initial_hectonanosecs.ft);
+       do {
+               GetSystemTimeAsFileTime(&next_hectonanosecs.ft);
+       } while (initial_hectonanosecs.ull == next_hectonanosecs.ull);
+
+       os_clock_precision = next_hectonanosecs.ull -
+               initial_hectonanosecs.ull;
+
+       msyslog(LOG_INFO,
+               "Windows clock precision %.3f msec, min. slew %.3f ppm/s",
+               os_clock_precision / 1e4, 
+               ppm_per_adjust_unit);
+
+       winnt_time_initialized = TRUE;
+
+       if (os_clock_precision < 4 * 10000 && !getenv("NTPD_USE_INTERP_DANGEROUS")) {
+               msyslog(LOG_INFO, "using Windows clock directly");
+       } else {
+               winnt_use_interpolation = TRUE;
+               get_sys_time_as_filetime = GetInterpTimeAsFileTime;
+               StartClockThread();
        }
 }
 
 
-void reset_winnt_time(void)
+void
+atexit_revert_mm_timer(void)
 {
-       /* restore the clock frequency back to its original value */
-       if (!SetSystemTimeAdjustment(0, TRUE)) 
-       {
-               msyslog(LOG_ERR, "Failed to reset clock state, SetSystemTimeAdjustment(): %m");
-       }
-       /* read the current system time, and write it back to
-           force CMOS update: */
-      /************ Added back in 2003-01-26 *****************/
-       {
-               SYSTEMTIME st;
+       timeEndPeriod(wTimerRes); 
+       DPRINTF(1, ("MM timer resolution reset\n"));
+}
+
+
+void 
+reset_winnt_time(void)
+{
+       SYSTEMTIME st;
+
+       /*
+        * If we're in the 2-second slew right after a leap second, 
+        * we don't want to continue that extreme slew, in that case
+        * disable our slewing and return clock discipline to the 
+        * kernel.  Similarly if we are not yet synchronized, 
+        * our current slew may not be a good ongoing trim.
+        * Otherwise, our leave in place the last SetSystemTimeAdjustment
+        * as an ongoing frequency correction, better than nothing.
+        * TODO:
+        * Verify this will not call SetSystemTimeAdjustment if
+        * ntpd is running in ntpdate mode.
+        */
+       if (sys_leap == LEAP_NOTINSYNC || ls_time_adjustment)
+               SetSystemTimeAdjustment(0, TRUE);        
+
+       /*
+        * Read the current system time, and write it back to
+        * force CMOS update, only if we are exiting because
+        * the computer is shutting down and we are already
+        * synchronized.
+        */
+        if (ntservice_systemisshuttingdown() && sys_leap != LEAP_NOTINSYNC) {
                GetSystemTime(&st);
                SetSystemTime(&st);
+               NLOG(NLOG_SYSEVENT | NLOG_CLOCKINFO)
+                       msyslog(LOG_NOTICE, "system is shutting down, CMOS time reset.");
        }
 }
 
 
+/*
+ * GetSystemTimeAsFileTime() interface clone is used by getclock() in ntpd.
+ */
 
-int
-gettimeofday(
-       struct timeval *tv
+void WINAPI 
+GetInterpTimeAsFileTime(
+       LPFILETIME pft
        )
 {
-       /*  Use the system time (roughly synchronised to the tick, and
-        *  extrapolated using the system performance counter.
-        */
-
-       ULONGLONG Count;
-       LARGE_INTEGER LargeIntNowCount;
-       ULONGLONG Time;
-       ULONGLONG NowCount;
-       ULONGLONG PreCount;                                                  /*FIX*/
-       LONGLONG TicksElapsed;
-       LONG time_adjustment;
+       FT_ULL now_time;
+       FT_ULL now_count;
 
        /*  Mark a mark ASAP. The latency to here should
         *  be reasonably deterministic
-        */
+       */
 
-       PreCount = LastTimerCount;                                           /*FIX*/
-
-       if (!QueryPerformanceCounter(&LargeIntNowCount)) {
-               msyslog(LOG_ERR, "QueryPeformanceCounter failed: %m");
-               exit(1);
-       }
+       now_count.ull = perf_ctr();
+       now_time.ull = interp_time(now_count.ull, TRUE);
 
-       NowCount = LargeIntNowCount.QuadPart;
-
-       /*  Get base time we are going to extrapolate from
-        */     
-       EnterCriticalSection(&TimerCritialSection);
-       Count = LastTimerCount;
-       Time = LastTimerTime;
-       LeaveCriticalSection(&TimerCritialSection);
-
-       /*  Calculate when now is.
-        *
-        *  Result = LastTimerTime +  (NowCount - LastTimerCount) / PerfFrequency
-        */
-
-       if (NowCount >= Count)
-       {
-               TicksElapsed = NowCount - Count; /* linear progression of ticks */
-       }
-       else
-       {
-       /************************************************************************/
-       /* Differentiate between real rollover and the case of taking a         */
-       /* perfcount then the APC coming in.                                    */
-       /************************************************************************/
-               if (Count > PreCount)                                           /*FIX*/
-               {                                                               /*FIX*/
-                       TicksElapsed = 0;                                       /*FIX*/
-               }                                                               /*FIX*/
-               else                                                            /*FIX*/
-               {                                                               /*FIX*/
-                       TicksElapsed = NowCount + (RollOverCount - Count);      /*FIX*/
-               }                                                               /*FIX*/
-       }
-
-       /*  Calculate the new time (in 100's of nano-seconds)
-        */
-       time_adjustment = (long) ((TicksElapsed * HECTONANOSECONDS) / PerfFrequency);
-       Time += time_adjustment;
+       if (last_interp_time > now_time.ull) {
 
-       /* Convert the hecto-nano second time to tv format
-        */
-       Time -= FILETIME_1970;
-       tv->tv_sec = (LONG) ( Time / 10000000ui64);
-       tv->tv_usec = (LONG) (( Time % 10000000ui64) / 10);
+               clock_backward_count++;
+               if (last_interp_time - now_time.ull > clock_backward_max)
+                       clock_backward_max = last_interp_time - now_time.ull;
+               now_time.ull = last_interp_time;
+       } else
+               last_interp_time = now_time.ull;
 
-       return 0;
+       *pft = now_time.ft;
+       return;
 }
 
+
+/*
+ * TimerApcFunction is invoked on the high-priority clock
+ * thread to capture a new  baseline system time and
+ * performance counter correlation every 43 msec (64Hz 
+ * OS clock precision).
+ */
 static void CALLBACK
 TimerApcFunction(
        LPVOID lpArgToCompletionRoutine,
@@ -460,128 +735,195 @@ TimerApcFunction(
        DWORD dwTimerHighValue
        )
 {
-       LARGE_INTEGER LargeIntNowCount;
-       (void) lpArgToCompletionRoutine; /* not used */
+       static BOOL             ctr_freq_timer_started = FALSE;
+       static ULONGLONG        prev_count;
+       ULONGLONG               now_time;
+       FT_ULL                  now_count;
 
-       if (dwTimerLowValue == lastLowTimer) return;
-       
        /* Grab the counter first of all */
-       QueryPerformanceCounter(&LargeIntNowCount);
+       now_count.ull = perf_ctr();
 
-       /* Save this for next time */
-       lastLowTimer = dwTimerLowValue;
+       now_time = (((ULONGLONG)dwTimerHighValue << 32) |
+                               dwTimerLowValue);
 
-       /* Check to see if the counter has rolled. This happens
-          more often on Multi-CPU systems */
+       /*
+        * Save this correlation in the history.
+        */
+       add_counter_time_pair(now_count.ull, now_time);
 
-       if ((ULONGLONG) LargeIntNowCount.QuadPart < LastTimerCount) {
-               /* Counter Rolled - try and estimate the rollover point using
-                 the nominal counter frequency divided by an estimate of the
-                 OS frequency */
-               RollOverCount = LastTimerCount + PerfFrequency * every /  HECTONANOSECONDS -
-                       (ULONGLONG) LargeIntNowCount.QuadPart;
-#ifdef DEBUG
-               msyslog(LOG_INFO,
-                       "Performance Counter Rollover %I64u:\rLast Timer Count %I64u\rCurrent Count %I64u",
-                               RollOverCount, LastTimerCount, LargeIntNowCount.QuadPart);
-#endif
-       }
+       /*
+        * Once we're synchronized start the counter frequency
+        * tuning timer.
+        */
+       if (INVALID_HANDLE_VALUE == ctr_freq_timer &&
+           LEAP_NOTINSYNC != sys_leap)
 
-       /* Now we can hang out and wait for the critical section to free up;
-          we will get the CPU this timeslice. Meanwhile other tasks can use
-          the last value of LastTimerCount */
-               
-       EnterCriticalSection(&TimerCritialSection);
-       LastTimerCount = (ULONGLONG) LargeIntNowCount.QuadPart;
-       LastTimerTime = ((ULONGLONG) dwTimerHighValue << 32) +
-                        (ULONGLONG) dwTimerLowValue;
-       LeaveCriticalSection(&TimerCritialSection);
+               start_ctr_freq_timer(now_time);
 }
 
 
-
-DWORD WINAPI ClockThread(void *arg)
+unsigned WINAPI 
+ClockThread(
+       void *arg
+       )
 {
+       LARGE_INTEGER   DueTime;
+       HANDLE          timer;
+       double          HZ;
+       double          TimerHz;
+       DWORD           timer_period_msec;
+       DWORD           res;
+       char            *ntpd_int_int_text;
+
+       UNUSED_ARG(arg);
+
+       timer = CreateWaitableTimer(NULL, FALSE, NULL);
+
+       ntpd_int_int_text = getenv("NTPD_INT_INT");
+
+       HZ = (double)HECTONANOSECONDS / clockperiod;
+
+       if (HZ > 63 && HZ < 65) {
+               timer_period_msec = 43;
+       } else if (HZ > 98 && HZ < 102) {
+               timer_period_msec = 27;
+               if (!ntpd_int_int_text)
+                       msyslog(LOG_WARNING, 
+                               "%.3f Hz system clock may benefit from "
+                               "custom NTPD_INT_INT env var timer interval "
+                               "override between approx. 20 and 50 msecs.",
+                               HZ);
+       } else {
+               timer_period_msec = (DWORD)(0.5 + (2.752 * clockperiod / 10000));
+               if (!ntpd_int_int_text)
+                       msyslog(LOG_WARNING, 
+                               "unfamiliar %.3f Hz system clock may benefit "
+                               "from custom NTPD_INT_INT env var timer "
+                               "interval override between approx. 20 and 50 "
+                               "msecs.",
+                               HZ);
+       }
 
-       LARGE_INTEGER DueTime;
-       HANDLE WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
-
-       (void) arg; /* not used */
-
-       if (WaitableTimerHandle != NULL) {
-               DueTime.QuadPart = 0i64;
-               if (SetWaitableTimer(WaitableTimerHandle, &DueTime, 1L /* ms */, TimerApcFunction, &WaitableTimerHandle, FALSE) != NO_ERROR) {
-                       for(;;) {
-                               if (WaitForSingleObjectEx(TimerThreadExitRequest, INFINITE, TRUE) == WAIT_OBJECT_0) {
-                                       break; /* we've been asked to exit */
-                               }
-                       }
-               }
-               CloseHandle(WaitableTimerHandle);
-               WaitableTimerHandle = NULL;
+       if (ntpd_int_int_text) {
+               timer_period_msec = atoi(ntpd_int_int_text);
+               timer_period_msec = max(9, timer_period_msec);
+               msyslog(LOG_NOTICE, 
+                       "using NTPD_INT_INT env var override %u", 
+                       timer_period_msec);
        }
-       return 0;
-}
 
+       TimerHz = 1e3 / timer_period_msec;
+       msyslog(LOG_NOTICE, "HZ %.3f using %u msec timer %.3f Hz %d deep", 
+               HZ,
+               timer_period_msec,
+               TimerHz,
+               BASELINES_USED);
 
-static void StartClockThread(void)
-{
-       DWORD tid;
-       FILETIME StartTime;
-       LARGE_INTEGER Freq = { 0, 0 };
-       
-       /* get the performance counter freq */
-       if (!QueryPerformanceFrequency(&Freq))
-       {
-               msyslog(LOG_ERR, "QueryPerformanceFrequency failed: %m\n");
-               exit (-1);
-       }
+       /* negative DueTime means relative to now */
+       DueTime.QuadPart = -(int)timer_period_msec;
 
-       PerfFrequency = Freq.QuadPart;
+       SetWaitableTimer(
+               timer, 
+               &DueTime,               /* first fire */
+               timer_period_msec,      /* period thereafter */
+               TimerApcFunction,       /* callback routine */
+               &timer,                 /* context for callback */
+               FALSE);                 /* do not interfere with power saving */
 
+       /*
+        * The clock thread spends the rest of its life in the TimerApcFunction
+        * and ctr_freq_timer_fired timer APC callbacks, which can only occur 
+        * while this thread is in an alertable wait.  Note the Ex on 
+        * WaitForSingleObjectEx and TRUE for fAlertable.  The wait will return 
+        * after each APC callback in which case we simply wait again.  We will
+        * break out of the loop when StopClockThread signals our exit event.
+        */
+       do res = WaitForSingleObjectEx(
+                       TimerThreadExitRequest, 
+                       INFINITE, 
+                       TRUE);
+       while (WAIT_OBJECT_0 != res);
 
-       if ( modify_mm_timer != 0)
-       {
-               if (timeGetDevCaps( &tc, sizeof( tc ) ) == TIMERR_NOERROR ) 
-               {
-                       wTimerRes = min( max( tc.wPeriodMin, MM_TIMER_INTV ), tc.wPeriodMax );
+       CloseHandle(timer);
 
-                       timeBeginPeriod( wTimerRes );
-#ifdef DEBUG
-                       msyslog( LOG_INFO, "MM timer resolution: %u..%u ms, set to %u ms\n",
-                                tc.wPeriodMin, tc.wPeriodMax, wTimerRes );
-#endif
-               }
-               else
-                       msyslog( LOG_ERR, "Failed to get MM timer caps\n" );
+       if (ctr_freq_timer != INVALID_HANDLE_VALUE) {
+               CloseHandle(ctr_freq_timer);
+               ctr_freq_timer = INVALID_HANDLE_VALUE;
        }
 
+       return 0;
+}
 
-       /* init variables with the time now */
-       GetSystemTimeAsFileTime(&StartTime);
-       LastTimerTime = (((ULONGLONG) StartTime.dwHighDateTime) << 32) +
-                         (ULONGLONG) StartTime.dwLowDateTime;
 
-       /* init sync objects */
-       InitializeCriticalSection(&TimerCritialSection);
-       TimerThreadExitRequest = CreateEvent(NULL, FALSE, FALSE, "TimerThreadExitRequest");
+static void 
+StartClockThread(void)
+{
+       static BOOL done_once = FALSE;
+       FT_ULL StartTime;
 
-       ClockThreadHandle = CreateThread(NULL, 0, ClockThread, NULL, 
-               CREATE_SUSPENDED, &tid);
+       /* init variables with the time now */
+       GetSystemTimeAsFileTime(&StartTime.ft);
+       baseline_times[0] = StartTime.ull;
+       baseline_counts[0] = perf_ctr();
 
-       if (ClockThreadHandle != NULL) {
+       /* init sync objects */
+       TimerThreadExitRequest = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+       clock_thread = 
+               (HANDLE)_beginthreadex(
+                       NULL, 
+                       0, 
+                       ClockThread, 
+                       NULL, 
+                       CREATE_SUSPENDED, 
+                       &clock_thread_id);
+
+       if (clock_thread != NULL) {
                /* remember the thread priority is only within the process class */
-               if (!SetThreadPriority(ClockThreadHandle, THREAD_PRIORITY_TIME_CRITICAL)) {
+               if (!SetThreadPriority(clock_thread, THREAD_PRIORITY_TIME_CRITICAL)) {
                        DPRINTF(1, ("Error setting thread priority\n"));
                }
 
-               lock_thread_to_processor(ClockThreadHandle);
-               ResumeThread(ClockThreadHandle);
+               lock_thread_to_processor(clock_thread);
+               ResumeThread(clock_thread);
+
+               if (FALSE == done_once) {
+                       done_once = TRUE;
+                       lock_thread_to_processor(GetCurrentThread());
+                       atexit( StopClockThread );
+               }
+
+               /*
+                * Give the clock thread time to fill its counter/time
+                * sample buffer.  This will underfill the buffer a
+                * bit for sample periods over 43 msec.
+                */
+               Sleep(BASELINES_USED * 43);
+       }
+}
+
 
-               lock_thread_to_processor(GetCurrentThread());
+void 
+StopClockThread(void)
+{
+       /*
+        * if the clock thread exit()s this routine
+        * will be called on the clock thread and
+        * we need not (and can't) use the normal
+        * TimerThreadExitRequest event.
+        */
+       if (GetCurrentThreadId() != clock_thread_id) {
 
-               atexit( StopClockThread );
+               if (!SetEvent(TimerThreadExitRequest) ||
+                   WaitForSingleObject(clock_thread, 2 * 1000) != 
+                   WAIT_OBJECT_0) {
+                       msyslog(LOG_ERR, "Failed to stop clock thread.");
+               }
        }
+       CloseHandle(TimerThreadExitRequest);
+       TimerThreadExitRequest = NULL;
+       CloseHandle(clock_thread);
+       clock_thread = NULL;
 }
 
 
@@ -594,7 +936,28 @@ lock_thread_to_processor(HANDLE thread)
        char                    *cputext;
        unsigned int            cpu;
 
+       if ( ! winnt_time_initialized) {
+               DPRINTF(1, ("init_winnt_time() must be called before "
+                               "lock_thread_to_processor(), exiting\n"));
+               exit(-1);
+       }
+
+       if ( ! winnt_use_interpolation)
+               return;
+       
+       if (-1 == use_pcc) {
+               DPRINTF(1, ("perf_ctr is not called before affinity, "
+                           "change lock_thread_to_processor to call it\n"));
+               exit(-1);
+       } else if (0 == use_pcc)
+               return;
+
+       /*
+        * Calculate the ThreadAffinityMask we'll use once on the
+        * first invocation.
+        */
        if ( ! ProcessAffinityMask) {
+
                /*
                 * Choose which processor to nail the main and clock threads to.
                 * If we have more than one, we simply choose the 2nd.
@@ -635,55 +998,540 @@ lock_thread_to_processor(HANDLE thread)
                ThreadAffinityMask = (0 == cpu) ? 0 : (1 << (cpu - 1));
 
                if (ThreadAffinityMask && 
-                       !(ThreadAffinityMask & ProcessAffinityMask)) {
+                       !(ThreadAffinityMask & ProcessAffinityMask)) 
 
                        DPRINTF(1, ("Selected CPU %u (mask %x) is outside "
                                        "process mask %x, using all CPUs.\n",
                                        cpu, ThreadAffinityMask, 
                                        ProcessAffinityMask));
-               } else {
+               else
                        DPRINTF(1, ("Wiring to processor %u (0 means all) "
                                        "affinity mask %x\n",   
                                        cpu, ThreadAffinityMask));
-               }
 
                ThreadAffinityMask &= ProcessAffinityMask;
        }
 
        if (ThreadAffinityMask && 
-               !SetThreadAffinityMask(thread, ThreadAffinityMask)) {
-               
-               DPRINTF(1, ("Unable to wire thread to mask %x: %s\n", 
-                       ThreadAffinityMask, strerror(GetLastError())));
+           !SetThreadAffinityMask(thread, ThreadAffinityMask))
+
+               msyslog(LOG_ERR, 
+                       "Unable to wire thread to mask %x: %m\n", 
+                       ThreadAffinityMask);
+}
+
+
+#ifdef HAVE_PPSAPI
+/*
+ * helper routine for serial PPS which returns QueryPerformanceCounter
+ * timestamp and needs to interpolate it to an NTP timestamp.
+ */
+void 
+pps_ntp_timestamp_from_counter(
+       ntp_fp_t        *result, 
+       ULONGLONG       Timestamp, 
+       ULONGLONG       Counterstamp
+       )
+{
+       /*
+        * convert between equivalent l_fp and PPSAPI ntp_fp_t
+        */
+       ntp_timestamp_from_counter(
+               (l_fp *)result,
+               Timestamp,
+               Counterstamp);
+}
+
+
+void 
+ntp_timestamp_from_counter(
+       l_fp *result, 
+       ULONGLONG Timestamp, 
+       ULONGLONG Counterstamp
+       )
+{
+#ifdef DEBUG
+       FT_ULL          Now;
+#endif
+       ULONGLONG       InterpTimestamp;
+
+       if (winnt_use_interpolation) {
+               InterpTimestamp = interp_time(Counterstamp + QPC_offset, FALSE);
+
+#ifdef DEBUG
+               /* sanity check timestamp is within 1 minute of now */
+               GetSystemTimeAsFileTime(&Now.ft);
+               Now.ll -= InterpTimestamp;
+               if (Now.ll > 60 * HECTONANOSECONDS || 
+                   Now.ll < -60 * (LONGLONG) HECTONANOSECONDS) {
+                       DPRINTF(1, ("ntp_timestamp_from_counter interpolated "
+                                   "time %.6fs from current\n",
+                                       Now.ll / (double) HECTONANOSECONDS));
+                       DPRINTF(1, ("interpol time %llx from  %llx\n",
+                                       InterpTimestamp,
+                                       Counterstamp));
+                       exit(-1);
+               }
+#endif
+       } else {  /* ! winnt_use_interpolation */
+               /* have to simply use the driver's system time timestamp */
+               InterpTimestamp = Timestamp;
+#ifdef DEBUG
+               /* sanity check timestamp is within 1 minute of now */
+               GetSystemTimeAsFileTime(&Now.ft);
+               Now.ll -= InterpTimestamp;
+               if (Now.ll > 60 * HECTONANOSECONDS || 
+                   Now.ll < -60 * (LONGLONG) HECTONANOSECONDS) {
+                       DPRINTF(1, ("ntp_timestamp_from_counter serial driver system "
+                                   "time %.6fs from current\n",
+                                   Now.ll / (double) HECTONANOSECONDS));
+                       exit(-1);
+               }
+#endif
        }
+
+       /* convert from 100ns units to NTP fixed point format */
+
+       InterpTimestamp -= FILETIME_1970;
+       result->l_ui = JAN_1970 + (u_int32)(InterpTimestamp / HECTONANOSECONDS);
+       result->l_uf = (u_int32)((InterpTimestamp % HECTONANOSECONDS) *
+                                (FRAC / HECTONANOSECONDS));
 }
+#endif  /* HAVE_PPSAPI */
 
 
-static void StopClockThread(void)
-{      
-       if ( wTimerRes )  /* if not 0 then the MM timer has been modified at startup */
-       {
-               timeEndPeriod( wTimerRes ); 
-               wTimerRes = 0;
+void 
+time_stepped(void)
+{
+       /*
+        * called back by ntp_set_tod after the system
+        * time has been stepped (set).
+        *
+        * We normally prevent the reported time from going backwards
+        * but need to allow it in this case.
+        */
+       if (FALSE == winnt_use_interpolation)
+               return;
+
+
+       /*
+        * Restart the clock thread to get a new baseline
+        * time/counter correlation.
+        */
+       StopClockThread();
+
+       /*
+        * newest_baseline_gen is a generation counter
+        * incremented once each time newest_baseline
+        * is reset.
+        */
+       newest_baseline_gen++;
+
+       last_interp_time = 
+               clock_backward_max = 
+               clock_backward_count = 
+               newest_baseline = 0;
+
+       memset(baseline_counts, 0, sizeof(baseline_counts));
+       memset(baseline_times, 0, sizeof(baseline_times));
+
+       StartClockThread();
+}
+
+
+/*
+ * log2ull - log base 2 of a unsigned 64-bit number
+ */
+int 
+log2ull(
+       ULONGLONG n
+       )
+{
+       const ULONGLONG one = 1;
+       int log = 0;
+
+       if (n >= one<<32) { n >>= 32; log += 32; }
+       if (n >= one<<16) { n >>= 16; log += 16; }
+       if (n >= one<< 8) { n >>=  8; log +=  8; }
+       if (n >= one<< 4) { n >>=  4; log +=  4; }
+       if (n >= one<< 2) { n >>=  2; log +=  2; }
+       if (n >= one<< 1) {           log +=  1; }
+
+       return (n) ? log : (-1);
+}
+
+
+/*
+ * ctr_freq_timer_fired is called once a few seconds before
+ * tune_ctr_period seconds have elapsed, to reset the timer
+ * and hopefully minimize error due to the system using the
+ * nominal performance counter frequency to set the timer
+ * internally, which is typically dozens of PPM from the
+ * actual performance counter rate.  A few seconds later
+ * it is called again to observe the counter and estimate the
+ * counter frequency.
+ */
+static void CALLBACK
+ctr_freq_timer_fired(
+       LPVOID arg,
+       DWORD dwTimeLow,
+       DWORD dwTimeHigh
+       )
+{
+       static FT_ULL           begin_time = {0};
+       static FT_ULL           begin_count = {0};
+       static ULONGLONG        next_period_time = 0;
+       static ULONGLONG        report_systemtime = 0;
+       FT_ULL                  now_time;
+       FT_ULL                  now_count;
+
+       if (!begin_time.ull) {
+               begin_count.ull = perf_ctr();
+               begin_time.ft.dwLowDateTime = dwTimeLow;
+               begin_time.ft.dwHighDateTime = dwTimeHigh;
+
+               /*
+                * adapt perf ctr observation interval to the
+                * counter frequency
+                */
+               tune_ctr_period = 22680 / log2ull(NomPerfCtrFreq);
+
+               /*
+                * reset timer 2s before period ends to minimize
+                * error from OS timer routines using nominal 
+                * performance frequency internally.
+                */
+               tune_ctr_freq_max_interval = tune_ctr_period - 2;
+
+               next_period_time = begin_time.ull + 
+                       (ULONGLONG)tune_ctr_period * HECTONANOSECONDS;
+
+               ROUND_TO_NEXT_SEC_BOTTOM(next_period_time);
+
+               reset_ctr_freq_timer(next_period_time, begin_time.ull);
+
+               return;
+       }
+
+       now_time.ft.dwLowDateTime = dwTimeLow;
+       now_time.ft.dwHighDateTime = dwTimeHigh;
+
+       if (now_time.ull >= next_period_time) {
+
+               now_count.ull = perf_ctr();
+               tune_ctr_freq(
+                       now_count.ull - begin_count.ull,
+                       now_time.ull - begin_time.ull);
+
+               next_period_time += (ULONGLONG)tune_ctr_period * HECTONANOSECONDS;
+               begin_count.ull = now_count.ull;
+               begin_time.ull = now_time.ull;
+       }
+
+       /* 
+        * Log clock backward events no more often than 5 minutes.
+        */
+       if (!report_systemtime) 
+
+               report_systemtime = now_time.ull +
+                       5 * 60 * HECTONANOSECONDS;
+
+       else if (report_systemtime <= now_time.ull) {
+
+               report_systemtime +=  5 * 60 * HECTONANOSECONDS;
+
+               if (clock_backward_count) {
+                       msyslog(LOG_WARNING, 
+                               "clock would have gone backward %d times, "
+                               "max %.1f usec",
+                               clock_backward_count, 
+                               clock_backward_max / 10.);
+
+                       clock_backward_max = clock_backward_count = 0;
+               }
+       }
+
+       reset_ctr_freq_timer(next_period_time, now_time.ull);
+}
+
+
+void
+reset_ctr_freq_timer_abs(
+       ULONGLONG when
+       )
+{
+       FT_ULL  fire_time;
+
+       fire_time.ull = when; 
+
+       SetWaitableTimer(
+               ctr_freq_timer,
+               &fire_time.li,          /* first fire */
+               0,                      /* not periodic */
+               ctr_freq_timer_fired,   /* callback routine */
+               NULL,                   /* context for callback */
+               FALSE);                 /* do not interfere with power saving */
+}
+
+
+void
+reset_ctr_freq_timer(
+       ULONGLONG when,
+       ULONGLONG now
+       )
+{
+       if (when - now > 
+           (tune_ctr_freq_max_interval * HECTONANOSECONDS + HECTONANOSECONDS))
+
+               when = now + tune_ctr_freq_max_interval * HECTONANOSECONDS;
+
+       reset_ctr_freq_timer_abs(when);
+}
+
+
+void
+start_ctr_freq_timer(
+       ULONGLONG now_time
+       )
+{
+       ULONGLONG when;
+
+       ctr_freq_timer = CreateWaitableTimer(NULL, FALSE, NULL);
+
+       when = now_time;
+       ROUND_TO_NEXT_SEC_BOTTOM(when);
+
+       reset_ctr_freq_timer_abs(when);
+}
+
+
+/*
+ * tune_ctr_freq is called once per tune_ctr_period seconds
+ * with a counter difference and time difference.
+ */
+void 
+tune_ctr_freq(
+       LONGLONG ctr_delta,
+       LONGLONG time_delta
+       )
+{
+       static unsigned count = 0;
+       static unsigned dispcount = 0;
+       static unsigned report_at_count = 0;
+       static int disbelieved = 0;
+       static int i = 0;
+       static double nom_freq = 0;
+       static LONGLONG diffs[TUNE_CTR_DEPTH] = {0};
+       static LONGLONG sum = 0;
+
+       LONGLONG delta;
+       LONGLONG deltadiff;
+       ULONGLONG ObsPerfCtrFreq;
+       double obs_freq;
+       double this_freq;
+       int isneg;
+
+       /* nom_freq is constant over the run */
+       if (!report_at_count) {
+               report_at_count = 24 * 60 * 60 / tune_ctr_period;
+               nom_freq = NomPerfCtrFreq / 1e6;
+       }
+
+       /* delta is the per-second observed frequency this time */
+       delta = (LONGLONG)((double)ctr_delta * HECTONANOSECONDS /
+                          time_delta);
+
+       /* disbelieve any delta more than +/- 976 PPM from nominal */
+       deltadiff = delta - NomPerfCtrFreq;
+       if (0 > deltadiff) {
+               isneg = 1;
+               deltadiff = -deltadiff;
+       } else
+               isneg = 0;
+
+       if ((ULONGLONG)deltadiff > (NomPerfCtrFreq / 1024)) {
+               disbelieved++;
+               dispcount++;
 #ifdef DEBUG
-               msyslog( LOG_INFO, "MM timer set to default\n" );
+               msyslog(LOG_DEBUG, "ctr delta %s%lld exceeds limit %llu",
+                                  (isneg) ? "-" : "",
+                                  deltadiff,
+                                  NomPerfCtrFreq / 1024);
 #endif
+       } else {
+
+               /*
+                * collect average over TUNE_CTR_DEPTH samples
+                * for our PerfCtrFreq trimming.
+                */
+
+               if (isneg)
+                       deltadiff = -deltadiff;
+               sum -= diffs[i];
+               diffs[i] = deltadiff;
+               sum += deltadiff;
+               i = (i + 1) % COUNTOF(diffs);
+               count++;
+               dispcount++;
        }
 
-       if (SetEvent(TimerThreadExitRequest) &&
-           WaitForSingleObject(ClockThreadHandle, 10000L) == 0)
-       {
-               CloseHandle(TimerThreadExitRequest);
-               TimerThreadExitRequest = NULL;
+       this_freq = delta / 1e6;
+
+       ObsPerfCtrFreq = NomPerfCtrFreq + (sum / COUNTOF(diffs));
+
+#if 1  /* #if 0 to disable changing freq used */
+       /* get rid of ObsPerfCtrFreq when removing the #ifdef */
+       PerfCtrFreq = ObsPerfCtrFreq;
+#endif
+       obs_freq = ObsPerfCtrFreq / 1e6;
 
-               CloseHandle(ClockThreadHandle);
-               ClockThreadHandle = NULL;
+       /* 
+        * report observed ctr freq each time the estimate used during
+        * startup moves toward the observed freq from the nominal, 
+        * and once a day afterward.
+        */
 
-               DeleteCriticalSection(&TimerCritialSection);
+       if (count > COUNTOF(diffs) &&
+           /* (count % COUNTOF(diffs)) && */   /* enables reporting each */
+           dispcount < report_at_count)        /* TUNE_CTR_DEPTH samples */
+               return;
+
+       NLOG(NLOG_CLOCKINFO)
+               if (count <= COUNTOF(diffs))
+                       /* moving to observed freq. from nominal (startup) */
+                       msyslog(LOG_INFO,
+                               (obs_freq > 100)
+                                ? "ctr %.3f MHz %+6.2f PPM using "
+                                      "%.3f MHz %+6.2f PPM"
+                                : "ctr %.6f MHz %+6.2f PPM using "
+                                      "%.6f MHz %+6.2f PPM",
+                               this_freq,
+                               1e6 * (this_freq - nom_freq) / nom_freq,
+                               obs_freq, 
+                               1e6 * (obs_freq - nom_freq) / nom_freq);
+               else
+                       /* steady state */
+                       msyslog(LOG_INFO,
+                               (obs_freq > 100)
+                                ? "ctr %.3f MHz %+.2f PPM"
+                                : "ctr %.6f MHz %+.2f PPM",
+                               obs_freq, 
+                               1e6 * (obs_freq - nom_freq) / nom_freq);
+
+       if (disbelieved) {
+               msyslog(LOG_ERR, 
+                       "%d ctr samples exceed +/- 976 PPM range gate",
+                       disbelieved);
+               disbelieved = 0;
        }
-       else
-       {
-               msyslog(LOG_ERR, "Failed to stop clock thread.");
-               Sleep( 100 );
+
+       dispcount = 0;
+}
+
+
+/*
+ * add_counter_time_pair is called by the
+ * high priority clock thread with each new
+ * baseline counter/time correlation.
+ */
+void
+add_counter_time_pair(
+       ULONGLONG ctr,
+       LONGLONG time
+       )
+{
+       int i;
+
+       i = (newest_baseline + 1) % BASELINES_TOT;
+
+       baseline_counts[i] = ctr;
+       baseline_times[i] = time;
+
+       newest_baseline = i;
+}
+
+
+/*
+ * interp_time estimates NT time in 100ns units
+ * based on a performance counter value given.
+ * This must tolerate recent historical counters
+ * as well as current.  When current is FALSE
+ * we can't assume ctr is the latest/highest
+ * seen.
+ */
+ULONGLONG
+interp_time(
+       ULONGLONG ctr,
+       BOOL current
+       )
+{
+       static __declspec(thread) int           last_newest = -1;
+       static __declspec(thread) int           last_newest_gen;
+       static __declspec(thread) int           best_index;
+       ULONGLONG       this_ctr;
+       LONGLONG        this_time;
+       LONGLONG        latest_time;
+       LONGLONG        ctr_diff;
+       int             i;
+       int             i_gen;
+       int             c;
+
+       /*
+        * Use the system time (roughly synchronised to the tick, and
+        * extrapolated using the system performance counter.
+        *
+        * Cache the results per thread and only repeat the
+        * calculation when new data has arrived.
+        */
+       i = newest_baseline;
+       i_gen = newest_baseline_gen;
+
+       if (last_newest == i && last_newest_gen == i_gen) {
+               this_time = baseline_times[best_index];
+               ctr_diff = ctr - baseline_counts[best_index];
+               this_time += (LONGLONG)PERF2HNS((double)ctr_diff);
+               return this_time;
        }
+
+       last_newest = i;
+       last_newest_gen = i_gen;
+
+       latest_time = 0;
+
+       /*
+        * Run through the history calculating the interpolated 
+        * time based on each counter/time correlation in turn,
+        * and believe the latest one.  This is akin to the NTP
+        * protocol minimum delay clock filter.  Errors due to 
+        * counter/time correlations with stale time are all 
+        * negative.
+        */
+       for (c = 0; c < BASELINES_USED; c++) {
+                if (baseline_times[i]) {
+                       this_time = baseline_times[i];
+                       this_ctr = baseline_counts[i];
+
+                       ctr_diff = ctr - this_ctr;
+
+                       if (current && ctr_diff < 0) {
+                               /* 
+                                * The performance counter apparently went 
+                                * backwards without rolling over.  It might 
+                                * be nice to complain but we don't want 
+                                * to do it repeatedly.
+                                */
+                               ctr_diff = 0;
+                       }
+
+                       this_time += (LONGLONG)PERF2HNS((double)ctr_diff);
+
+                       if (this_time > latest_time) {
+                               latest_time = this_time;
+                               best_index = i;
+                       }
+               }
+               i = i ? (i - 1) : (BASELINES_TOT - 1);
+       }
+
+       return latest_time;
 }
index 449dde113069dcad299cb97c73774ee67ff88379..7f7500e39175771dceb141af8e8b0fd483f0877d 100644 (file)
@@ -17,6 +17,7 @@
 #include "ntp_iocompletionport.h"
 #include "transmitbuff.h"
 #include "ntp_request.h"
+#include "clockstuff.h"
 #include "ntp_io.h"
 
 /*
@@ -54,9 +55,6 @@ typedef struct IoCompletionInfo {
   typedef DWORD ULONG_PTR;
 #endif
 
-/* in nt_clockstuff.c */
-extern void lock_thread_to_processor(HANDLE);
-
 /*
  * local function definitions
  */
@@ -157,7 +155,7 @@ iocompletionthread(void *NotUsed)
        IoCompletionInfo * lpo = NULL;
        u_long time_next_ifscan_after_error = 0;
 
-       /* UNUSED_ARG(NotUsed); */
+       UNUSED_ARG(NotUsed);
 
        /*
         *      socket and refclock receive call gettimeofday()
@@ -697,7 +695,7 @@ OnWriteComplete(ULONG_PTR i, IoCompletionInfo *lpo, DWORD Bytes, int errstatus)
        transmitbuf_t *buff;
        struct interface *inter;
 
-       /* UNUSED_ARG(Bytes); */
+       UNUSED_ARG(Bytes);
 
        buff = lpo->trans_buf;
 
index a9afe1f681b9f9bf85a646c465ca8762658a1ffc..4aaf8c09e8ece4d8092f2e36189cc1abddc2d07c 100644 (file)
 #include <crtdbg.h>
 #endif
 
+
 /* Handle to SCM for updating service status */
 static SERVICE_STATUS_HANDLE hServiceStatus = 0;
 static BOOL foreground = FALSE;
-static char ConsoleTitle[128];
+static BOOL computer_shutting_down = FALSE;
 static int glb_argc;
 static char **glb_argv;
 HANDLE hServDoneEvent = NULL;
 int accept_wildcard_if_for_winnt;
 extern volatile int debug;
-extern char *progname;
 
 void uninit_io_completion_port();
 int ntpdmain(int argc, char *argv[]);
 /*
  * Forward declarations
  */
-void ServiceControl(DWORD dwCtrlCode);
+void WINAPI ServiceControl(DWORD dwCtrlCode);
 void ntservice_exit(void);
 
 void WINAPI service_main( DWORD argc, LPTSTR *argv )
@@ -99,27 +99,27 @@ int main( int argc, char *argv[] )
 
        if (foreground) {
                /* run in console window */
-               exit(ntpdmain(argc, argv));
+               rc = ntpdmain(argc, argv);
        } else {
                /* Start up as service */
 
                SERVICE_TABLE_ENTRY dispatchTable[] = {
-                       { TEXT(NTP_DISPLAY_NAME), (LPSERVICE_MAIN_FUNCTION) service_main },
+                       { TEXT(NTP_DISPLAY_NAME), service_main },
                        { NULL, NULL }
                };
 
                rc = StartServiceCtrlDispatcher(dispatchTable);
-               if (!rc) {
-                       progname = argv[0];
+               if (rc)
+                       rc = 0; 
+               else {
                        rc = GetLastError();
 #ifdef DEBUG
-                       fprintf(stderr, "%s: unable to start as service, rc: %i\n\n", progname, rc);
+                       fprintf(stderr, "%s: unable to start as service, rc: %i\n\n", argv[0], rc);
 #endif
                        fprintf(stderr, "\nUse -d, -q, --help or -n to run from the command line.\n");
-                       exit(rc);
                }
        }
-       exit(0);
+       return rc;
 }
 
 /*
@@ -127,14 +127,15 @@ int main( int argc, char *argv[] )
  */
 void
 ntservice_init() {
+       char ConsoleTitle[256];
+
        if (!foreground) {
                /* Register handler with the SCM */
                hServiceStatus = RegisterServiceCtrlHandler(NTP_DISPLAY_NAME,
-                                       (LPHANDLER_FUNCTION)ServiceControl);
+                                       ServiceControl);
                if (!hServiceStatus) {
                        NTReportError(NTP_SERVICE_NAME,
                                "could not register service control handler");
-                       UpdateSCM(SERVICE_STOPPED);
                        exit(1);
                }
                UpdateSCM(SERVICE_RUNNING);
@@ -146,6 +147,7 @@ ntservice_init() {
 
        atexit( ntservice_exit );
 }
+
 /*
  * Routine to check if this is a service or a foreground program
  */
@@ -153,22 +155,19 @@ BOOL
 ntservice_isservice() {
        return(!foreground);
 }
-/* service_ctrl - control handler for NTP service
- * signals the service_main routine of start/stop requests
- * from the control panel or other applications making
- * win32API calls
+
+/*
+ * Routine to check if the service is stopping
+ * because the computer is shutting down
  */
+BOOL
+ntservice_systemisshuttingdown() {
+       return computer_shutting_down;
+}
+
 void
 ntservice_exit( void )
 {
-
-       if (!foreground) { /* did not become a service, simply exit */
-               /* service mode, need to have the service_main routine
-                * register with the service control manager that the 
-                * service has stopped running, before exiting
-                */
-               UpdateSCM(SERVICE_STOPPED);
-       }
        uninit_io_completion_port();
        Sleep( 200 );   //##++ 
 
@@ -179,13 +178,21 @@ ntservice_exit( void )
 # ifdef DEBUG
        _CrtDumpMemoryLeaks();
 # endif 
+
+       if (!foreground) {
+               /* service mode, need to have the service_main routine
+                * register with the service control manager that the 
+                * service has stopped running, before exiting
+                */
+               UpdateSCM(SERVICE_STOPPED);
+       }
 }
 
 /* 
  * ServiceControl(): Handles requests from the SCM and passes them on
  * to the service.
  */
-void
+void WINAPI
 ServiceControl(DWORD dwCtrlCode) {
        /* Handle the requested control code */
        HANDLE exitEvent = get_exit_event();
@@ -193,14 +200,17 @@ ServiceControl(DWORD dwCtrlCode) {
        switch(dwCtrlCode) {
 
        case SERVICE_CONTROL_SHUTDOWN:
+               computer_shutting_down = TRUE;
+               /* fall through to stop case */
+
        case SERVICE_CONTROL_STOP:
-               UpdateSCM(SERVICE_STOP_PENDING);
                if (exitEvent != NULL) {
                        SetEvent(exitEvent);
+                       UpdateSCM(SERVICE_STOP_PENDING);
                        Sleep( 100 );  //##++
                }
                return;
+
        case SERVICE_CONTROL_PAUSE:
        case SERVICE_CONTROL_CONTINUE:
        case SERVICE_CONTROL_INTERROGATE:
@@ -231,10 +241,7 @@ void UpdateSCM(DWORD state) {
                ss.dwWin32ExitCode = NO_ERROR;
                ss.dwWaitHint = dwState == SERVICE_STOP_PENDING ? 5000 : 1000;
 
-               if (!SetServiceStatus(hServiceStatus, &ss)) {
-                       ss.dwCurrentState = SERVICE_STOPPED;
-                       SetServiceStatus(hServiceStatus, &ss);
-               }
+               SetServiceStatus(hServiceStatus, &ss);
        }
 }
 
@@ -247,7 +254,7 @@ OnConsoleEvent(
 
        switch (dwCtrlType) {
 #ifdef DEBUG
-               case CTRL_BREAK_EVENT :
+               case CTRL_BREAK_EVENT:
                        if (debug > 0) {
                                debug <<= 1;
                        }
@@ -257,24 +264,28 @@ OnConsoleEvent(
                        if (debug > 8) {
                                debug = 0;
                        }
-                       printf("debug level %d\n", debug);
-               break ;
+                       msyslog(LOG_DEBUG, "debug level %d", debug);
+                       break;
+#else
+               case CTRL_BREAK_EVENT:
+                       break;
 #endif
 
-               case CTRL_C_EVENT  :
-               case CTRL_CLOSE_EVENT :
-               case CTRL_SHUTDOWN_EVENT :
+               case CTRL_C_EVENT:
+               case CTRL_CLOSE_EVENT:
+               case CTRL_SHUTDOWN_EVENT:
                        if (exitEvent != NULL) {
                                SetEvent(exitEvent);
                                Sleep( 100 );  //##++
                        }
-               break;
+                       break;
 
                default :
-                       return FALSE;
-
-
+                       /* pass to next handler */
+                       return FALSE; 
        }
+
+       /* we've handled it, no more handlers should be called */
        return TRUE;;
 }
 
index 20aa6dc890d3b9ea4898013d336fd61bba6f2a19..c8718464a7b384806b81535731fa3e95d084e39d 100644 (file)
 #define MAX_SERIAL 16  /* COM1-COM16 */
 
 
-int NT_set_process_priority(void)
-{
-       if (!SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS)) 
-               {
-               msyslog(LOG_ERR, "SetPriorityClass: %m"); 
-               return 0;
-               }
-       else 
-               return 1;
-}
-
-
 /*
  * common_serial_open ensures duplicate opens of the same port
  * work by duplicating the handle for the 2nd open, allowing
index 37e0c145a55db48d231572a4866e37417729af74..3edd8e901a504c1a1804a7f464b8374ff3212024 100644 (file)
                                        />
                                </FileConfiguration>
                        </File>
-                       <File
-                               RelativePath="..\libntp\util_clockstuff.c"
-                               >
-                               <FileConfiguration
-                                       Name="Debug|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                               <FileConfiguration
-                                       Name="Release|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                       </File>
                        <File
                                RelativePath="version.c"
                                >
index 94b6211294851c1db2ff0b5a712f36d900adbbc7..cee1866b7ae2481dd5cc33e23f8b39771ba64aaa 100644 (file)
                                        />
                                </FileConfiguration>
                        </File>
-                       <File
-                               RelativePath="..\libntp\util_clockstuff.c"
-                               >
-                               <FileConfiguration
-                                       Name="Debug|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                               <FileConfiguration
-                                       Name="Release|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                       </File>
                        <File
                                RelativePath="version.c"
                                >
index bf2b57d484c7aa7ca88f7e0090ee4650309c5806..7803454f12bb44bab79d6576a646e6fa1ecb5409 100644 (file)
                                        />
                                </FileConfiguration>
                        </File>
-                       <File
-                               RelativePath="..\libntp\util_clockstuff.c"
-                               >
-                               <FileConfiguration
-                                       Name="Release|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                               <FileConfiguration
-                                       Name="Debug|Win32"
-                                       >
-                                       <Tool
-                                               Name="VCCLCompilerTool"
-                                               AdditionalIncludeDirectories=""
-                                               PreprocessorDefinitions=""
-                                       />
-                               </FileConfiguration>
-                       </File>
                        <File
                                RelativePath="version.c"
                                >
index 71e6d80323b6f968343d174c727e3aeeb208e5a8..f548be43f56f2ef97eb4dfbc6ba81e319ff9e54c 100755 (executable)
@@ -130,14 +130,14 @@ REM ****************************************************************************
        SET UTC_SIGN=
        
        REM *** Now get the timezone settings from the registry
-       regedit /e %TEMP%\TZ.TMP "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
-       IF NOT EXIST %TEMP%\TZ.TMP GOTO NOTZINFO
+       regedit /e %TEMP%\TZ-%GENERATED_PROGRAM%.TMP "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
+       IF NOT EXIST %TEMP%\TZ-%GENERATED_PROGRAM%.TMP GOTO NOTZINFO
 
-       for /f "Tokens=1* Delims==" %%a in ('type %TEMP%\TZ.TMP') do if %%a == "ActiveTimeBias" SET ACTIVEBIAS=%%b
+       for /f "Tokens=1* Delims==" %%a in ('type %TEMP%\TZ-%GENERATED_PROGRAM%.TMP') do if %%a == "ActiveTimeBias" SET ACTIVEBIAS=%%b
        for /f "Tokens=1* Delims=:" %%a in ('echo %ACTIVEBIAS%') do ( SET ACTIVEBIAS=%%b & SET PARTYP=%%a )
        
        REM *** Clean up temporary file
-       IF EXIST %TEMP%\TZ.TMP DEL %TEMP%\TZ.TMP
+       IF EXIST %TEMP%\TZ-%GENERATED_PROGRAM%.TMP DEL %TEMP%\TZ-%GENERATED_PROGRAM%.TMP
        
        REM *** Check if we really got a dword value from the registry ...
        IF NOT "%PARTYP%"=="dword " goto NOTZINFO
index f6aa55b8965dfe4f8b6e9194fbe963d82857d631..787cf4d7c218afc2ed543262d132e78f24013f5f 100644 (file)
@@ -279,11 +279,8 @@ main(
         */
        gethostname(hostbuf, MAXHOSTNAME);
        hostname = hostbuf;
-#ifndef SYS_WINNT
        gettimeofday(&tv, 0);
-#else
-       gettimeofday(&tv);
-#endif
+
        epoch = tv.tv_sec;
 
        {