#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "ntp_stdlib.h"
#include "clockstuff.h"
#include "ntp_timer.h"
extern double sys_residual;
static long last_Adj = 0;
static CRITICAL_SECTION TimerCritialSection;
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;
int
adj_systime(
double now
)
{
double dtemp;
u_char isneg = 0;
int rc;
long dwTimeAdjustment;
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;
dwTimeAdjustment = (DWORD)( dtemp / ppm_per_adjust_unit + (isneg ? -0.5 : 0.5)) ;
dtemp += (double) -dwTimeAdjustment * ppm_per_adjust_unit;
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;
TOKEN_PRIVILEGES tkp;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
msyslog(LOG_ERR, "OpenProcessToken failed: %m");
exit(-1);
}
LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES) NULL, 0);
if (GetLastError() != ERROR_SUCCESS)
{
msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
}
if (!GetSystemTimeAdjustment(&initial_units_per_tick, &every,&noslew))
{
msyslog(LOG_ERR, "GetSystemTimeAdjustment failed: %m\n");
exit (-1);
}
units_per_tick = initial_units_per_tick;
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
SetThreadAffinityMask(GetCurrentThread(), 1L);
}
void reset_winnt_time(void) {
if (!SetSystemTimeAdjustment(0, TRUE)) {
msyslog(LOG_ERR, "Failed to reset clock state, SetSystemTimeAdjustment(): %m");
}
{
SYSTEMTIME st;
GetSystemTime(&st);
SetSystemTime(&st);
}
}
int
gettimeofday(
struct timeval *tv
)
{
ULONGLONG Count;
LARGE_INTEGER LargeIntNowCount;
ULONGLONG Time;
ULONGLONG NowCount;
ULONGLONG PreCount;
LONGLONG TicksElapsed;
LONG time_adjustment;
PreCount = LastTimerCount;
if (!QueryPerformanceCounter(&LargeIntNowCount)) {
msyslog(LOG_ERR, "QueryPeformanceCounter failed: %m");
exit(1);
}
NowCount = LargeIntNowCount.QuadPart;
EnterCriticalSection(&TimerCritialSection);
Count = LastTimerCount;
Time = LastTimerTime;
LeaveCriticalSection(&TimerCritialSection);
if (NowCount >= Count)
{
TicksElapsed = NowCount - Count;
}
else
{
if (Count > PreCount)
{
TicksElapsed = 0;
}
else
{
TicksElapsed = NowCount + (RollOverCount - Count);
}
}
time_adjustment = (long) ((TicksElapsed * HECTONANOSECONDS) / PerfFrequency);
Time += time_adjustment;
Time -= FILETIME_1970;
tv->tv_sec = (LONG) ( Time / 10000000ui64);
tv->tv_usec = (LONG) (( Time % 10000000ui64) / 10);
return 0;
}
static void CALLBACK
TimerApcFunction(
LPVOID lpArgToCompletionRoutine,
DWORD dwTimerLowValue,
DWORD dwTimerHighValue
)
{
LARGE_INTEGER LargeIntNowCount;
(void) lpArgToCompletionRoutine;
if (dwTimerLowValue == lastLowTimer) return;
QueryPerformanceCounter(&LargeIntNowCount);
lastLowTimer = dwTimerLowValue;
if ((ULONGLONG) LargeIntNowCount.QuadPart < LastTimerCount) {
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
}
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;
if (WaitableTimerHandle != NULL) {
DueTime.QuadPart = 0i64;
if (SetWaitableTimer(WaitableTimerHandle, &DueTime, 1L , TimerApcFunction, &WaitableTimerHandle, FALSE) != NO_ERROR) {
for(;;) {
if (WaitForSingleObjectEx(TimerThreadExitRequest, INFINITE, TRUE) == WAIT_OBJECT_0) {
break;
}
}
}
CloseHandle(WaitableTimerHandle);
WaitableTimerHandle = NULL;
}
return 0;
}
static void StartClockThread(void)
{
DWORD tid;
FILETIME StartTime;
LARGE_INTEGER Freq = { 0, 0 };
if (!QueryPerformanceFrequency(&Freq)) {
msyslog(LOG_ERR, "QueryPerformanceFrequency failed: %m\n");
exit (-1);
}
PerfFrequency = Freq.QuadPart;
GetSystemTimeAsFileTime(&StartTime);
LastTimerTime = (((ULONGLONG) StartTime.dwHighDateTime) << 32) +
(ULONGLONG) StartTime.dwLowDateTime;
InitializeCriticalSection(&TimerCritialSection);
TimerThreadExitRequest = CreateEvent(NULL, FALSE, FALSE, NULL);
ClockThreadHandle = CreateThread(NULL, 0, ClockThread, NULL, 0, &tid);
if (ClockThreadHandle != NULL) {
if (!SetThreadPriority(ClockThreadHandle, THREAD_PRIORITY_TIME_CRITICAL)) {
#ifdef DEBUG
printf("Error setting thread priority\n");
#endif
}
}
}
static void StopClockThread(void)
{
if (SetEvent(TimerThreadExitRequest) &&
WaitForSingleObject(ClockThreadHandle, 10000L) == 0) {
CloseHandle(TimerThreadExitRequest);
TimerThreadExitRequest = NULL;
CloseHandle(ClockThreadHandle);
ClockThreadHandle = NULL;
DeleteCriticalSection(&TimerCritialSection);
msyslog(LOG_INFO, "The Network Time Protocol Service has stopped.");
}
else
msyslog(LOG_ERR, "Network Time Protocol Service Failed to Stop");
}
typedef void (__cdecl *CRuntimeFunction)(void);
#pragma data_seg(".CRT$XIY")
CRuntimeFunction _StartClockThread = StartClockThread;
#pragma data_seg(".CRT$XTY")
CRuntimeFunction _StopClockThread = StopClockThread;
#pragma data_seg()