Annotation of embedaddon/ntp/ports/winnt/ntpd/nt_clockstuff.c, revision 1.1.1.1

1.1       misho       1: /* Windows NT Clock Routines
                      2:  *
                      3:  * Created by Sven Dietrich  sven@inter-yacht.com
                      4:  *
                      5:  * New interpolation scheme by Dave Hart <davehart@davehart.com> February 2009
                      6:  * overcomes 500us-1ms inherent jitter with the older scheme, first identified
                      7:  * by Peter Rosin (nee Ekberg) <peda@lysator.liu.se> in 2003 [Bug 216].
                      8:  */
                      9: 
                     10: 
                     11: #ifdef HAVE_CONFIG_H
                     12: #include "config.h"
                     13: #endif
                     14: 
                     15: #include <sys/resource.h>      /* our private version */
                     16: 
                     17: #if defined(_MSC_VER) && _MSC_VER >= 1400      /* VS 2005 */
                     18: #include <intrin.h>                            /* for __rdtsc() */
                     19: #endif
                     20: 
                     21: #ifdef HAVE_PPSAPI
                     22: #include <timepps.h>
                     23: /*
                     24:  * ports/winnt/include/timepps.h defines EOPNOTSUPP for compatibility
                     25:  * with PPSAPI on other platforms.  ports/winnt/include/isc/net.h has
                     26:  * #define EOPNOTSUPP WSAEOPNOTSUPP, so to avoid a macro redefinition
                     27:  * warning undefine it.
                     28:  */
                     29: #undef EOPNOTSUPP
                     30: #endif /* HAVE_PPSAPI */
                     31: 
                     32: #include "ntp_stdlib.h"
                     33: #include "ntp_unixtime.h"
                     34: #include "ntp_timer.h"
                     35: #include "ntp_assert.h"
                     36: #include "clockstuff.h"
                     37: #include "ntservice.h"
                     38: #include "ntpd.h"
                     39: #include "../../../ntpd/ntpd-opts.h"
                     40: 
                     41: extern double sys_residual;    /* residual from previous adjustment */
                     42: 
                     43: /*
                     44:  * Include code to possibly modify the MM timer while the service is active. 
                     45:  */
                     46: 
                     47: /*
                     48:  * Whether or not MM timer modifications takes place is still controlled 
                     49:  * by the variable below which is initialized by a default value but 
                     50:  * might be changed depending on a command line switch.
                     51:  */
                     52: static int modify_mm_timer = MM_TIMER_LORES;
                     53: 
                     54: #define MM_TIMER_INTV   1  /* the interval we'd want to set the MM timer to [ms] */
                     55: 
                     56: static UINT wTimerRes;
                     57: 
                     58: BOOL init_randfile();
                     59: 
                     60: static long last_Adj = 0;
                     61: 
                     62: #define LS_CORR_INTV_SECS  2   /* seconds to apply leap second correction */
                     63: #define LS_CORR_INTV   ( (LONGLONG) HECTONANOSECONDS * LS_CORR_INTV_SECS )  
                     64: #define LS_CORR_LIMIT  ( (LONGLONG) HECTONANOSECONDS / 2 )  // half a second
                     65: 
                     66: typedef union ft_ull {
                     67:        FILETIME ft;
                     68:        ULONGLONG ull;
                     69:        LONGLONG ll;
                     70:        LARGE_INTEGER li;
                     71: } FT_ULL;
                     72: 
                     73: /* leap second stuff */
                     74: static FT_ULL ls_ft;
                     75: static DWORD ls_time_adjustment;
                     76: static ULONGLONG ls_ref_perf_cnt;
                     77: static LONGLONG ls_elapsed;
                     78: 
                     79: static BOOL winnt_time_initialized = FALSE;
                     80: static BOOL winnt_use_interpolation = FALSE;
                     81: static ULONGLONG last_interp_time;
                     82: static unsigned clock_thread_id;
                     83: 
                     84: 
                     85: void WINAPI GetInterpTimeAsFileTime(LPFILETIME pft);
                     86: static void StartClockThread(void);
                     87: static void tune_ctr_freq(LONGLONG, LONGLONG);
                     88: void StopClockThread(void);
                     89: void atexit_revert_mm_timer(void);
                     90: void time_stepped(void);
                     91: 
                     92: static HANDLE clock_thread = NULL;
                     93: static HANDLE TimerThreadExitRequest = NULL;
                     94: 
                     95: /*
                     96:  * interp_time estimates time in 100ns units
                     97:  * based on a performance counter value given.
                     98:  * The 2nd parameter indicates if this is
                     99:  * part of a current time-of-day calculation.
                    100:  */
                    101: ULONGLONG interp_time(ULONGLONG, BOOL);
                    102: 
                    103: /*
                    104:  * add_counter_time_pair is called by the
                    105:  * high priority clock thread with a new
                    106:  * sample.
                    107:  */
                    108: void add_counter_time_pair(ULONGLONG, LONGLONG);
                    109: 
                    110: /*
                    111:  * globals used by the above two functions to 
                    112:  * implement the counter/time history
                    113:  */
                    114: #define BASELINES_TOT  256
                    115: #define BASELINES_USED 64
                    116: 
                    117: static volatile int    newest_baseline = 0;
                    118: static volatile int    newest_baseline_gen = 0;
                    119: static ULONGLONG       baseline_counts[BASELINES_TOT] = {0};
                    120: static LONGLONG                baseline_times[BASELINES_TOT] = {0};
                    121: 
                    122: static int             clock_backward_count;
                    123: static ULONGLONG       clock_backward_max;
                    124: 
                    125: 
                    126: /*
                    127:  * clockperiod is the period used for SetSystemTimeAdjustment 
                    128:  * slewing calculations but does not necessarily correspond
                    129:  * to the precision of the OS clock.  Prior to Windows Vista
                    130:  * (6.0) the two were identical.  In 100ns units.
                    131:  */
                    132: static DWORD clockperiod;
                    133: 
                    134: /*
                    135:  * os_clock_precision is the observed precision of the OS
                    136:  * clock, meaning the increment between discrete values. This
                    137:  * is currently calculated once at startup.  100ns units.
                    138:  */
                    139: static ULONGLONG os_clock_precision;
                    140: 
                    141: /*
                    142:  * NomPerfCtrFreq is from QueryPerformanceFrequency and is the 
                    143:  * number of performance counter beats per second.  PerfCtrFreq
                    144:  * starts from NomPerfCtrFreq but is maintained using a sliding
                    145:  * window average based on actual performance counter behavior,
                    146:  * to allow us to better tolerate powersaving measures that
                    147:  * alter the effective frequency of the processor cycle counter
                    148:  * (TSC) which sometimes underlies QueryPerformanceCounter.
                    149:  *
                    150:  * Note that the OS is unlikely to be so subtle in its internal
                    151:  * scheduling of waitable timers, presumably done using the
                    152:  * performance counter.  Therefore our calculations for
                    153:  * interpolated time should be based on PerfCtrFreq but our
                    154:  * calculations for SetWaitableTimer should assume the OS will
                    155:  * convert from FILETIME 100ns units to performance counter
                    156:  * beats using the nominal frequency.
                    157:  */
                    158: 
                    159: volatile ULONGLONG PerfCtrFreq = 0;
                    160:         ULONGLONG NomPerfCtrFreq = 0;
                    161: 
                    162: /* 
                    163:  * If we're using RDTSC beating at the same rate as
                    164:  * QueryPerformanceCounter, there is a systemic
                    165:  * offset we need to account for when using
                    166:  * counterstamps from serialpps.sys, which are
                    167:  * always from QPC (actually KeQueryPerformanceCounter).
                    168:  */
                    169: static LONGLONG QPC_offset = 0;
                    170: 
                    171: /*
                    172:  * Substitute RDTSC for QueryPerformanceCounter()?
                    173:  */
                    174: static int use_pcc = -1;
                    175: 
                    176: /*
                    177:  * Restrict threads that call QPC/RDTSC to one CPU?
                    178:  */
                    179: static int lock_interp_threads = -1;
                    180: 
                    181: static void    choose_interp_counter(void);
                    182: static int     is_qpc_built_on_pcc(void);
                    183: 
                    184: /*
                    185:  * ppm_per_adjust_unit is parts per million effect on the OS
                    186:  * clock per slewing adjustment unit per second.  Per haps.
                    187:  */
                    188: static DOUBLE ppm_per_adjust_unit = 0.0;
                    189: 
                    190: /*
                    191:  * wintickadj emulates the functionality provided by unix tickadj,
                    192:  * providing a baseline clock correction if needed to get the
                    193:  * clock within a few hundred PPM of correct frequency.
                    194:  */
                    195: static long wintickadj;
                    196: 
                    197: /*
                    198:  * performance counter frequency observations
                    199:  */
                    200: #define TUNE_CTR_DEPTH         3       /* running avg depth */
                    201: 
                    202: static HANDLE          ctr_freq_timer = INVALID_HANDLE_VALUE;
                    203: static ULONGLONG       tune_ctr_freq_max_interval;
                    204: static unsigned                tune_ctr_period;
                    205: void start_ctr_freq_timer(ULONGLONG now_time);
                    206: void reset_ctr_freq_timer(ULONGLONG when, ULONGLONG now);
                    207: void reset_ctr_freq_timer_abs(ULONGLONG when);
                    208: 
                    209: /* round a Windows time to the next bottom of the second */
                    210: 
                    211: #define ROUND_TO_NEXT_SEC_BOTTOM(t)    \
                    212: do {   \
                    213:        (t) += 3 * HECTONANOSECONDS / 2 - 1;    \
                    214:        (t) /= HECTONANOSECONDS;        \
                    215:        (t) *= HECTONANOSECONDS;        \
                    216:        (t) -= HECTONANOSECONDS / 2;    \
                    217: } while (0)
                    218: 
                    219: /*
                    220:  * workaround for VC6 inability to convert unsigned __int64 to double
                    221:  */
                    222: #define        LL_HNS  ((LONGLONG)HECTONANOSECONDS)
                    223: 
                    224: /*
                    225:  * NT native time format is 100's of nanoseconds since 1601-01-01.
                    226:  * Helpers for converting between "hectonanoseconds" and the 
                    227:  * performance counter scale from which interpolated time is
                    228:  * derived.
                    229:  *
                    230:  * Once support for VC6 is dropped, the cast of PerfCtrFreq to
                    231:  * LONGLONG can come out of PERF2HNS().  It avoids the VC6 error
                    232:  * message:
                    233:  * 
                    234:  * conversion from unsigned __int64 to double not implemented, use
                    235:  * signed __int64
                    236:  */
                    237: #define HNS2PERF(hns)  ((hns) * PerfCtrFreq / LL_HNS)
                    238: #define PERF2HNS(ctr)  ((ctr) * LL_HNS / (LONGLONG)PerfCtrFreq)
                    239: 
                    240: 
                    241: #if defined(_MSC_VER) && _MSC_VER >= 1400      /* VS 2005 */
                    242: #define        get_pcc()       __rdtsc()
                    243: #else
                    244: /*
                    245:  * something like this can be used for a compiler without __rdtsc()
                    246:  */
                    247: ULONGLONG __forceinline 
                    248: get_pcc(void)
                    249: {
                    250:        /* RDTSC returns in EDX:EAX, same as C compiler */
                    251:        __asm {
                    252:                RDTSC
                    253:        }
                    254: }
                    255: #endif
                    256: 
                    257: 
                    258: /*
                    259:  * perf_ctr() returns the current performance counter value, 
                    260:  * from QueryPerformanceCounter or RDTSC.
                    261:  */
                    262: ULONGLONG WINAPI 
                    263: perf_ctr(void)
                    264: {
                    265:        FT_ULL ft;
                    266: 
                    267:        if (use_pcc)
                    268:                return get_pcc();
                    269:        else {
                    270:                QueryPerformanceCounter(&ft.li);
                    271:                return ft.ull;
                    272:        }
                    273: }
                    274: 
                    275: 
                    276: /*
                    277:  * choose_interp_counter - select between QueryPerformanceCounter and
                    278:  *                        the x86 processor cycle counter (TSC).
                    279:  */
                    280: static void
                    281: choose_interp_counter(void)
                    282: {
                    283:        const char *    ntpd_pcc_freq_text;
                    284:        int             qpc_built_on_pcc;
                    285: 
                    286:        /*
                    287:         * Regardless of whether we actually use RDTSC, first determine
                    288:         * if QueryPerformanceCounter is built on it, so that we can
                    289:         * decide whether it's prudent to lock QPC-consuming threads to
                    290:         * a particular CPU.
                    291:         */
                    292:        qpc_built_on_pcc = is_qpc_built_on_pcc();
                    293:        lock_interp_threads = qpc_built_on_pcc;
                    294: 
                    295:        /*
                    296:         * It's time to make some more permanent knobs,
                    297:         * but for right now the RDTSC aka PCC dance on x86 is:
                    298:         *
                    299:         * 1.  With none of these variables defined, only QPC
                    300:         *     is used because there is no reliable way to
                    301:         *     detect counter frequency variation after ntpd
                    302:         *     startup implemented.
                    303:         * 2.  We need a better knob, but for now if you know
                    304:         *     your RDTSC / CPU frequency is invariant, set
                    305:         *     NTPD_PCC and assuming your QPC is based on the
                    306:         *     PCC as well, RDTSC will be substituted.
                    307:         * 3.  More forcefully, you can jam in a desired exact
                    308:         *     processor frequency, expressed in cycles per
                    309:         *     second by setting NTPD_PCC_FREQ=398125000, for
                    310:         *     example, if yor actual known CPU frequency is
                    311:         *     398.125 MHz, and NTPD_PCC doesn't work because
                    312:         *     QueryPerformanceCounter is implemented using
                    313:         *     another counter.  It is very easy to make ntpd
                    314:         *     fall down if the NTPD_PCC_FREQ value isn't very
                    315:         *     close to the observed RDTSC units per second.
                    316:         *
                    317:         * Items 2 and 3 could probably best be combined into one
                    318:         * new windows-specific command line switch such as
                    319:         *   ntpd --pcc
                    320:         * or
                    321:         *   ntpd --pcc=398125000
                    322:         *
                    323:         * They are currently tied to Windows because that is
                    324:         * the only ntpd port with its own interpolation, and
                    325:         * to x86/x64 because no one has ported the Windows
                    326:         * ntpd port to the sole remaining alternative, Intel
                    327:         * Itanium.
                    328:         */
                    329:        if (HAVE_OPT(PCCFREQ))
                    330:                ntpd_pcc_freq_text = OPT_ARG(PCCFREQ);
                    331:        else
                    332:                ntpd_pcc_freq_text = getenv("NTPD_PCC_FREQ");
                    333: 
                    334:        if (!HAVE_OPT(USEPCC)
                    335:            && NULL == ntpd_pcc_freq_text
                    336:            && NULL == getenv("NTPD_PCC")) {
                    337:                use_pcc = 0;
                    338:                return;
                    339:        }
                    340: 
                    341:        if (!qpc_built_on_pcc && NULL == ntpd_pcc_freq_text) {
                    342:                use_pcc = 0;
                    343:                return;
                    344:        }
                    345: 
                    346:        use_pcc = 1;
                    347:        if (ntpd_pcc_freq_text != NULL)
                    348:                sscanf(ntpd_pcc_freq_text, 
                    349:                       "%I64u", 
                    350:                       &NomPerfCtrFreq);
                    351: 
                    352:        NLOG(NLOG_CLOCKINFO)
                    353:                msyslog(LOG_INFO, 
                    354:                        "using processor cycle counter "
                    355:                        "%.3f MHz", 
                    356:                        (LONGLONG)NomPerfCtrFreq / 1e6);
                    357:        return;
                    358: }
                    359: 
                    360: 
                    361: /*
                    362:  * is_qpc_built_on_pcc - test if QueryPerformanceCounter runs at the
                    363:  *                      same rate as the processor cycle counter (TSC).
                    364:  */
                    365: static int
                    366: is_qpc_built_on_pcc(void)
                    367: {
                    368:        LONGLONG        offset;
                    369:        FT_ULL          ft1;
                    370:        FT_ULL          ft2;
                    371:        FT_ULL          ft3;
                    372:        FT_ULL          ft4;
                    373:        FT_ULL          ft5;
                    374: 
                    375:        NTP_REQUIRE(NomPerfCtrFreq != 0);
                    376: 
                    377:        QueryPerformanceCounter(&ft1.li);
                    378:        ft2.ull = get_pcc();
                    379:        Sleep(1);
                    380:        QueryPerformanceCounter(&ft3.li);
                    381:        Sleep(1);
                    382:        ft4.ull = get_pcc();
                    383:        Sleep(1);
                    384:        QueryPerformanceCounter(&ft5.li);
                    385: 
                    386:        offset = ft2.ull - ft1.ull;
                    387:        ft3.ull += offset;
                    388:        ft5.ull += offset;
                    389: 
                    390:        if (ft2.ull <= ft3.ull &&
                    391:            ft3.ull <= ft4.ull &&
                    392:            ft4.ull <= ft5.ull) {
                    393: 
                    394:                QPC_offset = offset;
                    395:                return TRUE;
                    396:        }
                    397: 
                    398:        return FALSE;
                    399: }
                    400: 
                    401: 
                    402: /*
                    403:  * Request Multimedia Timer
                    404:  */
                    405: void
                    406: set_mm_timer(
                    407:        int timerres
                    408:        )
                    409: {
                    410:        modify_mm_timer = timerres;
                    411: }
                    412: 
                    413: /*
                    414:  * adj_systime - called once every second to make system time adjustments.
                    415:  * Returns 1 if okay, 0 if trouble.
                    416:  */
                    417: int
                    418: adj_systime(
                    419:        double now
                    420:        )
                    421: {
                    422:        double dtemp;
                    423:        u_char isneg = 0;
                    424:        int rc;
                    425:        long TimeAdjustment;
                    426: 
                    427:        /*
                    428:         * Add the residual from the previous adjustment to the new
                    429:         * adjustment, bound and round.
                    430:         */
                    431:        dtemp = sys_residual + now;
                    432:        sys_residual = 0;
                    433:        if (dtemp < 0)
                    434:        {
                    435:                isneg = 1;
                    436:                dtemp = -dtemp;
                    437:        }
                    438: 
                    439:        if (dtemp > NTP_MAXFREQ)
                    440:                dtemp = NTP_MAXFREQ;
                    441: 
                    442:        dtemp = dtemp * 1e6;
                    443: 
                    444:        if (isneg)
                    445:                dtemp = -dtemp;
                    446: 
                    447:        /* 
                    448:         * dtemp is in micro seconds. NT uses 100 ns units,
                    449:         * so a unit change in TimeAdjustment corresponds
                    450:         * to slewing 10 ppm on a 100 Hz system. Calculate
                    451:         * the number of 100ns units to add, using OS tick
                    452:         * frequency as per suggestion from Harry Pyle,
                    453:         * and leave the remainder in dtemp
                    454:         */
                    455:        TimeAdjustment = (long) (dtemp / ppm_per_adjust_unit + (isneg ? -0.5 : 0.5));
                    456:        dtemp -= (double) TimeAdjustment * ppm_per_adjust_unit; 
                    457: 
                    458: 
                    459:        /*
                    460:         * If a leap second is pending then determine the UTC time stamp 
                    461:         * of when the insertion must take place 
                    462:         */
                    463:        if (leapsec > 0)
                    464:        {
                    465:                if ( ls_ft.ull == 0 )  /* time stamp has not yet been computed */
                    466:                {
                    467:                        SYSTEMTIME st;
                    468: 
                    469:                        GetSystemTime(&st);
                    470: 
                    471:                        /*
                    472:                         * Accept leap announcement only 1 month in advance,
                    473:                         * for end of March, June, September, or December.
                    474:                         */
                    475:                        if ( ( st.wMonth % 3 ) == 0 )
                    476:                        {
                    477:                                /*
                    478:                                 * The comparison time stamp is computed according 
                    479:                                 * to 0:00h UTC of the following day 
                    480:                                 */
                    481:                                if ( ++st.wMonth > 12 )
                    482:                                {
                    483:                                        st.wMonth -= 12;
                    484:                                        st.wYear++;
                    485:                                }
                    486:                                
                    487:                                st.wDay = 1;
                    488:                                st.wHour = 0;
                    489:                                st.wMinute = 0;
                    490:                                st.wSecond = 0;
                    491:                                st.wMilliseconds = 0;
                    492: 
                    493:                                SystemTimeToFileTime(&st, &ls_ft.ft);
                    494:                                msyslog(LOG_NOTICE,
                    495:                                        "Detected positive leap second announcement "
                    496:                                        "for %04d-%02d-%02d %02d:%02d:%02d UTC",
                    497:                                        st.wYear, st.wMonth, st.wDay,
                    498:                                        st.wHour, st.wMinute, st.wSecond);
                    499:                        }
                    500:                }
                    501:        }
                    502:        else
                    503:        {
                    504:                if ( ls_ft.ull )  /* Leap second has been armed before */
                    505:                {
                    506:                        /*
                    507:                         * Disarm leap second only if the leap second
                    508:                         * is not already in progress.
                    509:                         */
                    510:                        if ( !ls_time_adjustment )
                    511:                        {
                    512:                                ls_ft.ull = 0;
                    513:                                msyslog( LOG_NOTICE, "Leap second announcement disarmed" );
                    514:                        }
                    515:                }
                    516:        }
                    517: 
                    518: 
                    519:        /*
                    520:         * If the time stamp for the next leap second has been set
                    521:         * then check if the leap second must be handled
                    522:         */
                    523:        if ( ls_ft.ull )
                    524:        {
                    525:                ULONGLONG this_perf_count;
                    526: 
                    527:                this_perf_count = perf_ctr();
                    528: 
                    529:                if ( ls_time_adjustment == 0 ) /* has not yet been scheduled */
                    530:                {
                    531:                        FT_ULL curr_ft;
                    532: 
                    533:                        GetSystemTimeAsFileTime(&curr_ft.ft);   
                    534:                        if ( curr_ft.ull >= ls_ft.ull )
                    535:                        {
                    536:                                ls_time_adjustment = clockperiod / LS_CORR_INTV_SECS;
                    537:                                ls_ref_perf_cnt = this_perf_count;
                    538:                                ls_elapsed = 0;
                    539:                                msyslog(LOG_NOTICE, "Inserting positive leap second.");
                    540:                        }
                    541:                }
                    542:                else  /* leap sec adjustment has been scheduled previously */
                    543:                {
                    544:                        ls_elapsed = ( this_perf_count - ls_ref_perf_cnt ) 
                    545:                                       * HECTONANOSECONDS / PerfCtrFreq;
                    546:                }
                    547: 
                    548:                if ( ls_time_adjustment )  /* leap second adjustment is currently active */
                    549:                {
                    550:                        if ( ls_elapsed > ( LS_CORR_INTV - LS_CORR_LIMIT ) )
                    551:                        {
                    552:                                ls_time_adjustment = 0;  /* leap second adjustment done */
                    553:                                ls_ft.ull = 0;
                    554:                        }
                    555: 
                    556:                        /* 
                    557:                         * NOTE: While the system time is slewed during the leap second 
                    558:                         * the interpolation function which is based on the performance 
                    559:                         * counter does not account for the slew.
                    560:                        */
                    561:                        TimeAdjustment -= ls_time_adjustment;
                    562:                }
                    563:        }
                    564: 
                    565: 
                    566:        /* only adjust the clock if adjustment changes */
                    567:        TimeAdjustment += wintickadj;
                    568:        if (last_Adj != TimeAdjustment) {
                    569:                last_Adj = TimeAdjustment;
                    570:                DPRINTF(1, ("SetSystemTimeAdjustment(%+ld)\n", TimeAdjustment));
                    571:                rc = !SetSystemTimeAdjustment(clockperiod + TimeAdjustment, FALSE);
                    572:        }
                    573:        else rc = 0;
                    574:        if (rc)
                    575:        {
                    576:                msyslog(LOG_ERR, "Can't adjust time: %m");
                    577:                return 0;
                    578:        }
                    579:        else {
                    580:                sys_residual = dtemp / 1e6;
                    581:        }
                    582: 
                    583:        DPRINTF(6, ("adj_systime: adj %.9f -> remaining residual %.9f\n", 
                    584:                    now, sys_residual));
                    585: 
                    586:        return 1;
                    587: }
                    588: 
                    589: 
                    590: void 
                    591: init_winnt_time(void)
                    592: {
                    593:        static const char settod[] = "settimeofday=\"SetSystemTime\"";
                    594:        char szMsgPath[MAX_PATH+1];
                    595:        HANDLE hToken = INVALID_HANDLE_VALUE;
                    596:        TOKEN_PRIVILEGES tkp;
                    597:        TIMECAPS tc;
                    598:        BOOL noslew;
                    599:        DWORD adjclockperiod;
                    600:        LARGE_INTEGER Freq;
                    601:        FT_ULL initial_hectonanosecs;
                    602:        FT_ULL next_hectonanosecs;
                    603:        double adjppm;
                    604:        double rawadj;
                    605:        char * pch;
                    606: 
                    607:        if (winnt_time_initialized)
                    608:                return;
                    609: 
                    610:        /*
                    611:         * Make sure the service is initialized
                    612:         * before we do anything else
                    613:         */
                    614:        ntservice_init();
                    615: 
                    616:        /* Set up the Console Handler */
                    617:        if (!SetConsoleCtrlHandler(OnConsoleEvent, TRUE))
                    618:        {
                    619:                msyslog(LOG_ERR, "Can't set console control handler: %m");
                    620:        }
                    621: 
                    622:        /* Set the Event-ID message-file name. */
                    623:        if (!GetModuleFileName(NULL, szMsgPath, sizeof(szMsgPath))) 
                    624:        {
                    625:                msyslog(LOG_ERR, "GetModuleFileName(PGM_EXE_FILE) failed: %m\n");
                    626:                exit(1);
                    627:        }
                    628: 
                    629:        /* Initialize random file before OpenSSL checks */
                    630:        if (!init_randfile())
                    631:                msyslog(LOG_ERR, "Unable to initialize .rnd file\n");
                    632: 
                    633: #pragma warning(push)
                    634: #pragma warning(disable: 4127) /* conditional expression is constant */
                    635: 
                    636: #ifdef DEBUG
                    637:        if (SIZEOF_TIME_T != sizeof(time_t)
                    638:            || SIZEOF_INT != sizeof(int)
                    639:            || SIZEOF_SIGNED_CHAR != sizeof(char)) {
                    640:        
                    641:                msyslog(LOG_ERR, "config.h SIZEOF_* macros wrong, fatal");
                    642:                exit(1);
                    643:        }
                    644: #endif
                    645: 
                    646: #pragma warning(pop)
                    647: 
                    648:        /*
                    649:         * Get privileges needed for fiddling with the clock
                    650:         */
                    651: 
                    652:        /* get the current process token handle */
                    653:        if (!OpenProcessToken(GetCurrentProcess(),
                    654:             TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) 
                    655:        {
                    656:                msyslog(LOG_ERR, "OpenProcessToken failed: %m");
                    657:                exit(-1);
                    658:        }
                    659:        /* get the LUID for system-time privilege. */
                    660:        LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
                    661:        tkp.PrivilegeCount = 1;  /* one privilege to set */
                    662:        tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
                    663: 
                    664:        /* get set-time privilege for this process. */
                    665:        AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
                    666:                (PTOKEN_PRIVILEGES) NULL, 0);
                    667: 
                    668:        /* cannot use return value of AdjustTokenPrivileges. */
                    669:        /* (success does not indicate all privileges were set) */
                    670:        if (GetLastError() != ERROR_SUCCESS) 
                    671:        {
                    672:                msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
                    673:                /* later set time call will probably fail */
                    674:        }
                    675: 
                    676:        CloseHandle(hToken);
                    677:        hToken = INVALID_HANDLE_VALUE;
                    678: 
                    679:        /*
                    680:         * Say how we're setting the time of day
                    681:         */
                    682:        set_sys_var(settod, sizeof(settod), RO);
                    683: 
                    684:        /*
                    685:         * ntpd on Windows has always raised its priority, without
                    686:         * requiring -N as on Unix.  Since Windows ntpd doesn't share
                    687:         * the history of unix ntpd of once having no -N and therefore
                    688:         * needing to be invoked under nice, there is no reason to
                    689:         * bring it in line with the Unix version in this regard.
                    690:         * Instsrv assumes ntpd is invoked with no arguments, and
                    691:         * upgrading users would be negatively surprised by the 
                    692:         * poor timekeeping if they failed to add -N as part of 
                    693:         * upgrading were we to correct this platform difference.
                    694:         */
                    695:        if (-1 == setpriority(PRIO_PROCESS, 0, NTP_PRIO))
                    696:                exit(-1);
                    697: 
                    698:        /*
                    699:         * register with libntp ntp_set_tod() to call us back
                    700:         * when time is stepped.
                    701:         */
                    702:        step_callback = time_stepped;
                    703: 
                    704:        /* 
                    705:         * before we start looking at clock period, do any multimedia
                    706:         * timer manipulation requested via -M option.
                    707:         */
                    708:        if (modify_mm_timer) {
                    709: 
                    710:                if (timeGetDevCaps(&tc, sizeof(tc)) == TIMERR_NOERROR) {
                    711: 
                    712:                        wTimerRes = min(max(tc.wPeriodMin, MM_TIMER_INTV), tc.wPeriodMax);
                    713:                        timeBeginPeriod(wTimerRes);
                    714:                        atexit(atexit_revert_mm_timer);
                    715:                        
                    716:                        msyslog(LOG_INFO, "MM timer resolution: %u..%u msec, set to %u msec",
                    717:                                tc.wPeriodMin, tc.wPeriodMax, wTimerRes );
                    718:                } else
                    719:                        msyslog(LOG_ERR, "Multimedia timer unavailable");
                    720:        }
                    721:        
                    722:        /* get the performance counter ticks per second */
                    723:        if (!QueryPerformanceFrequency(&Freq) || !Freq.QuadPart)
                    724:        {
                    725:                msyslog(LOG_ERR, "QueryPerformanceFrequency failed: %m\n");
                    726:                exit(-1);
                    727:        }
                    728: 
                    729:        NomPerfCtrFreq = PerfCtrFreq = Freq.QuadPart;
                    730:        /*
                    731:         * the cast to LONGLONG is for VC6 compatibility:
                    732:         * nt_clockstuff.c(586) : error C2520: conversion from
                    733:         * unsigned __int64 to double not implemented, use signed 
                    734:         * __int64
                    735:         */
                    736:        msyslog(LOG_INFO, 
                    737:                "Performance counter frequency %.3f MHz", 
                    738:                (LONGLONG)PerfCtrFreq / 1e6);
                    739: 
                    740:        /* Determine the existing system time slewing */
                    741:        if (!GetSystemTimeAdjustment(&adjclockperiod, &clockperiod, &noslew))
                    742:        {
                    743:                msyslog(LOG_ERR, "GetSystemTimeAdjustment failed: %m\n");
                    744:                exit(-1);
                    745:        }
                    746: 
                    747:        /*
                    748:         * If there is no slewing before ntpd, adjclockperiod and clockperiod
                    749:         * will be equal.  Any difference is carried into adj_systime's first
                    750:         * pass as the previous adjustment.
                    751:         */
                    752:        last_Adj = adjclockperiod - clockperiod;
                    753:        
                    754:        if (last_Adj)
                    755:                msyslog(LOG_INFO, 
                    756:                        "Clock interrupt period %.3f msec "
                    757:                        "(startup slew %.1f usec/period)",
                    758:                        clockperiod / 1e4,
                    759:                        last_Adj / 10.);
                    760:        else
                    761:                msyslog(LOG_INFO, 
                    762:                        "Clock interrupt period %.3f msec", 
                    763:                        clockperiod / 1e4);
                    764: 
                    765:        /*
                    766:         * Calculate the time adjustment resulting from incrementing
                    767:         * units per tick by 1 unit for 1 second 
                    768:         */
                    769:        ppm_per_adjust_unit = 1e6 / clockperiod;
                    770: 
                    771:        /*
                    772:         * Spin on GetSystemTimeAsFileTime to determine its
                    773:         * granularity.  Prior to Windows Vista this is 
                    774:         * typically the same as the clock period.
                    775:         */
                    776:        GetSystemTimeAsFileTime(&initial_hectonanosecs.ft);
                    777:        do {
                    778:                GetSystemTimeAsFileTime(&next_hectonanosecs.ft);
                    779:        } while (initial_hectonanosecs.ull == next_hectonanosecs.ull);
                    780: 
                    781:        os_clock_precision = next_hectonanosecs.ull -
                    782:                initial_hectonanosecs.ull;
                    783: 
                    784:        msyslog(LOG_INFO,
                    785:                "Windows clock precision %.3f msec, min. slew %.3f ppm/s",
                    786:                (LONGLONG)os_clock_precision / 1e4, 
                    787:                ppm_per_adjust_unit);
                    788: 
                    789:        pch = getenv("NTPD_TICKADJ_PPM");
                    790:        if (pch != NULL && 1 == sscanf(pch, "%lf", &adjppm)) {
                    791:                rawadj = adjppm / ppm_per_adjust_unit;
                    792:                rawadj += (rawadj < 0)
                    793:                              ? -0.5
                    794:                              : 0.5;
                    795:                wintickadj = (long)rawadj;
                    796:                msyslog(LOG_INFO,
                    797:                        "Using NTPD_TICKADJ_PPM %+g ppm (%+ld)",
                    798:                        adjppm, wintickadj);
                    799:        }
                    800: 
                    801:        winnt_time_initialized = TRUE;
                    802: 
                    803:        choose_interp_counter();
                    804: 
                    805:        if (getenv("NTPD_USE_SYSTEM_CLOCK") ||
                    806:            (os_clock_precision < 4 * 10000 &&
                    807:             !getenv("NTPD_USE_INTERP_DANGEROUS"))) {
                    808:                msyslog(LOG_INFO, "using Windows clock directly");
                    809:        } else {
                    810:                winnt_use_interpolation = TRUE;
                    811:                get_sys_time_as_filetime = GetInterpTimeAsFileTime;
                    812:                StartClockThread();
                    813:        }
                    814: }
                    815: 
                    816: 
                    817: void
                    818: atexit_revert_mm_timer(void)
                    819: {
                    820:        timeEndPeriod(wTimerRes); 
                    821:        DPRINTF(1, ("MM timer resolution reset\n"));
                    822: }
                    823: 
                    824: 
                    825: void 
                    826: reset_winnt_time(void)
                    827: {
                    828:        SYSTEMTIME st;
                    829: 
                    830:        /*
                    831:         * If we're in the 2-second slew right after a leap second, 
                    832:         * we don't want to continue that extreme slew, in that case
                    833:         * disable our slewing and return clock discipline to the 
                    834:         * kernel.  Similarly if we are not yet synchronized, 
                    835:         * our current slew may not be a good ongoing trim.
                    836:         * Otherwise, our leave in place the last SetSystemTimeAdjustment
                    837:         * as an ongoing frequency correction, better than nothing.
                    838:         * TODO:
                    839:         * Verify this will not call SetSystemTimeAdjustment if
                    840:         * ntpd is running in ntpdate mode.
                    841:         */
                    842:        if (sys_leap == LEAP_NOTINSYNC || ls_time_adjustment)
                    843:                SetSystemTimeAdjustment(0, TRUE);        
                    844: 
                    845:        /*
                    846:         * Read the current system time, and write it back to
                    847:         * force CMOS update, only if we are exiting because
                    848:         * the computer is shutting down and we are already
                    849:         * synchronized.
                    850:         */
                    851:         if (ntservice_systemisshuttingdown() && sys_leap != LEAP_NOTINSYNC) {
                    852:                GetSystemTime(&st);
                    853:                SetSystemTime(&st);
                    854:                NLOG(NLOG_SYSEVENT | NLOG_CLOCKINFO)
                    855:                        msyslog(LOG_NOTICE, "system is shutting down, CMOS time reset.");
                    856:        }
                    857: }
                    858: 
                    859: 
                    860: /*
                    861:  * GetSystemTimeAsFileTime() interface clone is used by getclock() in ntpd.
                    862:  */
                    863: 
                    864: void WINAPI 
                    865: GetInterpTimeAsFileTime(
                    866:        LPFILETIME pft
                    867:        )
                    868: {
                    869:        FT_ULL now_time;
                    870:        FT_ULL now_count;
                    871: 
                    872:        /*  Mark a mark ASAP. The latency to here should
                    873:         *  be reasonably deterministic
                    874:        */
                    875: 
                    876:        now_count.ull = perf_ctr();
                    877:        now_time.ull = interp_time(now_count.ull, TRUE);
                    878: 
                    879:        if (last_interp_time > now_time.ull) {
                    880: 
                    881:                clock_backward_count++;
                    882:                if (last_interp_time - now_time.ull > clock_backward_max)
                    883:                        clock_backward_max = last_interp_time - now_time.ull;
                    884:                now_time.ull = last_interp_time;
                    885:        } else
                    886:                last_interp_time = now_time.ull;
                    887: 
                    888:        *pft = now_time.ft;
                    889:        return;
                    890: }
                    891: 
                    892: 
                    893: /*
                    894:  * TimerApcFunction is invoked on the high-priority clock
                    895:  * thread to capture a new  baseline system time and
                    896:  * performance counter correlation every 43 msec (64Hz 
                    897:  * OS clock precision).
                    898:  */
                    899: static void CALLBACK
                    900: TimerApcFunction(
                    901:        LPVOID lpArgToCompletionRoutine,
                    902:        DWORD dwTimerLowValue,
                    903:        DWORD dwTimerHighValue
                    904:        )
                    905: {
                    906:        static BOOL             ctr_freq_timer_started = FALSE;
                    907:        static ULONGLONG        prev_count;
                    908:        ULONGLONG               now_time;
                    909:        FT_ULL                  now_count;
                    910: 
                    911:        /* Grab the counter first of all */
                    912:        now_count.ull = perf_ctr();
                    913: 
                    914:        now_time = (((ULONGLONG)dwTimerHighValue << 32) |
                    915:                                dwTimerLowValue);
                    916: 
                    917:        /*
                    918:         * Save this correlation in the history.
                    919:         */
                    920:        add_counter_time_pair(now_count.ull, now_time);
                    921: 
                    922:        /*
                    923:         * Once we're synchronized start the counter frequency
                    924:         * tuning timer.
                    925:         */
                    926:        if (INVALID_HANDLE_VALUE == ctr_freq_timer &&
                    927:            LEAP_NOTINSYNC != sys_leap)
                    928: 
                    929:                start_ctr_freq_timer(now_time);
                    930: }
                    931: 
                    932: 
                    933: unsigned WINAPI 
                    934: ClockThread(
                    935:        void *arg
                    936:        )
                    937: {
                    938:        LARGE_INTEGER   DueTime;
                    939:        HANDLE          timer;
                    940:        double          HZ;
                    941:        double          TimerHz;
                    942:        DWORD           timer_period_msec;
                    943:        DWORD           res;
                    944:        char            *ntpd_int_int_text;
                    945: 
                    946:        UNUSED_ARG(arg);
                    947: 
                    948:        timer = CreateWaitableTimer(NULL, FALSE, NULL);
                    949: 
                    950:        ntpd_int_int_text = getenv("NTPD_INT_INT");
                    951: 
                    952:        HZ = (double)HECTONANOSECONDS / clockperiod;
                    953: 
                    954:        if (HZ > 63 && HZ < 65) {
                    955:                timer_period_msec = 43;
                    956:        } else if (HZ > 98 && HZ < 102) {
                    957:                timer_period_msec = 27;
                    958:                if (!ntpd_int_int_text)
                    959:                        msyslog(LOG_WARNING, 
                    960:                                "%.3f Hz system clock may benefit from "
                    961:                                "custom NTPD_INT_INT env var timer interval "
                    962:                                "override between approx. 20 and 50 msecs.",
                    963:                                HZ);
                    964:        } else {
                    965:                timer_period_msec = (DWORD)(0.5 + (2.752 * clockperiod / 10000));
                    966:                if (!ntpd_int_int_text)
                    967:                        msyslog(LOG_WARNING, 
                    968:                                "unfamiliar %.3f Hz system clock may benefit "
                    969:                                "from custom NTPD_INT_INT env var timer "
                    970:                                "interval override between approx. 20 and 50 "
                    971:                                "msecs.",
                    972:                                HZ);
                    973:        }
                    974: 
                    975:        if (ntpd_int_int_text) {
                    976:                timer_period_msec = atoi(ntpd_int_int_text);
                    977:                timer_period_msec = max(9, timer_period_msec);
                    978:                msyslog(LOG_NOTICE, 
                    979:                        "using NTPD_INT_INT env var override %u", 
                    980:                        timer_period_msec);
                    981:        }
                    982: 
                    983:        TimerHz = 1e3 / timer_period_msec;
                    984:        msyslog(LOG_NOTICE, "HZ %.3f using %u msec timer %.3f Hz %d deep", 
                    985:                HZ,
                    986:                timer_period_msec,
                    987:                TimerHz,
                    988:                BASELINES_USED);
                    989: 
                    990:        /* negative DueTime means relative to now */
                    991:        DueTime.QuadPart = -(int)timer_period_msec;
                    992: 
                    993:        SetWaitableTimer(
                    994:                timer, 
                    995:                &DueTime,               /* first fire */
                    996:                timer_period_msec,      /* period thereafter */
                    997:                TimerApcFunction,       /* callback routine */
                    998:                &timer,                 /* context for callback */
                    999:                FALSE);                 /* do not interfere with power saving */
                   1000: 
                   1001:        /*
                   1002:         * The clock thread spends the rest of its life in the TimerApcFunction
                   1003:         * and ctr_freq_timer_fired timer APC callbacks, which can only occur 
                   1004:         * while this thread is in an alertable wait.  Note the Ex on 
                   1005:         * WaitForSingleObjectEx and TRUE for fAlertable.  The wait will return 
                   1006:         * after each APC callback in which case we simply wait again.  We will
                   1007:         * break out of the loop when StopClockThread signals our exit event.
                   1008:         */
                   1009:        do res = WaitForSingleObjectEx(
                   1010:                        TimerThreadExitRequest, 
                   1011:                        INFINITE, 
                   1012:                        TRUE);
                   1013:        while (WAIT_OBJECT_0 != res);
                   1014: 
                   1015:        CloseHandle(timer);
                   1016: 
                   1017:        if (ctr_freq_timer != INVALID_HANDLE_VALUE) {
                   1018:                CloseHandle(ctr_freq_timer);
                   1019:                ctr_freq_timer = INVALID_HANDLE_VALUE;
                   1020:        }
                   1021: 
                   1022:        return 0;
                   1023: }
                   1024: 
                   1025: 
                   1026: static void 
                   1027: StartClockThread(void)
                   1028: {
                   1029:        static BOOL done_once = FALSE;
                   1030:        FT_ULL StartTime;
                   1031: 
                   1032:        /* init variables with the time now */
                   1033:        GetSystemTimeAsFileTime(&StartTime.ft);
                   1034:        baseline_times[0] = StartTime.ull;
                   1035:        baseline_counts[0] = perf_ctr();
                   1036: 
                   1037:        /* init sync objects */
                   1038:        TimerThreadExitRequest = CreateEvent(NULL, FALSE, FALSE, NULL);
                   1039: 
                   1040:        clock_thread = 
                   1041:                (HANDLE)_beginthreadex(
                   1042:                        NULL, 
                   1043:                        0, 
                   1044:                        ClockThread, 
                   1045:                        NULL, 
                   1046:                        CREATE_SUSPENDED, 
                   1047:                        &clock_thread_id);
                   1048: 
                   1049:        if (clock_thread != NULL) {
                   1050:                /* remember the thread priority is only within the process class */
                   1051:                if (!SetThreadPriority(clock_thread, THREAD_PRIORITY_TIME_CRITICAL)) {
                   1052:                        DPRINTF(1, ("Error setting thread priority\n"));
                   1053:                }
                   1054: 
                   1055:                lock_thread_to_processor(clock_thread);
                   1056:                ResumeThread(clock_thread);
                   1057: 
                   1058:                if (FALSE == done_once) {
                   1059:                        done_once = TRUE;
                   1060:                        lock_thread_to_processor(GetCurrentThread());
                   1061:                        atexit( StopClockThread );
                   1062:                }
                   1063: 
                   1064:                /*
                   1065:                 * Give the clock thread time to fill its counter/time
                   1066:                 * sample buffer.  This will underfill the buffer a
                   1067:                 * bit for sample periods over 43 msec.
                   1068:                 */
                   1069:                Sleep(BASELINES_USED * 43);
                   1070:        }
                   1071: }
                   1072: 
                   1073: 
                   1074: void 
                   1075: StopClockThread(void)
                   1076: {
                   1077:        /*
                   1078:         * if the clock thread exit()s this routine
                   1079:         * will be called on the clock thread and
                   1080:         * we need not (and can't) use the normal
                   1081:         * TimerThreadExitRequest event.
                   1082:         */
                   1083:        if (GetCurrentThreadId() != clock_thread_id) {
                   1084: 
                   1085:                if (!SetEvent(TimerThreadExitRequest) ||
                   1086:                    WaitForSingleObject(clock_thread, 2 * 1000) != 
                   1087:                    WAIT_OBJECT_0) {
                   1088:                        msyslog(LOG_ERR, "Failed to stop clock thread.");
                   1089:                }
                   1090:        }
                   1091:        CloseHandle(TimerThreadExitRequest);
                   1092:        TimerThreadExitRequest = NULL;
                   1093:        CloseHandle(clock_thread);
                   1094:        clock_thread = NULL;
                   1095: }
                   1096: 
                   1097: 
                   1098: void
                   1099: lock_thread_to_processor(HANDLE thread)
                   1100: {
                   1101:        static  DWORD_PTR       ProcessAffinityMask;
                   1102:        static  DWORD_PTR       ThreadAffinityMask;
                   1103:        DWORD_PTR               SystemAffinityMask;
                   1104:        char                    *cputext;
                   1105:        unsigned int            cpu;
                   1106: 
                   1107:        if ( ! winnt_time_initialized) {
                   1108:                DPRINTF(1, ("init_winnt_time() must be called before "
                   1109:                                "lock_thread_to_processor(), exiting\n"));
                   1110:                exit(-1);
                   1111:        }
                   1112: 
                   1113:        if ( ! winnt_use_interpolation)
                   1114:                return;
                   1115:        
                   1116:        if (-1 == lock_interp_threads) {
                   1117:                DPRINTF(1, ("choose_interp_counter() is not called "
                   1118:                            "before lock_thread_to_processor()\n"));
                   1119:                exit(-1);
                   1120:        } else if (!lock_interp_threads)
                   1121:                return;
                   1122: 
                   1123:        /*
                   1124:         * Calculate the ThreadAffinityMask we'll use once on the
                   1125:         * first invocation.
                   1126:         */
                   1127:        if ( ! ProcessAffinityMask) {
                   1128: 
                   1129:                /*
                   1130:                 * Choose which processor to nail the main and clock threads to.
                   1131:                 * If we have more than one, we simply choose the 2nd.
                   1132:                 * Randomly choosing from 2 to n would be better, but in
                   1133:                 * either case with clock and network interrupts more likely
                   1134:                 * to be serviced by the first procecssor, let's stay away 
                   1135:                 * from it.  QueryPerformanceCounter is not necessarily
                   1136:                 * consistent across CPUs, hence the need to nail the two
                   1137:                 * threads involved in QPC-based interpolation to the same
                   1138:                 * CPU.
                   1139:                 */
                   1140: 
                   1141:                GetProcessAffinityMask(
                   1142:                        GetCurrentProcess(), 
                   1143:                        &ProcessAffinityMask,
                   1144:                        &SystemAffinityMask);
                   1145: 
                   1146:                /*
                   1147:                 * respect NTPD_CPU environment variable if present
                   1148:                 * for testing.  NTPD_CPU=0 means use all CPUs, 1-64
                   1149:                 * means lock threads involved in interpolation to
                   1150:                 * that CPU.  Default to 2nd if more than 1.
                   1151:                 */
                   1152: 
                   1153:                cpu = 2;
                   1154:                cputext = getenv("NTPD_CPU");
                   1155:                if (cputext) {
                   1156:                        cpu = (unsigned int) atoi(cputext);
                   1157:                        cpu = min((8 * sizeof(DWORD_PTR)), cpu);
                   1158:                }
                   1159: 
                   1160:                /* 
                   1161:                 * Clear all bits except the 2nd.  If we have only one proc
                   1162:                 * that leaves ThreadAffinityMask zeroed and we won't bother
                   1163:                 * with SetThreadAffinityMask.
                   1164:                 */
                   1165: 
                   1166:                ThreadAffinityMask = (0 == cpu) ? 0 : (1 << (cpu - 1));
                   1167: 
                   1168:                if (ThreadAffinityMask && 
                   1169:                        !(ThreadAffinityMask & ProcessAffinityMask)) 
                   1170: 
                   1171:                        DPRINTF(1, ("Selected CPU %u (mask %x) is outside "
                   1172:                                        "process mask %x, using all CPUs.\n",
                   1173:                                        cpu, ThreadAffinityMask, 
                   1174:                                        ProcessAffinityMask));
                   1175:                else
                   1176:                        DPRINTF(1, ("Wiring to processor %u (0 means all) "
                   1177:                                        "affinity mask %x\n",   
                   1178:                                        cpu, ThreadAffinityMask));
                   1179: 
                   1180:                ThreadAffinityMask &= ProcessAffinityMask;
                   1181:        }
                   1182: 
                   1183:        if (ThreadAffinityMask && 
                   1184:            !SetThreadAffinityMask(thread, ThreadAffinityMask))
                   1185: 
                   1186:                msyslog(LOG_ERR, 
                   1187:                        "Unable to wire thread to mask %x: %m\n", 
                   1188:                        ThreadAffinityMask);
                   1189: }
                   1190: 
                   1191: 
                   1192: #ifdef HAVE_PPSAPI
                   1193: /*
                   1194:  * helper routine for serial PPS which returns QueryPerformanceCounter
                   1195:  * timestamp and needs to interpolate it to an NTP timestamp.
                   1196:  */
                   1197: void 
                   1198: pps_ntp_timestamp_from_counter(
                   1199:        ntp_fp_t        *result, 
                   1200:        ULONGLONG       Timestamp, 
                   1201:        ULONGLONG       Counterstamp
                   1202:        )
                   1203: {
                   1204:        /*
                   1205:         * convert between equivalent l_fp and PPSAPI ntp_fp_t
                   1206:         */
                   1207:        ntp_timestamp_from_counter(
                   1208:                (l_fp *)result,
                   1209:                Timestamp,
                   1210:                Counterstamp);
                   1211: }
                   1212: 
                   1213: 
                   1214: void 
                   1215: ntp_timestamp_from_counter(
                   1216:        l_fp *result, 
                   1217:        ULONGLONG Timestamp, 
                   1218:        ULONGLONG Counterstamp
                   1219:        )
                   1220: {
                   1221: #ifdef DEBUG
                   1222:        FT_ULL          Now;
                   1223: #endif
                   1224:        ULONGLONG       InterpTimestamp;
                   1225: 
                   1226:        if (winnt_use_interpolation) {
                   1227:                InterpTimestamp = interp_time(Counterstamp + QPC_offset, FALSE);
                   1228: 
                   1229: #ifdef DEBUG
                   1230:                /* sanity check timestamp is within 1 minute of now */
                   1231:                GetSystemTimeAsFileTime(&Now.ft);
                   1232:                Now.ll -= InterpTimestamp;
                   1233:                if (debug &&
                   1234:                    Now.ll > 60 * HECTONANOSECONDS || 
                   1235:                    Now.ll < -60 * (LONGLONG) HECTONANOSECONDS) {
                   1236:                        DPRINTF(1, ("ntp_timestamp_from_counter interpolated time %.6fs from current\n",
                   1237:                                        Now.ll / (double)LL_HNS));
                   1238:                        DPRINTF(1, ("interpol time %llx from  %llx\n",
                   1239:                                        InterpTimestamp,
                   1240:                                        Counterstamp));
                   1241:                        msyslog(LOG_ERR,
                   1242:                                "ntp_timestamp_from_counter interpolated time %.6fs from current\n",
                   1243:                                Now.ll / (double)LL_HNS);
                   1244:                        exit(-1);
                   1245:                }
                   1246: #endif
                   1247:        } else {  /* ! winnt_use_interpolation */
                   1248:                /* have to simply use the driver's system time timestamp */
                   1249:                InterpTimestamp = Timestamp;
                   1250: #ifdef DEBUG
                   1251:                /* sanity check timestamp is within 1 minute of now */
                   1252:                GetSystemTimeAsFileTime(&Now.ft);
                   1253:                Now.ll -= InterpTimestamp;
                   1254:                if (Now.ll > 60 * HECTONANOSECONDS || 
                   1255:                    Now.ll < -60 * (LONGLONG) HECTONANOSECONDS) {
                   1256:                        DPRINTF(1, ("ntp_timestamp_from_counter serial driver system time %.6fs from current\n",
                   1257:                                    Now.ll / (double)LL_HNS));
                   1258:                        msyslog(LOG_ERR,
                   1259:                                "ntp_timestamp_from_counter serial driver system time %.6fs from current\n",
                   1260:                                Now.ll / (double)LL_HNS);
                   1261:                        exit(-1);
                   1262:                }
                   1263: #endif
                   1264:        }
                   1265: 
                   1266:        /* convert from 100ns units to NTP fixed point format */
                   1267: 
                   1268:        InterpTimestamp -= FILETIME_1970;
                   1269:        result->l_ui = JAN_1970 + (u_int32)(InterpTimestamp / HECTONANOSECONDS);
                   1270:        result->l_uf = (u_int32)((InterpTimestamp % HECTONANOSECONDS) *
                   1271:                                 (ULONGLONG)FRAC / HECTONANOSECONDS);
                   1272: }
                   1273: #endif  /* HAVE_PPSAPI */
                   1274: 
                   1275: 
                   1276: void 
                   1277: time_stepped(void)
                   1278: {
                   1279:        /*
                   1280:         * called back by ntp_set_tod after the system
                   1281:         * time has been stepped (set).
                   1282:         *
                   1283:         * We normally prevent the reported time from going backwards
                   1284:         * but need to allow it in this case.
                   1285:         */
                   1286:        if (FALSE == winnt_use_interpolation)
                   1287:                return;
                   1288: 
                   1289: 
                   1290:        /*
                   1291:         * Restart the clock thread to get a new baseline
                   1292:         * time/counter correlation.
                   1293:         */
                   1294:        StopClockThread();
                   1295: 
                   1296:        /*
                   1297:         * newest_baseline_gen is a generation counter
                   1298:         * incremented once each time newest_baseline
                   1299:         * is reset.
                   1300:         */
                   1301:        newest_baseline_gen++;
                   1302: 
                   1303:        last_interp_time = 
                   1304:                clock_backward_max = 
                   1305:                clock_backward_count = 
                   1306:                newest_baseline = 0;
                   1307: 
                   1308:        memset(baseline_counts, 0, sizeof(baseline_counts));
                   1309:        memset(baseline_times, 0, sizeof(baseline_times));
                   1310: 
                   1311:        StartClockThread();
                   1312: }
                   1313: 
                   1314: 
                   1315: /*
                   1316:  * log2ull - log base 2 of a unsigned 64-bit number
                   1317:  */
                   1318: int 
                   1319: log2ull(
                   1320:        ULONGLONG n
                   1321:        )
                   1322: {
                   1323:        const ULONGLONG one = 1;
                   1324:        int log = 0;
                   1325: 
                   1326:        if (n >= one<<32) { n >>= 32; log += 32; }
                   1327:        if (n >= one<<16) { n >>= 16; log += 16; }
                   1328:        if (n >= one<< 8) { n >>=  8; log +=  8; }
                   1329:        if (n >= one<< 4) { n >>=  4; log +=  4; }
                   1330:        if (n >= one<< 2) { n >>=  2; log +=  2; }
                   1331:        if (n >= one<< 1) {           log +=  1; }
                   1332: 
                   1333:        return (n) ? log : (-1);
                   1334: }
                   1335: 
                   1336: 
                   1337: /*
                   1338:  * ctr_freq_timer_fired is called once a few seconds before
                   1339:  * tune_ctr_period seconds have elapsed, to reset the timer
                   1340:  * and hopefully minimize error due to the system using the
                   1341:  * nominal performance counter frequency to set the timer
                   1342:  * internally, which is typically dozens of PPM from the
                   1343:  * actual performance counter rate.  A few seconds later
                   1344:  * it is called again to observe the counter and estimate the
                   1345:  * counter frequency.
                   1346:  */
                   1347: static void CALLBACK
                   1348: ctr_freq_timer_fired(
                   1349:        LPVOID arg,
                   1350:        DWORD dwTimeLow,
                   1351:        DWORD dwTimeHigh
                   1352:        )
                   1353: {
                   1354:        static  FT_ULL          begin_time = {0};
                   1355:        static  FT_ULL          begin_count = {0};
                   1356:        static  ULONGLONG       next_period_time = 0;
                   1357:        static  ULONGLONG       report_systemtime = 0;
                   1358:        const   ULONGLONG       five_minutes = 5ui64 * 60 * HECTONANOSECONDS;
                   1359:        FT_ULL                  now_time;
                   1360:        FT_ULL                  now_count;
                   1361: 
                   1362:        if (!begin_time.ull) {
                   1363:                begin_count.ull = perf_ctr();
                   1364:                begin_time.ft.dwLowDateTime = dwTimeLow;
                   1365:                begin_time.ft.dwHighDateTime = dwTimeHigh;
                   1366: 
                   1367:                /*
                   1368:                 * adapt perf ctr observation interval to the
                   1369:                 * counter frequency
                   1370:                 */
                   1371:                tune_ctr_period = 22680 / log2ull(NomPerfCtrFreq);
                   1372: 
                   1373:                /*
                   1374:                 * reset timer 2s before period ends to minimize
                   1375:                 * error from OS timer routines using nominal 
                   1376:                 * performance frequency internally.
                   1377:                 */
                   1378:                tune_ctr_freq_max_interval = tune_ctr_period - 2;
                   1379: 
                   1380:                next_period_time = begin_time.ull + 
                   1381:                        (ULONGLONG)tune_ctr_period * HECTONANOSECONDS;
                   1382: 
                   1383:                ROUND_TO_NEXT_SEC_BOTTOM(next_period_time);
                   1384: 
                   1385:                reset_ctr_freq_timer(next_period_time, begin_time.ull);
                   1386: 
                   1387:                return;
                   1388:        }
                   1389: 
                   1390:        now_time.ft.dwLowDateTime = dwTimeLow;
                   1391:        now_time.ft.dwHighDateTime = dwTimeHigh;
                   1392: 
                   1393:        if (now_time.ull >= next_period_time) {
                   1394: 
                   1395:                now_count.ull = perf_ctr();
                   1396:                tune_ctr_freq(
                   1397:                        now_count.ull - begin_count.ull,
                   1398:                        now_time.ull - begin_time.ull);
                   1399: 
                   1400:                next_period_time += (ULONGLONG)tune_ctr_period * HECTONANOSECONDS;
                   1401:                begin_count.ull = now_count.ull;
                   1402:                begin_time.ull = now_time.ull;
                   1403:        }
                   1404: 
                   1405:        /* 
                   1406:         * Log clock backward events no more often than 5 minutes.
                   1407:         */
                   1408:        if (!report_systemtime) 
                   1409: 
                   1410:                report_systemtime = now_time.ull + five_minutes;
                   1411: 
                   1412:        else if (report_systemtime <= now_time.ull) {
                   1413: 
                   1414:                report_systemtime +=  five_minutes;
                   1415: 
                   1416:                if (clock_backward_count) {
                   1417:                        msyslog(LOG_WARNING, 
                   1418:                                "clock would have gone backward %d times, "
                   1419:                                "max %.1f usec",
                   1420:                                clock_backward_count, 
                   1421:                                (LONGLONG)clock_backward_max / 10.);
                   1422: 
                   1423:                        clock_backward_max = clock_backward_count = 0;
                   1424:                }
                   1425:        }
                   1426: 
                   1427:        reset_ctr_freq_timer(next_period_time, now_time.ull);
                   1428: }
                   1429: 
                   1430: 
                   1431: void
                   1432: reset_ctr_freq_timer_abs(
                   1433:        ULONGLONG when
                   1434:        )
                   1435: {
                   1436:        FT_ULL  fire_time;
                   1437: 
                   1438:        fire_time.ull = when; 
                   1439: 
                   1440:        SetWaitableTimer(
                   1441:                ctr_freq_timer,
                   1442:                &fire_time.li,          /* first fire */
                   1443:                0,                      /* not periodic */
                   1444:                ctr_freq_timer_fired,   /* callback routine */
                   1445:                NULL,                   /* context for callback */
                   1446:                FALSE);                 /* do not interfere with power saving */
                   1447: }
                   1448: 
                   1449: 
                   1450: void
                   1451: reset_ctr_freq_timer(
                   1452:        ULONGLONG when,
                   1453:        ULONGLONG now
                   1454:        )
                   1455: {
                   1456:        if (when - now > 
                   1457:            (tune_ctr_freq_max_interval * HECTONANOSECONDS + HECTONANOSECONDS))
                   1458: 
                   1459:                when = now + tune_ctr_freq_max_interval * HECTONANOSECONDS;
                   1460: 
                   1461:        reset_ctr_freq_timer_abs(when);
                   1462: }
                   1463: 
                   1464: 
                   1465: void
                   1466: start_ctr_freq_timer(
                   1467:        ULONGLONG now_time
                   1468:        )
                   1469: {
                   1470:        ULONGLONG when;
                   1471: 
                   1472:        ctr_freq_timer = CreateWaitableTimer(NULL, FALSE, NULL);
                   1473: 
                   1474:        when = now_time;
                   1475:        ROUND_TO_NEXT_SEC_BOTTOM(when);
                   1476: 
                   1477:        reset_ctr_freq_timer_abs(when);
                   1478: }
                   1479: 
                   1480: 
                   1481: /*
                   1482:  * tune_ctr_freq is called once per tune_ctr_period seconds
                   1483:  * with a counter difference and time difference.
                   1484:  */
                   1485: void 
                   1486: tune_ctr_freq(
                   1487:        LONGLONG ctr_delta,
                   1488:        LONGLONG time_delta
                   1489:        )
                   1490: {
                   1491:        static unsigned count = 0;
                   1492:        static unsigned dispcount = 0;
                   1493:        static unsigned report_at_count = 0;
                   1494:        static int disbelieved = 0;
                   1495:        static int i = 0;
                   1496:        static double nom_freq = 0;
                   1497:        static LONGLONG diffs[TUNE_CTR_DEPTH] = {0};
                   1498:        static LONGLONG sum = 0;
                   1499: 
                   1500:        LONGLONG delta;
                   1501:        LONGLONG deltadiff;
                   1502:        ULONGLONG ObsPerfCtrFreq;
                   1503:        double obs_freq;
                   1504:        double this_freq;
                   1505:        int isneg;
                   1506: 
                   1507:        /* one-time initialization */
                   1508:        if (!report_at_count) {
                   1509:                report_at_count = 24 * 60 * 60 / tune_ctr_period;
                   1510:                nom_freq = (LONGLONG)NomPerfCtrFreq / 1e6;
                   1511:        }
                   1512: 
                   1513:        /* delta is the per-second observed frequency this time */
                   1514:        delta = (LONGLONG)((double)ctr_delta * HECTONANOSECONDS /
                   1515:                           time_delta);
                   1516: 
                   1517:        /* disbelieve any delta more than +/- 976 PPM from nominal */
                   1518:        deltadiff = delta - NomPerfCtrFreq;
                   1519:        if (0 > deltadiff) {
                   1520:                isneg = 1;
                   1521:                deltadiff = -deltadiff;
                   1522:        } else
                   1523:                isneg = 0;
                   1524: 
                   1525:        if ((ULONGLONG)deltadiff > (NomPerfCtrFreq / 1024)) {
                   1526:                disbelieved++;
                   1527:                dispcount++;
                   1528: #ifdef DEBUG
                   1529:                msyslog(LOG_DEBUG, "ctr delta %s%lld exceeds limit %llu",
                   1530:                                   (isneg) ? "-" : "",
                   1531:                                   deltadiff,
                   1532:                                   NomPerfCtrFreq / 1024);
                   1533: #endif
                   1534:        } else {
                   1535: 
                   1536:                /*
                   1537:                 * collect average over TUNE_CTR_DEPTH samples
                   1538:                 * for our PerfCtrFreq trimming.
                   1539:                 */
                   1540: 
                   1541:                if (isneg)
                   1542:                        deltadiff = -deltadiff;
                   1543:                sum -= diffs[i];
                   1544:                diffs[i] = deltadiff;
                   1545:                sum += deltadiff;
                   1546:                i = (i + 1) % COUNTOF(diffs);
                   1547:                count++;
                   1548:                dispcount++;
                   1549:        }
                   1550: 
                   1551:        this_freq = delta / 1e6;
                   1552: 
                   1553:        ObsPerfCtrFreq = NomPerfCtrFreq + (sum / COUNTOF(diffs));
                   1554: 
                   1555: #if 1  /* #if 0 to disable changing freq used */
                   1556:        /* get rid of ObsPerfCtrFreq when removing the #ifdef */
                   1557:        PerfCtrFreq = ObsPerfCtrFreq;
                   1558: #endif
                   1559:        obs_freq = (LONGLONG)ObsPerfCtrFreq / 1e6;
                   1560: 
                   1561:        /* 
                   1562:         * report observed ctr freq each time the estimate used during
                   1563:         * startup moves toward the observed freq from the nominal, 
                   1564:         * and once a day afterward.
                   1565:         */
                   1566: 
                   1567:        if (count > COUNTOF(diffs) &&
                   1568:            /* (count % COUNTOF(diffs)) && */   /* enables reporting each */
                   1569:            dispcount < report_at_count)        /* TUNE_CTR_DEPTH samples */
                   1570:                return;
                   1571: 
                   1572:        NLOG(NLOG_CLOCKINFO)
                   1573:                if (count <= COUNTOF(diffs))
                   1574:                        /* moving to observed freq. from nominal (startup) */
                   1575:                        msyslog(LOG_INFO,
                   1576:                                (obs_freq > 100)
                   1577:                                 ? "ctr %.3f MHz %+6.2f PPM using "
                   1578:                                       "%.3f MHz %+6.2f PPM"
                   1579:                                 : "ctr %.6f MHz %+6.2f PPM using "
                   1580:                                       "%.6f MHz %+6.2f PPM",
                   1581:                                this_freq,
                   1582:                                1e6 * (this_freq - nom_freq) / nom_freq,
                   1583:                                obs_freq, 
                   1584:                                1e6 * (obs_freq - nom_freq) / nom_freq);
                   1585:                else
                   1586:                        /* steady state */
                   1587:                        msyslog(LOG_INFO,
                   1588:                                (obs_freq > 100)
                   1589:                                 ? "ctr %.3f MHz %+.2f PPM"
                   1590:                                 : "ctr %.6f MHz %+.2f PPM",
                   1591:                                obs_freq, 
                   1592:                                1e6 * (obs_freq - nom_freq) / nom_freq);
                   1593: 
                   1594:        if (disbelieved) {
                   1595:                msyslog(LOG_ERR, 
                   1596:                        "%d ctr samples exceed +/- 976 PPM range gate",
                   1597:                        disbelieved);
                   1598:                disbelieved = 0;
                   1599:        }
                   1600: 
                   1601:        dispcount = 0;
                   1602: }
                   1603: 
                   1604: 
                   1605: /*
                   1606:  * add_counter_time_pair is called by the
                   1607:  * high priority clock thread with each new
                   1608:  * baseline counter/time correlation.
                   1609:  */
                   1610: void
                   1611: add_counter_time_pair(
                   1612:        ULONGLONG ctr,
                   1613:        LONGLONG time
                   1614:        )
                   1615: {
                   1616:        int i;
                   1617: 
                   1618:        i = (newest_baseline + 1) % BASELINES_TOT;
                   1619: 
                   1620:        baseline_counts[i] = ctr;
                   1621:        baseline_times[i] = time;
                   1622: 
                   1623:        newest_baseline = i;
                   1624: }
                   1625: 
                   1626: 
                   1627: /*
                   1628:  * interp_time estimates NT time in 100ns units
                   1629:  * based on a performance counter value given.
                   1630:  * This must tolerate recent historical counters
                   1631:  * as well as current.  When current is FALSE
                   1632:  * we can't assume ctr is the latest/highest
                   1633:  * seen.
                   1634:  */
                   1635: ULONGLONG
                   1636: interp_time(
                   1637:        ULONGLONG ctr,
                   1638:        BOOL current
                   1639:        )
                   1640: {
                   1641:        static __declspec(thread) int           last_newest = -1;
                   1642:        static __declspec(thread) int           last_newest_gen;
                   1643:        static __declspec(thread) int           best_index;
                   1644:        ULONGLONG       this_ctr;
                   1645:        LONGLONG        this_time;
                   1646:        LONGLONG        latest_time;
                   1647:        LONGLONG        ctr_diff;
                   1648:        int             i;
                   1649:        int             i_gen;
                   1650:        int             c;
                   1651: 
                   1652:        /*
                   1653:         * Use the system time (roughly synchronised to the tick, and
                   1654:         * extrapolated using the system performance counter.
                   1655:         *
                   1656:         * Cache the results per thread and only repeat the
                   1657:         * calculation when new data has arrived.
                   1658:         */
                   1659:        i = newest_baseline;
                   1660:        i_gen = newest_baseline_gen;
                   1661: 
                   1662:        if (last_newest == i && last_newest_gen == i_gen) {
                   1663:                this_time = baseline_times[best_index];
                   1664:                ctr_diff = ctr - baseline_counts[best_index];
                   1665:                this_time += (LONGLONG)PERF2HNS((double)ctr_diff);
                   1666: 
                   1667:                return this_time;
                   1668:        }
                   1669: 
                   1670:        last_newest = i;
                   1671:        last_newest_gen = i_gen;
                   1672: 
                   1673:        latest_time = 0;
                   1674: 
                   1675:        /*
                   1676:         * Run through the history calculating the interpolated 
                   1677:         * time based on each counter/time correlation in turn,
                   1678:         * and believe the latest one.  This is akin to the NTP
                   1679:         * protocol minimum delay clock filter.  Errors due to 
                   1680:         * counter/time correlations with stale time are all 
                   1681:         * negative.
                   1682:         */
                   1683:        for (c = 0; c < BASELINES_USED; c++) {
                   1684:                 if (baseline_times[i]) {
                   1685:                        this_time = baseline_times[i];
                   1686:                        this_ctr = baseline_counts[i];
                   1687: 
                   1688:                        ctr_diff = ctr - this_ctr;
                   1689: 
                   1690:                        if (current && ctr_diff < 0) {
                   1691:                                /* 
                   1692:                                 * The performance counter apparently went 
                   1693:                                 * backwards without rolling over.  It might 
                   1694:                                 * be nice to complain but we don't want 
                   1695:                                 * to do it repeatedly.
                   1696:                                 */
                   1697:                                ctr_diff = 0;
                   1698:                        }
                   1699: 
                   1700:                        this_time += (LONGLONG)PERF2HNS((double)ctr_diff);
                   1701: 
                   1702:                        if (this_time > latest_time) {
                   1703:                                latest_time = this_time;
                   1704:                                best_index = i;
                   1705:                        }
                   1706:                }
                   1707:                i = i ? (i - 1) : (BASELINES_TOT - 1);
                   1708:        }
                   1709: 
                   1710:        return latest_time;
                   1711: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>