📄 nt_clockstuff.c
字号:
/* Windows NT Clock Routines * * * Revision History: * $Log$ * Revision 1.9 2000/11/19 09:02:12 dietrich * From: Ron Thornton [rthornto@pictel.com] * Sent: Thu 11/16/00 8:51 AM * On Windows 2000 it requires a privilege on the current process token * that is disabled by default on Windows 2000. * * I set the token by adding the following code at the beginning of the * init_winnt_time() function in nt_clockstuff.c. * * Revision 1.8 2000/11/19 08:03:20 dietrich * From: "Colin Dancer" <colin.dancer@pyrochrome.net> * To: <bugs@ntp.org> * Sent: 10 November 2000 12:59 * Subject: NT bug in NTP 4.0.99j * * I've found a bug in (and produced a fix for) the NT clock interpolation * code in NTP 4.0.99j. * * The symptoms of the problem are that gettimeofday() function on NT * can be wrong by hundreds of seconds if, while a gettimeofday() call * is being processed, an APC completes after the query of the performance * counter but before the lock is grabbed. The most obvious fix is to move * the lock to include the querying of the performance counter, but this * could affect the predictability of the timestamp so I have instead * tweaked the code to detect and sidestep the duff calculation. * * I've also found that on a loaded system the execution of the APC can be * delayed, leading to errors of upto 10ms. There is no easy fix to this, * but I do have code for an alternative interpolation scheme which avoids * the problem on single processor systems. I'm currently integrating this * along with code for deciding which algorithm to use based on whether * the system is SP or MP. * * Created by Sven Dietrich sven@inter-yacht.com * */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "ntp_stdlib.h"#include "clockstuff.h"#include "ntservice.h"#include "ntp_timer.h"#include "ntpd.h"/* * Include code to possibly modify the MM timer while the service is active. */ /* * Whether or not MM timer modifications takes place is still controlled * by the variable below which is initialized by a default value but * might be changed depending on a command line switch. */ int modify_mm_timer = MM_TIMER_LORES; #define MM_TIMER_INTV 1 /* the interval we'd want to set the MM timer to [ms] */ static UINT wTimerRes; static TIMECAPS tc;extern double sys_residual; /* residual from previous adjustment */char szMsgPath[255];BOOL init_randfile();static long last_Adj = 0;#define LS_CORR_INTV_SECS 2 /* seconds to apply leap second correction */#define LS_CORR_INTV ( (LONGLONG) HECTONANOSECONDS * LS_CORR_INTV_SECS ) #define LS_CORR_LIMIT ( (LONGLONG) HECTONANOSECONDS / 2 ) // half a secondtypedef union{ FILETIME ft; ULONGLONG ull;} FT_ULL;static FT_ULL ls_ft;static DWORD ls_time_adjustment;static LARGE_INTEGER ls_ref_perf_cnt;static LONGLONG ls_elapsed;static void StartClockThread(void);static void StopClockThread(void);static CRITICAL_SECTION TimerCritialSection; /* lock for LastTimerCount & LastTimerTime */static ULONGLONG RollOverCount = 0;static ULONGLONG LastTimerCount = 0;static ULONGLONG LastTimerTime = 0;static HANDLE ClockThreadHandle = NULL;static HANDLE TimerThreadExitRequest = NULL;static DWORD every = 0;static DWORD initial_units_per_tick = 0;static DWORD lastLowTimer = 0;ULONGLONG PerfFrequency = 0;static DWORD units_per_tick = 0;static DOUBLE ppm_per_adjust_unit = 0.0;/* * Request Multimedia Timer */voidset_mm_timer(int timerres){ modify_mm_timer = timerres;}/* * adj_systime - called once every second to make system time adjustments. * Returns 1 if okay, 0 if trouble. */intadj_systime( double now ){ double dtemp; u_char isneg = 0; int rc; long dwTimeAdjustment; /* * Add the residual from the previous adjustment to the new * adjustment, bound and round. */ dtemp = sys_residual + now; sys_residual = 0; if (dtemp < 0) { isneg = 1; dtemp = -dtemp; } if (dtemp > NTP_MAXFREQ) dtemp = NTP_MAXFREQ; dtemp = dtemp * 1e6; if (isneg) dtemp = -dtemp; /* dtemp is in micro seconds. NT uses 100 ns units, * so a unit change in dwTimeAdjustment corresponds * to slewing 10 ppm on a 100 Hz system. * Calculate the number of 100ns units to add, * using OS tick frequency as per suggestion from Harry Pyle, * and leave the remainder in dtemp */ dwTimeAdjustment = (DWORD)( dtemp / ppm_per_adjust_unit + (isneg ? -0.5 : 0.5)) ; dtemp += (double) -dwTimeAdjustment * ppm_per_adjust_unit; /* If a leap second is pending then determine the UTC time stamp * of when the insertion must take place */ if (leap_next & LEAP_ADDSECOND) { if ( ls_ft.ull == 0 ) /* time stamp has not yet been computed */ { FT_ULL ft; SYSTEMTIME st; int itmp; GetSystemTimeAsFileTime(&ft.ft); FileTimeToSystemTime(&ft.ft, &st); /* Accept leap announcement only 1 month in advance, * for end of March, June, September, or December. */ if ( ( st.wMonth % 3 ) == 0 ) { /* The comarison time stamp is computed according * to 0:00h UTC of the following day */ if ( ++st.wMonth > 12 ) { st.wMonth -= 12; st.wYear++; } st.wDay = 1; st.wHour = 0; st.wMinute = 0; st.wSecond = 0; st.wMilliseconds = 0; SystemTimeToFileTime(&st, &ls_ft.ft); msyslog(LOG_INFO, "Detected positive leap second announcement " "for %04d-%02d-%02d %02d:%02d:%02d UTC", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); } } } /* If the time stamp for the next leap second has been set * then check if the leap second must be handled */ if ( ls_ft.ull ) { LARGE_INTEGER this_perf_count; QueryPerformanceCounter( &this_perf_count ); if ( ls_time_adjustment == 0 ) /* has not yet been scheduled */ { FT_ULL curr_ft; GetSystemTimeAsFileTime(&curr_ft.ft); if ( curr_ft.ull >= ls_ft.ull ) { ls_time_adjustment = every / LS_CORR_INTV_SECS; ls_ref_perf_cnt = this_perf_count; ls_elapsed = 0; msyslog(LOG_INFO, "Inserting positive leap second."); } } else /* leap sec adjustment has been scheduled previously */ { ls_elapsed = ( this_perf_count.QuadPart - ls_ref_perf_cnt.QuadPart ) * HECTONANOSECONDS / PerfFrequency; } if ( ls_time_adjustment ) /* leap second adjustment is currently active */ { if ( ls_elapsed > ( LS_CORR_INTV - LS_CORR_LIMIT ) ) { ls_time_adjustment = 0; /* leap second adjustment done */ ls_ft.ull = 0; } /* NOTE: While the system time is slewed during the leap second * the interpolation function which is based on the performance * counter does not account for the slew. */ dwTimeAdjustment -= ls_time_adjustment; } } /* only adjust the clock if adjustment changes */ if (last_Adj != dwTimeAdjustment) { last_Adj = dwTimeAdjustment;# ifdef DEBUG if (debug > 1) printf("SetSystemTimeAdjustment( %ld) + (%ld)\n", dwTimeAdjustment, units_per_tick); # endif dwTimeAdjustment += units_per_tick; rc = !SetSystemTimeAdjustment(dwTimeAdjustment, FALSE); } else rc = 0; if (rc) { msyslog(LOG_ERR, "Can't adjust time: %m"); return 0; } else { sys_residual = dtemp / 1000000.0; }#ifdef DEBUG if (debug > 6) printf("adj_systime: adj %.9f -> remaining residual %.9f\n", now, sys_residual);#endif return 1;}void init_winnt_time(void){ BOOL noslew; HANDLE hToken = INVALID_HANDLE_VALUE; TOKEN_PRIVILEGES tkp; /* * Make sure the service is initialized * before we do anything else */ ntservice_init(); /* Set the Event-ID message-file name. */ if (!GetModuleFileName(NULL, szMsgPath, sizeof(szMsgPath))) { msyslog(LOG_ERR, "GetModuleFileName(PGM_EXE_FILE) failed: %m\n"); exit(1); } /* Initialize random file before OpenSSL checks */ if(!init_randfile()) msyslog(LOG_ERR, "Unable to initialize .rnd file\n"); /* * Get privileges needed for fiddling with the clock */ /* get the current process token handle */ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { msyslog(LOG_ERR, "OpenProcessToken failed: %m"); exit(-1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -