static void TIME_ClockTimeToFileTime(clock_t unix_time, LPFILETIME filetime) { ULONGLONG secs = RtlEnlargedUnsignedMultiply( unix_time, 10000000 ); secs = RtlExtendedLargeIntegerDivide( secs, CLK_TCK, NULL ); filetime->dwLowDateTime = (DWORD)secs; filetime->dwHighDateTime = (DWORD)(secs >> 32); }
DWORD TimeInMicroSeconds( DWORD dwTime ) { DWORD Remainder; return RtlExtendedLargeIntegerDivide( RtlEnlargedUnsignedMultiply( dwTime, 1000000L), Frequency, &Remainder ).LowPart; }
VOID KiCalibrateTimeAdjustment ( PADJUST_INTERRUPT_TIME_CONTEXT Adjust ) /*++ Routine Description: This function calibrates the adjustment of time on all processors. Arguments: Adjust - Supplies the operation context. Return Value: None. --*/ { ULONG cl; ULONG divisor; BOOLEAN Enable; LARGE_INTEGER InterruptTime; ULARGE_INTEGER li; PERFINFO_PO_CALIBRATED_PERFCOUNTER LogEntry; LARGE_INTEGER NewTickCount; ULONG NewTickOffset; LARGE_INTEGER PerfCount; LARGE_INTEGER PerfFreq; LARGE_INTEGER SetTime; // // As each processor arrives, decrement the remaining processor count. If // this is the last processor to arrive, then compute the time change, and // signal all processor when to apply the performance counter change. // if (InterlockedDecrement((PLONG)&Adjust->KiNumber)) { Enable = KeDisableInterrupts(); // // It is possible to deadlock if one or more of the other processors // receives and processes a freeze request while this processor has // interrupts disabled. Poll for a freeze request until all processors // are known to be in this code. // do { KiPollFreezeExecution(); } while (Adjust->KiNumber != (ULONG)-1); // // Wait to perform the time set. // while (Adjust->Barrier); } else { // // Set timer expiration dpc to scan the timer queues once for any // expired timers. // KeRemoveQueueDpc(&KiTimerExpireDpc); KeInsertQueueDpc(&KiTimerExpireDpc, ULongToPtr(KiQueryLowTickCount() - TIMER_TABLE_SIZE), NULL); // // Disable interrupts and indicate that this processor is now // in final portion of this code. // Enable = KeDisableInterrupts(); InterlockedDecrement((PLONG) &Adjust->KiNumber); // // Adjust Interrupt Time. // InterruptTime.QuadPart = KeQueryInterruptTime() + Adjust->Adjustment; SetTime.QuadPart = Adjust->Adjustment; // // Get the current times // PerfCount = KeQueryPerformanceCounter(&PerfFreq); // // Compute performance counter for current time. // // Multiply SetTime * PerfCount and obtain 96-bit result in cl, // li.LowPart, li.HighPart. Then divide the 96-bit result by // 10,000,000 to get new performance counter value. // li.QuadPart = RtlEnlargedUnsignedMultiply((ULONG)SetTime.LowPart, (ULONG)PerfFreq.LowPart).QuadPart; cl = li.LowPart; li.QuadPart = li.HighPart + RtlEnlargedUnsignedMultiply((ULONG)SetTime.LowPart, (ULONG)PerfFreq.HighPart).QuadPart; li.QuadPart = li.QuadPart + RtlEnlargedUnsignedMultiply((ULONG)SetTime.HighPart, (ULONG)PerfFreq.LowPart).QuadPart; li.HighPart = li.HighPart + SetTime.HighPart * PerfFreq.HighPart; divisor = 10000000; Adjust->NewCount.HighPart = RtlEnlargedUnsignedDivide(li, divisor, &li.HighPart); li.LowPart = cl; Adjust->NewCount.LowPart = RtlEnlargedUnsignedDivide(li, divisor, NULL); Adjust->NewCount.QuadPart += PerfCount.QuadPart; // // Compute tick count and tick offset for current interrupt time. // NewTickCount = RtlExtendedLargeIntegerDivide(InterruptTime, KeMaximumIncrement, &NewTickOffset); // // Apply changes to interrupt time, tick count, tick offset, and the // performance counter. // KiTickOffset = KeMaximumIncrement - NewTickOffset; KeInterruptTimeBias += Adjust->Adjustment; SharedUserData->TickCount.High2Time = NewTickCount.HighPart; #if defined(_WIN64) SharedUserData->TickCountQuad = NewTickCount.QuadPart; #else SharedUserData->TickCount.LowPart = NewTickCount.LowPart; SharedUserData->TickCount.High1Time = NewTickCount.HighPart; #endif // // N.B. There is no global tick count variable on AMD64. // #if defined(_X86_) KeTickCount.High2Time = NewTickCount.HighPart; KeTickCount.LowPart = NewTickCount.LowPart; KeTickCount.High1Time = NewTickCount.HighPart; #endif #if defined(_AMD64_) SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart; *((volatile ULONG64 *)&SharedUserData->InterruptTime) = InterruptTime.QuadPart; #else SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart; SharedUserData->InterruptTime.LowPart = InterruptTime.LowPart; SharedUserData->InterruptTime.High1Time = InterruptTime.HighPart; #endif // // Apply the performance counter change. // Adjust->Barrier = 0; } KeGetCurrentPrcb()->TickOffset = KiTickOffset; #if defined(_AMD64_) KeGetCurrentPrcb()->MasterOffset = KiTickOffset; #endif HalCalibratePerformanceCounter((LONG volatile *)&Adjust->HalNumber, (ULONGLONG)Adjust->NewCount.QuadPart); // // Log an event that the performance counter has been calibrated // properly and indicate the new performance counter value. // if (PERFINFO_IS_GROUP_ON(PERF_POWER)) { LogEntry.PerformanceCounter = KeQueryPerformanceCounter(NULL); PerfInfoLogBytes(PERFINFO_LOG_TYPE_PO_CALIBRATED_PERFCOUNTER, &LogEntry, sizeof(LogEntry)); } KeEnableInterrupts(Enable); return; }
/********************************************************************* * TIME_ClockTimeToFileTime ([email protected], 20-Sep-1998) * * Used by GetProcessTimes to convert clock_t into FILETIME. * * Differences to UnixTimeToFileTime: * 1) Divided by CLK_TCK * 2) Time is relative. There is no 'starting date', so there is * no need in offset correction, like in UnixTimeToFileTime */ static void TIME_ClockTimeToFileTime(clock_t unix_time, LPFILETIME filetime) { LONGLONG secs = RtlEnlargedUnsignedMultiply( unix_time, 10000000 ); ((LARGE_INTEGER *)filetime)->QuadPart = RtlExtendedLargeIntegerDivide( secs, sysconf( _SC_CLK_TCK ), NULL ); }