mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
Reimplemented Kernel and Executive Timers. Use Microsoft documented structures, added locks to protect against race conditions, use dispatcher database, implement new features like wake timers, use thread timer lists, simplify timer list, add more comments and debug info, actually add apc/dpc functions which do what the should do, fix a couple of bugs, simplfiy absolute vs relative timers. I will do more testing and see wether an experimental Timer Tree patch (which greatly speeds up timer processing) is necessary.
svn path=/trunk/; revision=13554
This commit is contained in:
parent
44b4c1125e
commit
3f700c132c
10 changed files with 1458 additions and 1292 deletions
|
@ -246,6 +246,12 @@ KeQueryTimeIncrement (
|
||||||
VOID
|
VOID
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ULONGLONG
|
||||||
|
STDCALL
|
||||||
|
KeQueryInterruptTime(
|
||||||
|
VOID
|
||||||
|
);
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
STDCALL
|
STDCALL
|
||||||
KeRaiseIrql (
|
KeRaiseIrql (
|
||||||
|
|
|
@ -96,6 +96,7 @@ OBJECTS_KE = \
|
||||||
ke/apc.o \
|
ke/apc.o \
|
||||||
ke/bug.o \
|
ke/bug.o \
|
||||||
ke/catch.o \
|
ke/catch.o \
|
||||||
|
ke/clock.o \
|
||||||
ke/critical.o \
|
ke/critical.o \
|
||||||
ke/dpc.o \
|
ke/dpc.o \
|
||||||
ke/device.o \
|
ke/device.o \
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -142,6 +142,8 @@ VOID STDCALL KiDeleteProfile(PVOID ObjectBody);
|
||||||
VOID STDCALL KeUpdateSystemTime(PKTRAP_FRAME TrapFrame, KIRQL Irql);
|
VOID STDCALL KeUpdateSystemTime(PKTRAP_FRAME TrapFrame, KIRQL Irql);
|
||||||
VOID STDCALL KeUpdateRunTime(PKTRAP_FRAME TrapFrame, KIRQL Irql);
|
VOID STDCALL KeUpdateRunTime(PKTRAP_FRAME TrapFrame, KIRQL Irql);
|
||||||
|
|
||||||
|
VOID STDCALL KiExpireTimers(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2);
|
||||||
|
|
||||||
KIRQL KeAcquireDispatcherDatabaseLock(VOID);
|
KIRQL KeAcquireDispatcherDatabaseLock(VOID);
|
||||||
VOID KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID);
|
VOID KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID);
|
||||||
VOID KeReleaseDispatcherDatabaseLock(KIRQL Irql);
|
VOID KeReleaseDispatcherDatabaseLock(KIRQL Irql);
|
||||||
|
@ -193,7 +195,7 @@ VOID KeInitTimer(VOID);
|
||||||
VOID KeInitDpc(struct _KPCR* Pcr);
|
VOID KeInitDpc(struct _KPCR* Pcr);
|
||||||
VOID KeInitDispatcher(VOID);
|
VOID KeInitDispatcher(VOID);
|
||||||
VOID KeInitializeDispatcher(VOID);
|
VOID KeInitializeDispatcher(VOID);
|
||||||
VOID KeInitializeTimerImpl(VOID);
|
VOID KiInitializeSystemClock(VOID);
|
||||||
VOID KeInitializeBugCheck(VOID);
|
VOID KeInitializeBugCheck(VOID);
|
||||||
VOID Phase1Initialization(PVOID Context);
|
VOID Phase1Initialization(PVOID Context);
|
||||||
|
|
||||||
|
|
410
reactos/ntoskrnl/ke/clock.c
Normal file
410
reactos/ntoskrnl/ke/clock.c
Normal file
|
@ -0,0 +1,410 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS kernel
|
||||||
|
* FILE: ntoskrnl/ke/clock.c
|
||||||
|
* PURPOSE: Handle System Clock
|
||||||
|
*
|
||||||
|
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Created
|
||||||
|
* David Welch & Phillip Susi - Implementation (?)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* NOTES ******************************************************************/
|
||||||
|
/*
|
||||||
|
* System time units are 100-nanosecond intervals
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES ***************************************************************/
|
||||||
|
|
||||||
|
#include <ntoskrnl.h>
|
||||||
|
|
||||||
|
#define NDEBUG
|
||||||
|
#include <internal/debug.h>
|
||||||
|
|
||||||
|
/* GLOBALS ****************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Current time
|
||||||
|
*/
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
LARGE_INTEGER SystemBootTime = (LARGE_INTEGER)0LL;
|
||||||
|
#else
|
||||||
|
LARGE_INTEGER SystemBootTime = { 0 };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CHAR KiTimerSystemAuditing = 0;
|
||||||
|
static KDPC KiExpireTimerDpc;
|
||||||
|
static BOOLEAN KiClockSetupComplete = FALSE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of timer interrupts since initialisation
|
||||||
|
*/
|
||||||
|
volatile ULONGLONG KeTickCount = 0;
|
||||||
|
volatile ULONG KiRawTicks = 0;
|
||||||
|
|
||||||
|
extern LIST_ENTRY KiTimerListHead;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The increment in the system clock every timer tick (in system time units)
|
||||||
|
*
|
||||||
|
* = (1/18.2)*10^9
|
||||||
|
*
|
||||||
|
* RJJ was 54945055
|
||||||
|
*/
|
||||||
|
#define CLOCK_INCREMENT (100000)
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
ULONG EXPORTED KeMaximumIncrement = 100000;
|
||||||
|
ULONG EXPORTED KeMinimumIncrement = 100000;
|
||||||
|
#else
|
||||||
|
/* Microsoft-style declarations */
|
||||||
|
EXPORTED ULONG KeMaximumIncrement = 100000;
|
||||||
|
EXPORTED ULONG KeMinimumIncrement = 100000;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MICROSECONDS_PER_TICK (10000)
|
||||||
|
#define TICKS_TO_CALIBRATE (1)
|
||||||
|
#define CALIBRATE_PERIOD (MICROSECONDS_PER_TICK * TICKS_TO_CALIBRATE)
|
||||||
|
|
||||||
|
/* FUNCTIONS **************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FUNCTION: Initializes timer irq handling
|
||||||
|
* NOTE: This is only called once from main()
|
||||||
|
*/
|
||||||
|
VOID
|
||||||
|
INIT_FUNCTION
|
||||||
|
KiInitializeSystemClock(VOID)
|
||||||
|
{
|
||||||
|
TIME_FIELDS TimeFields;
|
||||||
|
|
||||||
|
DPRINT1("KiInitializeSystemClock()\n");
|
||||||
|
InitializeListHead(&KiTimerListHead);
|
||||||
|
KeInitializeDpc(&KiExpireTimerDpc, (PKDEFERRED_ROUTINE)KiExpireTimers, 0);
|
||||||
|
|
||||||
|
/* Calculate the starting time for the system clock */
|
||||||
|
HalQueryRealTimeClock(&TimeFields);
|
||||||
|
RtlTimeFieldsToTime(&TimeFields, &SystemBootTime);
|
||||||
|
|
||||||
|
/* Set up the Used Shared Data */
|
||||||
|
SharedUserData->TickCountLowDeprecated = 0;
|
||||||
|
SharedUserData->TickCountMultiplier = 167783691; // 2^24 * 1193182 / 119310
|
||||||
|
SharedUserData->InterruptTime.High2Time = 0;
|
||||||
|
SharedUserData->InterruptTime.LowPart = 0;
|
||||||
|
SharedUserData->InterruptTime.High1Time = 0;
|
||||||
|
SharedUserData->SystemTime.High2Time = SystemBootTime.u.HighPart;
|
||||||
|
SharedUserData->SystemTime.LowPart = SystemBootTime.u.LowPart;
|
||||||
|
SharedUserData->SystemTime.High1Time = SystemBootTime.u.HighPart;
|
||||||
|
|
||||||
|
KiClockSetupComplete = TRUE;
|
||||||
|
DPRINT1("Finished KiInitializeSystemClock()\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
KiSetSystemTime(PLARGE_INTEGER NewSystemTime)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER OldSystemTime;
|
||||||
|
LARGE_INTEGER DeltaTime;
|
||||||
|
KIRQL OldIrql;
|
||||||
|
|
||||||
|
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
||||||
|
|
||||||
|
OldIrql = KeAcquireDispatcherDatabaseLock();
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
OldSystemTime.u.HighPart = SharedUserData->SystemTime.High1Time;
|
||||||
|
OldSystemTime.u.LowPart = SharedUserData->SystemTime.LowPart;
|
||||||
|
}
|
||||||
|
while (OldSystemTime.u.HighPart != SharedUserData->SystemTime.High2Time);
|
||||||
|
|
||||||
|
/* Set the new system time */
|
||||||
|
SharedUserData->SystemTime.LowPart = NewSystemTime->u.LowPart;
|
||||||
|
SharedUserData->SystemTime.High1Time = NewSystemTime->u.HighPart;
|
||||||
|
SharedUserData->SystemTime.High2Time = NewSystemTime->u.HighPart;
|
||||||
|
|
||||||
|
/* Calculate the difference between the new and the old time */
|
||||||
|
DeltaTime.QuadPart = NewSystemTime->QuadPart - OldSystemTime.QuadPart;
|
||||||
|
|
||||||
|
/* Update system boot time */
|
||||||
|
SystemBootTime.QuadPart += DeltaTime.QuadPart;
|
||||||
|
|
||||||
|
/* Update absolute timers */
|
||||||
|
DPRINT1("FIXME: TIMER UPDATE NOT DONE!!!\n");
|
||||||
|
|
||||||
|
KeReleaseDispatcherDatabaseLock(OldIrql);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: Expired timers will be processed at the next clock tick!
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
ULONG
|
||||||
|
STDCALL
|
||||||
|
KeQueryTimeIncrement(VOID)
|
||||||
|
/*
|
||||||
|
* FUNCTION: Gets the increment (in 100-nanosecond units) that is added to
|
||||||
|
* the system clock every time the clock interrupts
|
||||||
|
* RETURNS: The increment
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
return KeMaximumIncrement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
VOID
|
||||||
|
STDCALL
|
||||||
|
KeQueryTickCount(PLARGE_INTEGER TickCount)
|
||||||
|
/*
|
||||||
|
* FUNCTION: Returns the number of ticks since the system was booted
|
||||||
|
* ARGUMENTS:
|
||||||
|
* TickCount (OUT) = Points to storage for the number of ticks
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
TickCount->QuadPart = KeTickCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FUNCTION: Gets the current system time
|
||||||
|
* ARGUMENTS:
|
||||||
|
* CurrentTime (OUT) = The routine stores the current time here
|
||||||
|
* NOTE: The time is the number of 100-nanosecond intervals since the
|
||||||
|
* 1st of January, 1601.
|
||||||
|
*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
VOID
|
||||||
|
STDCALL
|
||||||
|
KeQuerySystemTime(PLARGE_INTEGER CurrentTime)
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
CurrentTime->u.HighPart = SharedUserData->SystemTime.High1Time;
|
||||||
|
CurrentTime->u.LowPart = SharedUserData->SystemTime.LowPart;
|
||||||
|
} while (CurrentTime->u.HighPart != SharedUserData->SystemTime.High2Time);
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONGLONG
|
||||||
|
STDCALL
|
||||||
|
KeQueryInterruptTime(VOID)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER CurrentTime;
|
||||||
|
|
||||||
|
do {
|
||||||
|
CurrentTime.u.HighPart = SharedUserData->InterruptTime.High1Time;
|
||||||
|
CurrentTime.u.LowPart = SharedUserData->InterruptTime.LowPart;
|
||||||
|
} while (CurrentTime.u.HighPart != SharedUserData->InterruptTime.High2Time);
|
||||||
|
|
||||||
|
return CurrentTime.QuadPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
VOID
|
||||||
|
STDCALL
|
||||||
|
KeSetTimeIncrement(
|
||||||
|
IN ULONG MaxIncrement,
|
||||||
|
IN ULONG MinIncrement)
|
||||||
|
{
|
||||||
|
/* Set some Internal Variables */
|
||||||
|
/* FIXME: We use a harcoded CLOCK_INCREMENT. That *must* be changed */
|
||||||
|
KeMaximumIncrement = MaxIncrement;
|
||||||
|
KeMinimumIncrement = MinIncrement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @unimplemented
|
||||||
|
*/
|
||||||
|
VOID
|
||||||
|
FASTCALL
|
||||||
|
KeSetTimeUpdateNotifyRoutine(
|
||||||
|
IN PTIME_UPDATE_NOTIFY_ROUTINE NotifyRoutine
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: On Windows this function takes exactly one parameter and EBP is
|
||||||
|
* guaranteed to point to KTRAP_FRAME. The function is used only
|
||||||
|
* by HAL, so there's no point in keeping that prototype.
|
||||||
|
*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
VOID
|
||||||
|
STDCALL
|
||||||
|
KeUpdateRunTime(
|
||||||
|
IN PKTRAP_FRAME TrapFrame,
|
||||||
|
IN KIRQL Irql
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PKPCR Pcr;
|
||||||
|
PKTHREAD CurrentThread;
|
||||||
|
PKPROCESS CurrentProcess;
|
||||||
|
#if 0
|
||||||
|
ULONG DpcLastCount;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Pcr = KeGetCurrentKPCR();
|
||||||
|
|
||||||
|
/* Make sure we don't go further if we're in early boot phase. */
|
||||||
|
if (Pcr == NULL || Pcr->PrcbData.CurrentThread == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DPRINT("KernelTime %u, UserTime %u \n", Pcr->PrcbData.KernelTime, Pcr->PrcbData.UserTime);
|
||||||
|
|
||||||
|
CurrentThread = Pcr->PrcbData.CurrentThread;
|
||||||
|
CurrentProcess = CurrentThread->ApcState.Process;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cs bit 0 is always set for user mode if we are in protected mode.
|
||||||
|
* V86 mode is counted as user time.
|
||||||
|
*/
|
||||||
|
if (TrapFrame->Cs & 0x1 ||
|
||||||
|
TrapFrame->Eflags & X86_EFLAGS_VM)
|
||||||
|
{
|
||||||
|
InterlockedIncrementUL(&CurrentThread->UserTime);
|
||||||
|
InterlockedIncrementUL(&CurrentProcess->UserTime);
|
||||||
|
Pcr->PrcbData.UserTime++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Irql > DISPATCH_LEVEL)
|
||||||
|
{
|
||||||
|
Pcr->PrcbData.InterruptTime++;
|
||||||
|
}
|
||||||
|
else if (Irql == DISPATCH_LEVEL)
|
||||||
|
{
|
||||||
|
Pcr->PrcbData.DpcTime++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InterlockedIncrementUL(&CurrentThread->KernelTime);
|
||||||
|
InterlockedIncrementUL(&CurrentProcess->KernelTime);
|
||||||
|
Pcr->PrcbData.KernelTime++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
DpcLastCount = Pcr->PrcbData.DpcLastCount;
|
||||||
|
Pcr->PrcbData.DpcLastCount = Pcr->PrcbData.DpcCount;
|
||||||
|
Pcr->PrcbData.DpcRequestRate = ((Pcr->PrcbData.DpcCount - DpcLastCount) +
|
||||||
|
Pcr->PrcbData.DpcRequestRate) / 2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (Pcr->PrcbData.DpcData[0].DpcQueueDepth > 0 &&
|
||||||
|
Pcr->PrcbData.DpcRoutineActive == FALSE &&
|
||||||
|
Pcr->PrcbData.DpcInterruptRequested == FALSE)
|
||||||
|
{
|
||||||
|
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: Do DPC rate adjustments */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we're at end of quantum request software interrupt. The rest
|
||||||
|
* is handled in KiDispatchInterrupt.
|
||||||
|
*/
|
||||||
|
if ((CurrentThread->Quantum -= 3) <= 0)
|
||||||
|
{
|
||||||
|
Pcr->PrcbData.QuantumEnd = TRUE;
|
||||||
|
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: On Windows this function takes exactly zero parameters and EBP is
|
||||||
|
* guaranteed to point to KTRAP_FRAME. Also [esp+0] contains an IRQL.
|
||||||
|
* The function is used only by HAL, so there's no point in keeping
|
||||||
|
* that prototype.
|
||||||
|
*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
VOID
|
||||||
|
STDCALL
|
||||||
|
KeUpdateSystemTime(
|
||||||
|
IN PKTRAP_FRAME TrapFrame,
|
||||||
|
IN KIRQL Irql
|
||||||
|
)
|
||||||
|
/*
|
||||||
|
* FUNCTION: Handles a timer interrupt
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
LARGE_INTEGER Time;
|
||||||
|
|
||||||
|
ASSERT(KeGetCurrentIrql() == PROFILE_LEVEL);
|
||||||
|
|
||||||
|
KiRawTicks++;
|
||||||
|
|
||||||
|
if (KiClockSetupComplete == FALSE) return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Increment the number of timers ticks
|
||||||
|
*/
|
||||||
|
KeTickCount++;
|
||||||
|
SharedUserData->TickCountLowDeprecated++;
|
||||||
|
|
||||||
|
Time.u.LowPart = SharedUserData->InterruptTime.LowPart;
|
||||||
|
Time.u.HighPart = SharedUserData->InterruptTime.High1Time;
|
||||||
|
Time.QuadPart += CLOCK_INCREMENT;
|
||||||
|
SharedUserData->InterruptTime.High2Time = Time.u.HighPart;
|
||||||
|
SharedUserData->InterruptTime.LowPart = Time.u.LowPart;
|
||||||
|
SharedUserData->InterruptTime.High1Time = Time.u.HighPart;
|
||||||
|
|
||||||
|
Time.u.LowPart = SharedUserData->SystemTime.LowPart;
|
||||||
|
Time.u.HighPart = SharedUserData->SystemTime.High1Time;
|
||||||
|
Time.QuadPart += CLOCK_INCREMENT;
|
||||||
|
SharedUserData->SystemTime.High2Time = Time.u.HighPart;
|
||||||
|
SharedUserData->SystemTime.LowPart = Time.u.LowPart;
|
||||||
|
SharedUserData->SystemTime.High1Time = Time.u.HighPart;
|
||||||
|
|
||||||
|
/* FIXME: Here we should check for remote debugger break-ins */
|
||||||
|
|
||||||
|
/* Update process and thread times */
|
||||||
|
KeUpdateRunTime(TrapFrame, Irql);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Queue a DPC that will expire timers
|
||||||
|
*/
|
||||||
|
KeInsertQueueDpc(&KiExpireTimerDpc, (PVOID)TrapFrame->Eip, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
ULONG
|
||||||
|
STDCALL
|
||||||
|
NtGetTickCount(VOID)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER TickCount;
|
||||||
|
|
||||||
|
KeQueryTickCount(&TickCount);
|
||||||
|
return TickCount.u.LowPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
STDCALL
|
||||||
|
NtQueryTimerResolution(OUT PULONG MinimumResolution,
|
||||||
|
OUT PULONG MaximumResolution,
|
||||||
|
OUT PULONG ActualResolution)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
STDCALL
|
||||||
|
NtSetTimerResolution(IN ULONG DesiredResolution,
|
||||||
|
IN BOOLEAN SetResolution,
|
||||||
|
OUT PULONG CurrentResolution)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* EOF */
|
|
@ -341,7 +341,7 @@ KeInit2(VOID)
|
||||||
|
|
||||||
KeInitializeBugCheck();
|
KeInitializeBugCheck();
|
||||||
KeInitializeDispatcher();
|
KeInitializeDispatcher();
|
||||||
KeInitializeTimerImpl();
|
KiInitializeSystemClock();
|
||||||
|
|
||||||
if (Pcr->PrcbData.FeatureBits & X86_FEATURE_PAE)
|
if (Pcr->PrcbData.FeatureBits & X86_FEATURE_PAE)
|
||||||
{
|
{
|
||||||
|
|
|
@ -72,6 +72,23 @@ KeQueryPriorityThread (
|
||||||
return Thread->Priority;
|
return Thread->Priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
ULONG
|
||||||
|
STDCALL
|
||||||
|
KeQueryRuntimeThread(
|
||||||
|
IN PKTHREAD Thread,
|
||||||
|
OUT PULONG UserTime
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/* Return the User Time */
|
||||||
|
*UserTime = Thread->UserTime;
|
||||||
|
|
||||||
|
/* Return the Kernel Time */
|
||||||
|
return Thread->KernelTime;
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
KeReleaseThread(PKTHREAD Thread)
|
KeReleaseThread(PKTHREAD Thread)
|
||||||
/*
|
/*
|
||||||
|
@ -405,3 +422,45 @@ KeTerminateThread(IN KPRIORITY Increment)
|
||||||
/* Call our own internal routine */
|
/* Call our own internal routine */
|
||||||
PsTerminateCurrentThread(0);
|
PsTerminateCurrentThread(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
STDCALL
|
||||||
|
NtDelayExecution(IN BOOLEAN Alertable,
|
||||||
|
IN PLARGE_INTEGER DelayInterval)
|
||||||
|
{
|
||||||
|
KPROCESSOR_MODE PreviousMode;
|
||||||
|
LARGE_INTEGER SafeInterval;
|
||||||
|
|
||||||
|
PreviousMode = ExGetPreviousMode();
|
||||||
|
|
||||||
|
if(PreviousMode != KernelMode)
|
||||||
|
{
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
_SEH_TRY
|
||||||
|
{
|
||||||
|
ProbeForRead(DelayInterval,
|
||||||
|
sizeof(LARGE_INTEGER),
|
||||||
|
sizeof(ULONG));
|
||||||
|
/* make a copy on the kernel stack and let DelayInterval point to it so
|
||||||
|
we don't need to wrap KeDelayExecutionThread in SEH! */
|
||||||
|
SafeInterval = *DelayInterval;
|
||||||
|
DelayInterval = &SafeInterval;
|
||||||
|
}
|
||||||
|
_SEH_HANDLE
|
||||||
|
{
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
}
|
||||||
|
_SEH_END;
|
||||||
|
|
||||||
|
if(!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return KeDelayExecutionThread(PreviousMode,
|
||||||
|
Alertable,
|
||||||
|
DelayInterval);
|
||||||
|
}
|
||||||
|
|
|
@ -284,3 +284,59 @@ KeSetProfileIrql(
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
UNIMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS STDCALL
|
||||||
|
NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter,
|
||||||
|
OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER PerfCounter;
|
||||||
|
LARGE_INTEGER PerfFrequency;
|
||||||
|
KPROCESSOR_MODE PreviousMode;
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
PreviousMode = ExGetPreviousMode();
|
||||||
|
|
||||||
|
if(PreviousMode != KernelMode)
|
||||||
|
{
|
||||||
|
_SEH_TRY
|
||||||
|
{
|
||||||
|
ProbeForWrite(PerformanceCounter,
|
||||||
|
sizeof(LARGE_INTEGER),
|
||||||
|
sizeof(ULONG));
|
||||||
|
if(PerformanceFrequency != NULL)
|
||||||
|
{
|
||||||
|
ProbeForWrite(PerformanceFrequency,
|
||||||
|
sizeof(LARGE_INTEGER),
|
||||||
|
sizeof(ULONG));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_SEH_HANDLE
|
||||||
|
{
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
}
|
||||||
|
_SEH_END;
|
||||||
|
|
||||||
|
if(!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PerfCounter = KeQueryPerformanceCounter(&PerfFrequency);
|
||||||
|
|
||||||
|
_SEH_TRY
|
||||||
|
{
|
||||||
|
*PerformanceCounter = PerfCounter;
|
||||||
|
if(PerformanceFrequency != NULL)
|
||||||
|
{
|
||||||
|
*PerformanceFrequency = PerfFrequency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_SEH_HANDLE
|
||||||
|
{
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
}
|
||||||
|
_SEH_END;
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -397,6 +397,32 @@ BOOLEAN KiDispatcherObjectWake(DISPATCHER_HEADER* hdr, KPRIORITY increment)
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
NTSTATUS STDCALL
|
||||||
|
KeDelayExecutionThread (KPROCESSOR_MODE WaitMode,
|
||||||
|
BOOLEAN Alertable,
|
||||||
|
PLARGE_INTEGER Interval)
|
||||||
|
/*
|
||||||
|
* FUNCTION: Puts the current thread into an alertable or nonalertable
|
||||||
|
* wait state for a given internal
|
||||||
|
* ARGUMENTS:
|
||||||
|
* WaitMode = Processor mode in which the caller is waiting
|
||||||
|
* Altertable = Specifies if the wait is alertable
|
||||||
|
* Interval = Specifies the interval to wait
|
||||||
|
* RETURNS: Status
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
PKTHREAD Thread = KeGetCurrentThread();
|
||||||
|
|
||||||
|
KeSetTimer(&Thread->Timer, *Interval, NULL);
|
||||||
|
return (KeWaitForSingleObject(&Thread->Timer,
|
||||||
|
(WaitMode == KernelMode) ? Executive : UserRequest, /* TMN: Was unconditionally Executive */
|
||||||
|
WaitMode, /* TMN: Was UserMode */
|
||||||
|
Alertable,
|
||||||
|
NULL));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
|
@ -585,13 +611,13 @@ KeWaitForMultipleObjects(ULONG Count,
|
||||||
{
|
{
|
||||||
Abandoned = KiSideEffectsBeforeWake(hdr, CurrentThread) ? TRUE : Abandoned;
|
Abandoned = KiSideEffectsBeforeWake(hdr, CurrentThread) ? TRUE : Abandoned;
|
||||||
|
|
||||||
|
KeReleaseDispatcherDatabaseLock(OldIrql);
|
||||||
|
|
||||||
if (Timeout != NULL && Timeout->QuadPart != 0)
|
if (Timeout != NULL && Timeout->QuadPart != 0)
|
||||||
{
|
{
|
||||||
KeCancelTimer(&CurrentThread->Timer);
|
KeCancelTimer(&CurrentThread->Timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
KeReleaseDispatcherDatabaseLock(OldIrql);
|
|
||||||
|
|
||||||
DPRINT("One object is (already) signaled!\n");
|
DPRINT("One object is (already) signaled!\n");
|
||||||
if (Abandoned == TRUE)
|
if (Abandoned == TRUE)
|
||||||
{
|
{
|
||||||
|
@ -612,12 +638,13 @@ KeWaitForMultipleObjects(ULONG Count,
|
||||||
Abandoned = KiSideEffectsBeforeWake(hdr, CurrentThread) ? TRUE : Abandoned;
|
Abandoned = KiSideEffectsBeforeWake(hdr, CurrentThread) ? TRUE : Abandoned;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeReleaseDispatcherDatabaseLock(OldIrql);
|
||||||
|
|
||||||
if (Timeout != NULL && Timeout->QuadPart != 0)
|
if (Timeout != NULL && Timeout->QuadPart != 0)
|
||||||
{
|
{
|
||||||
KeCancelTimer(&CurrentThread->Timer);
|
KeCancelTimer(&CurrentThread->Timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
KeReleaseDispatcherDatabaseLock(OldIrql);
|
|
||||||
DPRINT("All objects are (already) signaled!\n");
|
DPRINT("All objects are (already) signaled!\n");
|
||||||
|
|
||||||
if (Abandoned == TRUE)
|
if (Abandoned == TRUE)
|
||||||
|
@ -641,8 +668,8 @@ KeWaitForMultipleObjects(ULONG Count,
|
||||||
if (Timeout != NULL && KiIsObjectSignalled(&CurrentThread->Timer.Header, CurrentThread))
|
if (Timeout != NULL && KiIsObjectSignalled(&CurrentThread->Timer.Header, CurrentThread))
|
||||||
{
|
{
|
||||||
KiSideEffectsBeforeWake(&CurrentThread->Timer.Header, CurrentThread);
|
KiSideEffectsBeforeWake(&CurrentThread->Timer.Header, CurrentThread);
|
||||||
KeCancelTimer(&CurrentThread->Timer);
|
|
||||||
KeReleaseDispatcherDatabaseLock(OldIrql);
|
KeReleaseDispatcherDatabaseLock(OldIrql);
|
||||||
|
KeCancelTimer(&CurrentThread->Timer);
|
||||||
return (STATUS_TIMEOUT);
|
return (STATUS_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue