Annotation of embedaddon/ntp/ports/winnt/ntpd/nt_clockstuff.c, revision 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>