📄 nt_clockstuff.c
字号:
} /* get the LUID for system-time privilege. */ LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid); tkp.PrivilegeCount = 1; /* one privilege to set */ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; /* get set-time privilege for this process. */ AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0); /* cannot use return value of AdjustTokenPrivileges. */ /* (success does not indicate all privileges were set) */ if (GetLastError() != ERROR_SUCCESS) { msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m"); /* later set time call will probably fail */ } /* Reset the Clock to a reasonable increment */ if (!GetSystemTimeAdjustment(&initial_units_per_tick, &every,&noslew)) { msyslog(LOG_ERR, "GetSystemTimeAdjustment failed: %m\n"); exit(-1); } units_per_tick = initial_units_per_tick; /* Calculate the time adjustment resulting from incrementing * units per tick by 1 unit for 1 second */ ppm_per_adjust_unit = 1000000.0 / (double) every;#ifdef DEBUG msyslog(LOG_INFO, "Initial Clock increment %7.1f us", (float) (units_per_tick / 10)); msyslog(LOG_INFO, "Adjustment rate %5.3f ppm/s", ppm_per_adjust_unit);#endif StartClockThread(); /* Set up the Console Handler */ if (!SetConsoleCtrlHandler(OnConsoleEvent, TRUE)) { msyslog(LOG_ERR, "Can't set console control handler: %m"); }}void reset_winnt_time(void){ /* restore the clock frequency back to its original value */ if (!SetSystemTimeAdjustment(0, TRUE)) { msyslog(LOG_ERR, "Failed to reset clock state, SetSystemTimeAdjustment(): %m"); } /* read the current system time, and write it back to force CMOS update: */ /************ Added back in 2003-01-26 *****************/ { SYSTEMTIME st; GetSystemTime(&st); SetSystemTime(&st); }}intgettimeofday( struct timeval *tv ){ /* Use the system time (roughly synchronised to the tick, and * extrapolated using the system performance counter. */ ULONGLONG Count; LARGE_INTEGER LargeIntNowCount; ULONGLONG Time; ULONGLONG NowCount; ULONGLONG PreCount; /*FIX*/ LONGLONG TicksElapsed; LONG time_adjustment; /* Mark a mark ASAP. The latency to here should * be reasonably deterministic */ PreCount = LastTimerCount; /*FIX*/ if (!QueryPerformanceCounter(&LargeIntNowCount)) { msyslog(LOG_ERR, "QueryPeformanceCounter failed: %m"); exit(1); } NowCount = LargeIntNowCount.QuadPart; /* Get base time we are going to extrapolate from */ EnterCriticalSection(&TimerCritialSection); Count = LastTimerCount; Time = LastTimerTime; LeaveCriticalSection(&TimerCritialSection); /* Calculate when now is. * * Result = LastTimerTime + (NowCount - LastTimerCount) / PerfFrequency */ if (NowCount >= Count) { TicksElapsed = NowCount - Count; /* linear progression of ticks */ } else { /************************************************************************/ /* Differentiate between real rollover and the case of taking a */ /* perfcount then the APC coming in. */ /************************************************************************/ if (Count > PreCount) /*FIX*/ { /*FIX*/ TicksElapsed = 0; /*FIX*/ } /*FIX*/ else /*FIX*/ { /*FIX*/ TicksElapsed = NowCount + (RollOverCount - Count); /*FIX*/ } /*FIX*/ } /* Calculate the new time (in 100's of nano-seconds) */ time_adjustment = (long) ((TicksElapsed * HECTONANOSECONDS) / PerfFrequency); Time += time_adjustment; /* Convert the hecto-nano second time to tv format */ Time -= FILETIME_1970; tv->tv_sec = (LONG) ( Time / 10000000ui64); tv->tv_usec = (LONG) (( Time % 10000000ui64) / 10); return 0;}static void CALLBACKTimerApcFunction( LPVOID lpArgToCompletionRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue ){ LARGE_INTEGER LargeIntNowCount; (void) lpArgToCompletionRoutine; /* not used */ if (dwTimerLowValue == lastLowTimer) return; /* Grab the counter first of all */ QueryPerformanceCounter(&LargeIntNowCount); /* Save this for next time */ lastLowTimer = dwTimerLowValue; /* Check to see if the counter has rolled. This happens more often on Multi-CPU systems */ if ((ULONGLONG) LargeIntNowCount.QuadPart < LastTimerCount) { /* Counter Rolled - try and estimate the rollover point using the nominal counter frequency divided by an estimate of the OS frequency */ RollOverCount = LastTimerCount + PerfFrequency * every / HECTONANOSECONDS - (ULONGLONG) LargeIntNowCount.QuadPart;#ifdef DEBUG msyslog(LOG_INFO, "Performance Counter Rollover %I64u:\rLast Timer Count %I64u\rCurrent Count %I64u", RollOverCount, LastTimerCount, LargeIntNowCount.QuadPart);#endif } /* Now we can hang out and wait for the critical section to free up; we will get the CPU this timeslice. Meanwhile other tasks can use the last value of LastTimerCount */ EnterCriticalSection(&TimerCritialSection); LastTimerCount = (ULONGLONG) LargeIntNowCount.QuadPart; LastTimerTime = ((ULONGLONG) dwTimerHighValue << 32) + (ULONGLONG) dwTimerLowValue; LeaveCriticalSection(&TimerCritialSection);}DWORD WINAPI ClockThread(void *arg){ LARGE_INTEGER DueTime; HANDLE WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL); (void) arg; /* not used */ /*++++ Gerhard Junker * see Platform SDK for QueryPerformanceCounter * On a multiprocessor machine, it should not matter which processor is called. * However, you can get different results on different processors due to bugs in the BIOS or the HAL. * To specify processor affinity for a thread, use the SetThreadAffinityMask function. * ... we will hope, the apc routine will run on the same processor */ SetThreadAffinityMask(GetCurrentThread(), 1L); /*---- Gerhard Junker */ if (WaitableTimerHandle != NULL) { DueTime.QuadPart = 0i64; if (SetWaitableTimer(WaitableTimerHandle, &DueTime, 1L /* ms */, TimerApcFunction, &WaitableTimerHandle, FALSE) != NO_ERROR) { for(;;) { if (WaitForSingleObjectEx(TimerThreadExitRequest, INFINITE, TRUE) == WAIT_OBJECT_0) { break; /* we've been asked to exit */ } } } CloseHandle(WaitableTimerHandle); WaitableTimerHandle = NULL; } return 0;}static void StartClockThread(void){ DWORD tid; FILETIME StartTime; LARGE_INTEGER Freq = { 0, 0 }; /* get the performance counter freq */ if (!QueryPerformanceFrequency(&Freq)) { msyslog(LOG_ERR, "QueryPerformanceFrequency failed: %m\n"); exit (-1); } PerfFrequency = Freq.QuadPart; if ( modify_mm_timer != 0) { if (timeGetDevCaps( &tc, sizeof( tc ) ) == TIMERR_NOERROR ) { wTimerRes = min( max( tc.wPeriodMin, MM_TIMER_INTV ), tc.wPeriodMax ); timeBeginPeriod( wTimerRes );#ifdef DEBUG msyslog( LOG_INFO, "MM timer resolution: %u..%u ms, set to %u ms\n", tc.wPeriodMin, tc.wPeriodMax, wTimerRes );#endif } else msyslog( LOG_ERR, "Failed to get MM timer caps\n" ); } /* init variables with the time now */ GetSystemTimeAsFileTime(&StartTime); LastTimerTime = (((ULONGLONG) StartTime.dwHighDateTime) << 32) + (ULONGLONG) StartTime.dwLowDateTime; /* init sync objects */ InitializeCriticalSection(&TimerCritialSection); TimerThreadExitRequest = CreateEvent(NULL, FALSE, FALSE, "TimerThreadExitRequest"); ClockThreadHandle = CreateThread(NULL, 0, ClockThread, NULL, 0, &tid); if (ClockThreadHandle != NULL) { /* remember the thread priority is only within the process class */ if (!SetThreadPriority(ClockThreadHandle, THREAD_PRIORITY_TIME_CRITICAL)) {#ifdef DEBUG printf("Error setting thread priority\n");#endif } } atexit( StopClockThread );}static void StopClockThread(void){ if ( wTimerRes ) /* if not 0 then the MM timer has been modified at startup */ { timeEndPeriod( wTimerRes ); wTimerRes = 0;#ifdef DEBUG msyslog( LOG_INFO, "MM timer set to default\n" );#endif } if (SetEvent(TimerThreadExitRequest) && WaitForSingleObject(ClockThreadHandle, 10000L) == 0) { CloseHandle(TimerThreadExitRequest); TimerThreadExitRequest = NULL; CloseHandle(ClockThreadHandle); ClockThreadHandle = NULL; DeleteCriticalSection(&TimerCritialSection); } else { msyslog(LOG_ERR, "Failed to stop clock thread."); Sleep( 100 ); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -