reactos/ntoskrnl/ke/clock.c

240 lines
6.4 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ke/clock.c
* PURPOSE: System Clock Support
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
LARGE_INTEGER KeBootTime;
ULONGLONG KeBootTimeBias;
volatile KSYSTEM_TIME KeTickCount = { 0, 0, 0 };
ULONG KeMaximumIncrement;
ULONG KeMinimumIncrement;
ULONG KeTimeIncrement;
/* PRIVATE FUNCTIONS *********************************************************/
VOID
NTAPI
KeSetSystemTime(IN PLARGE_INTEGER NewTime,
OUT PLARGE_INTEGER OldTime,
IN BOOLEAN FixInterruptTime,
IN PLARGE_INTEGER HalTime OPTIONAL)
{
TIME_FIELDS TimeFields;
KIRQL OldIrql, OldIrql2;
LARGE_INTEGER DeltaTime;
PLIST_ENTRY ListHead, NextEntry;
PKTIMER Timer;
PKSPIN_LOCK_QUEUE LockQueue;
LIST_ENTRY TempList, TempList2;
ULONG Hand, i;
/* Sanity checks */
ASSERT((NewTime->HighPart & 0xF0000000) == 0);
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
/* Check if this is for the HAL */
if (HalTime) RtlTimeToTimeFields(HalTime, &TimeFields);
/* Set affinity to this CPU, lock the dispatcher, and raise IRQL */
KeSetSystemAffinityThread(1);
OldIrql = KiAcquireDispatcherLock();
KeRaiseIrql(HIGH_LEVEL, &OldIrql2);
/* Query the system time now */
KeQuerySystemTime(OldTime);
/* Set the new system time (ordering of these operations is critical) */
SharedUserData->SystemTime.High2Time = NewTime->HighPart;
SharedUserData->SystemTime.LowPart = NewTime->LowPart;
SharedUserData->SystemTime.High1Time = NewTime->HighPart;
/* Check if this was for the HAL and set the RTC time */
if (HalTime) ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields);
/* Calculate the difference between the new and the old time */
DeltaTime.QuadPart = NewTime->QuadPart - OldTime->QuadPart;
/* Update system boot time */
KeBootTime.QuadPart += DeltaTime.QuadPart;
KeBootTimeBias = KeBootTimeBias + DeltaTime.QuadPart;
/* Lower IRQL back */
KeLowerIrql(OldIrql2);
/* Check if we need to adjust interrupt time */
if (FixInterruptTime) ASSERT(FALSE);
/* Setup a temporary list of absolute timers */
InitializeListHead(&TempList);
/* Loop current timers */
for (i = 0; i < TIMER_TABLE_SIZE; i++)
{
/* Loop the entries in this table and lock the timers */
ListHead = &KiTimerTableListHead[i].Entry;
LockQueue = KiAcquireTimerLock(i);
NextEntry = ListHead->Flink;
while (NextEntry != ListHead)
{
/* Get the timer */
Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
NextEntry = NextEntry->Flink;
/* Is it absolute? */
if (Timer->Header.Absolute)
{
/* Remove it from the timer list */
KiRemoveEntryTimer(Timer);
/* Insert it into our temporary list */
InsertTailList(&TempList, &Timer->TimerListEntry);
}
}
/* Release the lock */
KiReleaseTimerLock(LockQueue);
}
/* Setup a temporary list of expired timers */
InitializeListHead(&TempList2);
/* Loop absolute timers */
while (TempList.Flink != &TempList)
{
/* Get the timer */
Timer = CONTAINING_RECORD(TempList.Flink, KTIMER, TimerListEntry);
RemoveEntryList(&Timer->TimerListEntry);
/* Update the due time and handle */
Timer->DueTime.QuadPart -= DeltaTime.QuadPart;
Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart);
Timer->Header.Hand = (UCHAR)Hand;
/* Lock the timer and re-insert it */
LockQueue = KiAcquireTimerLock(Hand);
if (KiInsertTimerTable(Timer, Hand))
{
/* Remove it from the timer list */
KiRemoveEntryTimer(Timer);
/* Insert it into our temporary list */
InsertTailList(&TempList2, &Timer->TimerListEntry);
}
/* Release the lock */
KiReleaseTimerLock(LockQueue);
}
/* Process expired timers. This releases the dispatcher lock. */
KiTimerListExpire(&TempList2, OldIrql);
/* Revert affinity */
KeRevertToUserAffinityThread();
}
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @implemented
*/
ULONG
NTAPI
KeQueryTimeIncrement(VOID)
{
/* Return the increment */
return KeMaximumIncrement;
}
/*
* @implemented
*/
#undef KeQueryTickCount
VOID
NTAPI
KeQueryTickCount(IN PLARGE_INTEGER TickCount)
{
/* Loop until we get a perfect match */
for (;;)
{
/* Read the tick count value */
TickCount->HighPart = KeTickCount.High1Time;
TickCount->LowPart = KeTickCount.LowPart;
if (TickCount->HighPart == KeTickCount.High2Time) break;
YieldProcessor();
}
}
#ifndef _M_AMD64
/*
* @implemented
*/
VOID
NTAPI
KeQuerySystemTime(OUT PLARGE_INTEGER CurrentTime)
{
/* Loop until we get a perfect match */
for (;;)
{
/* Read the time value */
CurrentTime->HighPart = SharedUserData->SystemTime.High1Time;
CurrentTime->LowPart = SharedUserData->SystemTime.LowPart;
if (CurrentTime->HighPart ==
SharedUserData->SystemTime.High2Time) break;
YieldProcessor();
}
}
/*
* @implemented
*/
ULONGLONG
NTAPI
KeQueryInterruptTime(VOID)
{
LARGE_INTEGER CurrentTime;
/* Loop until we get a perfect match */
for (;;)
{
/* Read the time value */
CurrentTime.HighPart = SharedUserData->InterruptTime.High1Time;
CurrentTime.LowPart = SharedUserData->InterruptTime.LowPart;
if (CurrentTime.HighPart ==
SharedUserData->InterruptTime.High2Time) break;
YieldProcessor();
}
/* Return the time value */
return CurrentTime.QuadPart;
}
#endif
/*
* @implemented
*/
VOID
NTAPI
KeSetTimeIncrement(IN ULONG MaxIncrement,
IN ULONG MinIncrement)
{
/* Set some Internal Variables */
KeMaximumIncrement = MaxIncrement;
KeMinimumIncrement = max(MinIncrement, 10000);
KeTimeAdjustment = MaxIncrement;
KeTimeIncrement = MaxIncrement;
KiTickOffset = MaxIncrement;
}
/* EOF */