mirror of
https://github.com/reactos/reactos.git
synced 2024-08-21 19:03:01 +00:00
240 lines
6.4 KiB
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 */
|