- Ported 13554, 13556, 13566 and 13568 (recent changes within the timer
implementation) from trunk.
Modified: branches/cache_manager_rewrite/reactos/include/ddk/kefuncs.h
Modified: branches/cache_manager_rewrite/reactos/ntoskrnl/Makefile
Modified: branches/cache_manager_rewrite/reactos/ntoskrnl/ex/timer.c
Modified:
branches/cache_manager_rewrite/reactos/ntoskrnl/include/internal/ke.h
Added: branches/cache_manager_rewrite/reactos/ntoskrnl/ke/clock.c
Modified:
branches/cache_manager_rewrite/reactos/ntoskrnl/ke/i386/kernel.c
Modified: branches/cache_manager_rewrite/reactos/ntoskrnl/ke/kthread.c
Modified: branches/cache_manager_rewrite/reactos/ntoskrnl/ke/profile.c
Modified: branches/cache_manager_rewrite/reactos/ntoskrnl/ke/timer.c
Modified: branches/cache_manager_rewrite/reactos/ntoskrnl/ke/wait.c
_____
Modified: branches/cache_manager_rewrite/reactos/include/ddk/kefuncs.h
--- branches/cache_manager_rewrite/reactos/include/ddk/kefuncs.h
2005-02-14 17:34:10 UTC (rev 13570)
+++ branches/cache_manager_rewrite/reactos/include/ddk/kefuncs.h
2005-02-14 18:19:29 UTC (rev 13571)
@@ -246,6 +246,12 @@
VOID
);
+ULONGLONG
+STDCALL
+KeQueryInterruptTime(
+ VOID
+ );
+
VOID
STDCALL
KeRaiseIrql (
_____
Modified: branches/cache_manager_rewrite/reactos/ntoskrnl/Makefile
--- branches/cache_manager_rewrite/reactos/ntoskrnl/Makefile
2005-02-14 17:34:10 UTC (rev 13570)
+++ branches/cache_manager_rewrite/reactos/ntoskrnl/Makefile
2005-02-14 18:19:29 UTC (rev 13571)
@@ -96,6 +96,7 @@
ke/apc.o \
ke/bug.o \
ke/catch.o \
+ ke/clock.o \
ke/critical.o \
ke/dpc.o \
ke/device.o \
_____
Modified: branches/cache_manager_rewrite/reactos/ntoskrnl/ex/timer.c
--- branches/cache_manager_rewrite/reactos/ntoskrnl/ex/timer.c
2005-02-14 17:34:10 UTC (rev 13570)
+++ branches/cache_manager_rewrite/reactos/ntoskrnl/ex/timer.c
2005-02-14 18:19:29 UTC (rev 13571)
@@ -5,7 +5,8 @@
* FILE: ntoskrnl/ex/timer.c
* PURPOSE: User-mode timers
*
- * PROGRAMMERS: David Welch (welch(a)mcmail.com)
+ * PROGRAMMERS: Alex Ionescu (alex(a)relsoft.net) - Reimplemented
+ * David Welch (welch(a)mcmail.com)
*/
/* INCLUDES
*****************************************************************/
@@ -13,528 +14,670 @@
#include <ntoskrnl.h>
#include <internal/debug.h>
-
/* TYPES
********************************************************************/
-typedef struct _NTTIMER
-{
- KTIMER Timer;
- KDPC Dpc;
- KAPC Apc;
- BOOLEAN Running;
-} NTTIMER, *PNTTIMER;
+/* Executive Timer Object */
+typedef struct _ETIMER {
+ KTIMER KeTimer;
+ KAPC TimerApc;
+ KDPC TimerDpc;
+ LIST_ENTRY ActiveTimerListEntry;
+ KSPIN_LOCK Lock;
+ LONG Period;
+ BOOLEAN ApcAssociated;
+ BOOLEAN WakeTimer;
+ LIST_ENTRY WakeTimerListEntry;
+} ETIMER, *PETIMER;
-
/* GLOBALS
******************************************************************/
+/* Timer Object Type */
POBJECT_TYPE ExTimerType = NULL;
+KSPIN_LOCK ExpWakeListLock;
+LIST_ENTRY ExpWakeList;
+
+/* Timer Mapping */
static GENERIC_MAPPING ExpTimerMapping = {
- STANDARD_RIGHTS_READ | TIMER_QUERY_STATE,
- STANDARD_RIGHTS_WRITE | TIMER_MODIFY_STATE,
- STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
- TIMER_ALL_ACCESS};
+ STANDARD_RIGHTS_READ | TIMER_QUERY_STATE,
+ STANDARD_RIGHTS_WRITE | TIMER_MODIFY_STATE,
+ STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
+ TIMER_ALL_ACCESS
+};
-static const INFORMATION_CLASS_INFO ExTimerInfoClass[] =
-{
- ICI_SQ_SAME( sizeof(TIMER_BASIC_INFORMATION), sizeof(ULONG),
ICIF_QUERY ), /* TimerBasicInformation */
+/* Timer Information Classes */
+static const INFORMATION_CLASS_INFO ExTimerInfoClass[] = {
+
+ /* TimerBasicInformation */
+ ICI_SQ_SAME( sizeof(TIMER_BASIC_INFORMATION), sizeof(ULONG),
ICIF_QUERY ),
};
/* FUNCTIONS
*****************************************************************/
-NTSTATUS STDCALL
-ExpCreateTimer(PVOID ObjectBody,
- PVOID Parent,
- PWSTR RemainingPath,
- POBJECT_ATTRIBUTES ObjectAttributes)
-{
- DPRINT("ExpCreateTimer(ObjectBody %x, Parent %x, RemainingPath
%S)\n",
- ObjectBody, Parent, RemainingPath);
-
- if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
- {
- return(STATUS_UNSUCCESSFUL);
- }
-
- return(STATUS_SUCCESS);
-}
-
-
-VOID STDCALL
+VOID
+STDCALL
ExpDeleteTimer(PVOID ObjectBody)
{
- KIRQL OldIrql;
- PNTTIMER Timer = ObjectBody;
+ KIRQL OldIrql;
+ PETIMER Timer = ObjectBody;
- DPRINT("ExpDeleteTimer()\n");
+ DPRINT("ExpDeleteTimer(Timer: %x)\n", Timer);
- OldIrql = KeRaiseIrqlToDpcLevel();
+ /* Lock the Wake List */
+ KeAcquireSpinLock(&ExpWakeListLock, &OldIrql);
+
+ /* Check if it has a Wait List */
+ if (!IsListEmpty(&Timer->WakeTimerListEntry)) {
+
+ /* Remove it from the Wait List */
+ DPRINT("Removing wake list\n");
+ RemoveEntryList(&Timer->WakeTimerListEntry);
+ }
+
+ /* Release the Wake List */
+ KeReleaseSpinLock(&ExpWakeListLock, OldIrql);
- KeCancelTimer(&Timer->Timer);
- KeRemoveQueueDpc(&Timer->Dpc);
- KeRemoveQueueApc(&Timer->Apc);
- Timer->Running = FALSE;
-
- KeLowerIrql(OldIrql);
+ /* Tell the Kernel to cancel the Timer */
+ DPRINT("Cancelling Timer\n");
+ KeCancelTimer(&Timer->KeTimer);
}
-
-VOID STDCALL
+VOID
+STDCALL
ExpTimerDpcRoutine(PKDPC Dpc,
- PVOID DeferredContext,
- PVOID SystemArgument1,
- PVOID SystemArgument2)
+ PVOID DeferredContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2)
{
- PNTTIMER Timer;
+ PETIMER Timer;
+ KIRQL OldIrql;
- DPRINT("ExpTimerDpcRoutine()\n");
+ DPRINT("ExpTimerDpcRoutine(Dpc: %x)\n", Dpc);
- Timer = (PNTTIMER)DeferredContext;
+ /* Get the Timer Object */
+ Timer = (PETIMER)DeferredContext;
- if ( Timer->Running )
- {
- KeInsertQueueApc(&Timer->Apc,
- SystemArgument1,
- SystemArgument2,
- IO_NO_INCREMENT);
- }
+ /* Lock the Timer */
+ KeAcquireSpinLock(&Timer->Lock, &OldIrql);
+
+ /* Queue the APC */
+ if(Timer->ApcAssociated) {
+
+ DPRINT("Queuing APC\n");
+ KeInsertQueueApc(&Timer->TimerApc,
+ SystemArgument1,
+ SystemArgument2,
+ IO_NO_INCREMENT);
+ }
+
+ /* Release the Timer */
+ KeReleaseSpinLock(&Timer->Lock, OldIrql);
}
-VOID STDCALL
+VOID
+STDCALL
ExpTimerApcKernelRoutine(PKAPC Apc,
- PKNORMAL_ROUTINE* NormalRoutine,
- PVOID* NormalContext,
- PVOID* SystemArgument1,
- PVOID* SystemArguemnt2)
+ PKNORMAL_ROUTINE* NormalRoutine,
+ PVOID* NormalContext,
+ PVOID* SystemArgument1,
+ PVOID* SystemArguemnt2)
{
- DPRINT("ExpTimerApcKernelRoutine()\n");
-
+ PETIMER Timer;
+ PETHREAD CurrentThread = PsGetCurrentThread();
+ KIRQL OldIrql;
+
+ /* We need to find out which Timer we are */
+ Timer = CONTAINING_RECORD(Apc, ETIMER, TimerApc);
+ DPRINT("ExpTimerApcKernelRoutine(Apc: %x. Timer: %x)\n", Apc,
Timer);
+
+ /* Lock the Timer */
+ KeAcquireSpinLock(&Timer->Lock, &OldIrql);
+
+ /* Lock the Thread's Active Timer List*/
+ KeAcquireSpinLockAtDpcLevel(&CurrentThread->ActiveTimerListLock);
+
+ /*
+ * Make sure that the Timer is still valid, and that it belongs to
this thread
+ * Remove it if it's not periodic
+ */
+ if ((Timer->ApcAssociated) &&
+ (&CurrentThread->Tcb == Timer->TimerApc.Thread) &&
+ (!Timer->Period)) {
+
+ /* Remove it from the Active Timers List */
+ DPRINT("Removing Timer\n");
+ RemoveEntryList(&Timer->ActiveTimerListEntry);
+
+ /* Disable it */
+ Timer->ApcAssociated = FALSE;
+
+ /* Release spinlocks */
+
KeReleaseSpinLockFromDpcLevel(&CurrentThread->ActiveTimerListLock);
+ KeReleaseSpinLock(&Timer->Lock, OldIrql);
+
+ /* Dereference the Timer Object */
+ ObDereferenceObject(Timer);
+ return;
+ }
+
+ /* Release spinlocks */
+ KeReleaseSpinLockFromDpcLevel(&CurrentThread->ActiveTimerListLock);
+ KeReleaseSpinLock(&Timer->Lock, OldIrql);
}
-
-VOID INIT_FUNCTION
+VOID
+INIT_FUNCTION
ExpInitializeTimerImplementation(VOID)
{
- ASSERT(!ExTimerType)
- ExTimerType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
+ DPRINT("ExpInitializeTimerImplementation()\n");
+
+ /* Allocate Memory for the Timer */
+ ExTimerType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
- RtlpCreateUnicodeString(&ExTimerType->TypeName, L"Timer",
NonPagedPool);
-
- ExTimerType->Tag = TAG('T', 'I', 'M', 'T');
- ExTimerType->PeakObjects = 0;
- ExTimerType->PeakHandles = 0;
- ExTimerType->TotalObjects = 0;
- ExTimerType->TotalHandles = 0;
- ExTimerType->PagedPoolCharge = 0;
- ExTimerType->NonpagedPoolCharge = sizeof(NTTIMER);
- ExTimerType->Mapping = &ExpTimerMapping;
- ExTimerType->Dump = NULL;
- ExTimerType->Open = NULL;
- ExTimerType->Close = NULL;
- ExTimerType->Delete = ExpDeleteTimer;
- ExTimerType->Parse = NULL;
- ExTimerType->Security = NULL;
- ExTimerType->QueryName = NULL;
- ExTimerType->OkayToClose = NULL;
- ExTimerType->Create = ExpCreateTimer;
- ExTimerType->DuplicationNotify = NULL;
-
- ObpCreateTypeObject(ExTimerType);
+ /* Create the Executive Timer Object */
+ RtlpCreateUnicodeString(&ExTimerType->TypeName, L"Timer",
NonPagedPool);
+ ExTimerType->Tag = TAG('T', 'I', 'M', 'T');
+ ExTimerType->PeakObjects = 0;
+ ExTimerType->PeakHandles = 0;
+ ExTimerType->TotalObjects = 0;
+ ExTimerType->TotalHandles = 0;
+ ExTimerType->PagedPoolCharge = 0;
+ ExTimerType->NonpagedPoolCharge = sizeof(ETIMER);
+ ExTimerType->Mapping = &ExpTimerMapping;
+ ExTimerType->Dump = NULL;
+ ExTimerType->Open = NULL;
+ ExTimerType->Close = NULL;
+ ExTimerType->Delete = ExpDeleteTimer;
+ ExTimerType->Parse = NULL;
+ ExTimerType->Security = NULL;
+ ExTimerType->QueryName = NULL;
+ ExTimerType->OkayToClose = NULL;
+ ExTimerType->Create = NULL;
+ ExTimerType->DuplicationNotify = NULL;
+ ObpCreateTypeObject(ExTimerType);
+
+ /* Initialize the Wait List and Lock */
+ KeInitializeSpinLock(&ExpWakeListLock);
+ InitializeListHead(&ExpWakeList);
}
-NTSTATUS STDCALL
+NTSTATUS
+STDCALL
NtCancelTimer(IN HANDLE TimerHandle,
- OUT PBOOLEAN CurrentState OPTIONAL)
+ OUT PBOOLEAN CurrentState OPTIONAL)
{
- PNTTIMER Timer;
- KPROCESSOR_MODE PreviousMode;
- NTSTATUS Status = STATUS_SUCCESS;
+ PETIMER Timer;
+ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOLEAN State;
+ KIRQL OldIrql;
+ BOOLEAN KillTimer = FALSE;
+ PETHREAD TimerThread;
- PreviousMode = ExGetPreviousMode();
+ DPRINT("NtCancelTimer(0x%x, 0x%x)\n", TimerHandle, CurrentState);
- DPRINT("NtCancelTimer(0x%x, 0x%x)\n", TimerHandle, CurrentState);
-
- if(CurrentState != NULL && PreviousMode != KernelMode)
- {
- _SEH_TRY
- {
- ProbeForWrite(CurrentState,
- sizeof(BOOLEAN),
- sizeof(BOOLEAN));
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
+ /* Check Parameter Validity */
+ if(CurrentState != NULL && PreviousMode != KernelMode) {
+ _SEH_TRY {
+ ProbeForWrite(CurrentState,
+ sizeof(BOOLEAN),
+ sizeof(BOOLEAN));
+ } _SEH_HANDLE {
+ Status = _SEH_GetExceptionCode();
+ } _SEH_END;
- if(!NT_SUCCESS(Status))
- {
- return Status;
- }
- }
+ if(!NT_SUCCESS(Status)) {
+ return Status;
+ }
+ }
- Status = ObReferenceObjectByHandle(TimerHandle,
- TIMER_ALL_ACCESS,
- ExTimerType,
- PreviousMode,
- (PVOID*)&Timer,
- NULL);
- if(NT_SUCCESS(Status))
- {
- BOOLEAN State;
- KIRQL OldIrql = KeRaiseIrqlToDpcLevel();
+ /* Get the Timer Object */
+ Status = ObReferenceObjectByHandle(TimerHandle,
+ TIMER_ALL_ACCESS,
+ ExTimerType,
+ PreviousMode,
+ (PVOID*)&Timer,
+ NULL);
+
+ /* Check for success */
+ if(NT_SUCCESS(Status)) {
+
+ DPRINT("Timer Referencced: %x\n", Timer);
+
+ /* Lock the Timer */
+ KeAcquireSpinLock(&Timer->Lock, &OldIrql);
+
+ /* Check if it's enabled */
+ if (Timer->ApcAssociated) {
+
+ /*
+ * First, remove it from the Thread's Active List
+ * Get the Thread.
+ */
+ TimerThread = CONTAINING_RECORD(Timer->TimerApc.Thread,
ETHREAD, Tcb);
+ DPRINT("Removing from Thread: %x\n", TimerThread);
+
+ /* Lock its active list */
+
KeAcquireSpinLockAtDpcLevel(&TimerThread->ActiveTimerListLock);
+
+ /* Remove it */
+ RemoveEntryList(&TimerThread->ActiveTimerListHead);
+
+ /* Unlock the list */
+
KeReleaseSpinLockFromDpcLevel(&TimerThread->ActiveTimerListLock);
+
+ /* Cancel the Timer */
+ KeCancelTimer(&Timer->KeTimer);
+ KeRemoveQueueDpc(&Timer->TimerDpc);
+ KeRemoveQueueApc(&Timer->TimerApc);
+ Timer->ApcAssociated = FALSE;
+ KillTimer = TRUE;
+
+ } else {
+
+ /* If timer was disabled, we still need to cancel it */
+ DPRINT("APC was not Associated. Cancelling Timer\n");
+ KeCancelTimer(&Timer->KeTimer);
+ }
+
+ /* Read the old State */
+ State = KeReadStateTimer(&Timer->KeTimer);
+
+ /* Dereference the Object */
+ ObDereferenceObject(Timer);
+
+ /* Unlock the Timer */
+ KeReleaseSpinLock(&Timer->Lock, OldIrql);
+
+ /* Dereference if it was previously enabled */
+ if (KillTimer) ObDereferenceObject(Timer);
+ DPRINT1("Timer disabled\n");
- State = KeCancelTimer(&Timer->Timer);
- KeRemoveQueueDpc(&Timer->Dpc);
- KeRemoveQueueApc(&Timer->Apc);
- Timer->Running = FALSE;
+ /* Make sure it's safe to write to the handle */
+ if(CurrentState != NULL) {
+ _SEH_TRY {
+ *CurrentState = State;
+ } _SEH_HANDLE {
+ Status = _SEH_GetExceptionCode();
+ } _SEH_END;
+ }
+ }
- KeLowerIrql(OldIrql);
- ObDereferenceObject(Timer);
-
- if(CurrentState != NULL)
- {
- _SEH_TRY
- {
- *CurrentState = State;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- }
- }
-
- return Status;
+ /* Return to Caller */
+ return Status;
}
-NTSTATUS STDCALL
+NTSTATUS
+STDCALL
NtCreateTimer(OUT PHANDLE TimerHandle,
- IN ACCESS_MASK DesiredAccess,
- IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
- IN TIMER_TYPE TimerType)
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
+ IN TIMER_TYPE TimerType)
{
- PNTTIMER Timer;
- HANDLE hTimer;
- KPROCESSOR_MODE PreviousMode;
- NTSTATUS Status = STATUS_SUCCESS;
+ PETIMER Timer;
+ HANDLE hTimer;
+ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ NTSTATUS Status = STATUS_SUCCESS;
- DPRINT("NtCreateTimer()\n");
+ DPRINT("NtCreateTimer(Handle: %x, Type: %d)\n", TimerHandle,
TimerType);
+
+ /* Check Parameter Validity */
+ if (PreviousMode != KernelMode) {
+ _SEH_TRY {
+ ProbeForWrite(TimerHandle,
+ sizeof(HANDLE),
+ sizeof(ULONG));
+ } _SEH_HANDLE {
+ Status = _SEH_GetExceptionCode();
+ } _SEH_END;
+
+ if(!NT_SUCCESS(Status)) {
+ return Status;
+ }
+ }
+
+ /* Create the Object */
+ Status = ObCreateObject(PreviousMode,
+ ExTimerType,
+ ObjectAttributes,
+ PreviousMode,
+ NULL,
+ sizeof(ETIMER),
+ 0,
+ 0,
+ (PVOID*)&Timer);
- PreviousMode = ExGetPreviousMode();
-
- if(PreviousMode != KernelMode)
- {
- _SEH_TRY
- {
- ProbeForWrite(TimerHandle,
- sizeof(HANDLE),
- sizeof(ULONG));
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
+ /* Check for Success */
+ if(NT_SUCCESS(Status)) {
+
+ /* Initialize the Kernel Timer */
+ DPRINT("Initializing Timer: %x\n", Timer);
+ KeInitializeTimerEx(&Timer->KeTimer, TimerType);
- if(!NT_SUCCESS(Status))
- {
- return Status;
- }
- }
+ /* Initialize the Timer Lock */
+ KeInitializeSpinLock(&Timer->Lock);
+
+ /* Initialize the DPC */
+ KeInitializeDpc(&Timer->TimerDpc, ExpTimerDpcRoutine, Timer);
- Status = ObCreateObject(PreviousMode,
- ExTimerType,
- ObjectAttributes,
- PreviousMode,
- NULL,
- sizeof(NTTIMER),
- 0,
- 0,
- (PVOID*)&Timer);
- if(NT_SUCCESS(Status))
- {
- KeInitializeTimerEx(&Timer->Timer,
- TimerType);
+ /* Set Initial State */
+ Timer->ApcAssociated = FALSE;
+ InitializeListHead(&Timer->WakeTimerListEntry);
+ Timer->WakeTimer = FALSE;
+
+ /* Insert the Timer */
+ Status = ObInsertObject((PVOID)Timer,
+ NULL,
+ DesiredAccess,
+ 0,
+ NULL,
+ &hTimer);
+ DPRINT("Timer Inserted\n");
- KeInitializeDpc(&Timer->Dpc,
- &ExpTimerDpcRoutine,
- Timer);
+
+ /* Make sure it's safe to write to the handle */
+ _SEH_TRY {
+ *TimerHandle = hTimer;
+ } _SEH_HANDLE {
+ Status = _SEH_GetExceptionCode();
+ } _SEH_END;
+ }
- Timer->Running = FALSE;
-
- Status = ObInsertObject ((PVOID)Timer,
- NULL,
- DesiredAccess,
- 0,
- NULL,
- &hTimer);
- ObDereferenceObject(Timer);
-
- if(NT_SUCCESS(Status))
- {
- _SEH_TRY
- {
- *TimerHandle = hTimer;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- }
- }
-
- return Status;
+ /* Return to Caller */
+ return Status;
}
-NTSTATUS STDCALL
+NTSTATUS
+STDCALL
NtOpenTimer(OUT PHANDLE TimerHandle,
- IN ACCESS_MASK DesiredAccess,
- IN POBJECT_ATTRIBUTES ObjectAttributes)
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes)
{
- HANDLE hTimer;
- KPROCESSOR_MODE PreviousMode;
- NTSTATUS Status = STATUS_SUCCESS;
+ HANDLE hTimer;
+ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ NTSTATUS Status = STATUS_SUCCESS;
- DPRINT("NtOpenTimer()\n");
+ DPRINT("NtOpenTimer(TimerHandle: %x)\n", TimerHandle);
- PreviousMode = ExGetPreviousMode();
+ /* Check Parameter Validity */
+ if (PreviousMode != KernelMode) {
+ _SEH_TRY {
+ ProbeForWrite(TimerHandle,
+ sizeof(HANDLE),
+ sizeof(ULONG));
+ } _SEH_HANDLE {
+ Status = _SEH_GetExceptionCode();
+ } _SEH_END;
+
+ if(!NT_SUCCESS(Status)) {
+ return Status;
+ }
+ }
- if(PreviousMode != KernelMode)
- {
- _SEH_TRY
- {
- ProbeForWrite(TimerHandle,
- sizeof(HANDLE),
- sizeof(ULONG));
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
+ /* Open the Timer */
+ Status = ObOpenObjectByName(ObjectAttributes,
+ ExTimerType,
+ NULL,
+ PreviousMode,
+ DesiredAccess,
+ NULL,
+ &hTimer);
+
+ /* Check for success */
+ if(NT_SUCCESS(Status)) {
+
+ /* Make sure it's safe to write to the handle */
+ _SEH_TRY {
+ *TimerHandle = hTimer;
+ } _SEH_HANDLE {
+ Status = _SEH_GetExceptionCode();
+ } _SEH_END;
+ }
- if(!NT_SUCCESS(Status))
- {
- return Status;
- }
- }
-
- Status = ObOpenObjectByName(ObjectAttributes,
- ExTimerType,
- NULL,
- PreviousMode,
- DesiredAccess,
- NULL,
- &hTimer);
- if(NT_SUCCESS(Status))
- {
- _SEH_TRY
- {
- *TimerHandle = hTimer;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- }
-
- return Status;
+ /* Return to Caller */
+ return Status;
}
-NTSTATUS STDCALL
+NTSTATUS
+STDCALL
NtQueryTimer(IN HANDLE TimerHandle,
- IN TIMER_INFORMATION_CLASS TimerInformationClass,
- OUT PVOID TimerInformation,
- IN ULONG TimerInformationLength,
- OUT PULONG ReturnLength OPTIONAL)
+ IN TIMER_INFORMATION_CLASS TimerInformationClass,
+ OUT PVOID TimerInformation,
+ IN ULONG TimerInformationLength,
+ OUT PULONG ReturnLength OPTIONAL)
{
- PNTTIMER Timer;
- KPROCESSOR_MODE PreviousMode;
- NTSTATUS Status = STATUS_SUCCESS;
+ PETIMER Timer;
+ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ NTSTATUS Status = STATUS_SUCCESS;
+ PTIMER_BASIC_INFORMATION BasicInfo =
(PTIMER_BASIC_INFORMATION)TimerInformation;
- PreviousMode = ExGetPreviousMode();
+ DPRINT("NtQueryTimer(TimerHandle: %x, Class: %d)\n", TimerHandle,
TimerInformationClass);
+
+ /* Check Validity */
+ DefaultQueryInfoBufferCheck(TimerInformationClass,
+ ExTimerInfoClass,
+ TimerInformation,
+ TimerInformationLength,
+ ReturnLength,
+ PreviousMode,
+ &Status);
+ if(!NT_SUCCESS(Status)) {
+
+ DPRINT1("NtQueryTimer() failed, Status: 0x%x\n", Status);
+ return Status;
+ }
- DefaultQueryInfoBufferCheck(TimerInformationClass,
- ExTimerInfoClass,
- TimerInformation,
- TimerInformationLength,
- ReturnLength,
- PreviousMode,
- &Status);
- if(!NT_SUCCESS(Status))
- {
- DPRINT1("NtQueryTimer() failed, Status: 0x%x\n", Status);
- return Status;
- }
+ /* Get the Timer Object */
+ Status = ObReferenceObjectByHandle(TimerHandle,
+ TIMER_QUERY_STATE,
+ ExTimerType,
+ PreviousMode,
+ (PVOID*)&Timer,
+ NULL);
+
+ /* Check for Success */
+ if(NT_SUCCESS(Status)) {
+
+ switch(TimerInformationClass) {
+ case TimerBasicInformation: {
+ /* Return the Basic Information */
+ _SEH_TRY {
- Status = ObReferenceObjectByHandle(TimerHandle,
- TIMER_QUERY_STATE,
- ExTimerType,
- PreviousMode,
- (PVOID*)&Timer,
- NULL);
- if(NT_SUCCESS(Status))
- {
- switch(TimerInformationClass)
- {
- case TimerBasicInformation:
- {
- PTIMER_BASIC_INFORMATION BasicInfo =
(PTIMER_BASIC_INFORMATION)TimerInformation;
+ /* FIXME: Interrupt correction based on Interrupt
Time */
+ DPRINT("Returning Information for Timer: %x. Time
Remaining: %d\n", Timer, Timer->KeTimer.DueTime.QuadPart);
+ BasicInfo->TimeRemaining.QuadPart =
Timer->KeTimer.DueTime.QuadPart;
+ BasicInfo->SignalState =
KeReadStateTimer(&Timer->KeTimer);
- _SEH_TRY
- {
- /* FIXME - interrupt correction */
- BasicInfo->TimeRemaining.QuadPart =
Timer->Timer.DueTime.QuadPart;
- BasicInfo->SignalState =
(BOOLEAN)Timer->Timer.Header.SignalState;
+ if(ReturnLength != NULL) {
+ *ReturnLength = sizeof(TIMER_BASIC_INFORMATION);
+ }
- if(ReturnLength != NULL)
- {
- *ReturnLength = sizeof(TIMER_BASIC_INFORMATION);
+ } _SEH_HANDLE {
+ Status = _SEH_GetExceptionCode();
+ } _SEH_END;
}
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- break;
- }
-
- default:
- Status = STATUS_NOT_IMPLEMENTED;
- break;
- }
-
- ObDereferenceObject(Timer);
- }
-
- return Status;
+ }
+
+ ObDereferenceObject(Timer);
+ }
+
+ /* Return Status */
+ return Status;
}
-
-NTSTATUS STDCALL
+NTSTATUS
+STDCALL
NtSetTimer(IN HANDLE TimerHandle,
- IN PLARGE_INTEGER DueTime,
- IN PTIMER_APC_ROUTINE TimerApcRoutine OPTIONAL,
- IN PVOID TimerContext OPTIONAL,
- IN BOOLEAN ResumeTimer,
- IN LONG Period OPTIONAL,
- OUT PBOOLEAN PreviousState OPTIONAL)
+ IN PLARGE_INTEGER DueTime,
+ IN PTIMER_APC_ROUTINE TimerApcRoutine OPTIONAL,
+ IN PVOID TimerContext OPTIONAL,
+ IN BOOLEAN WakeTimer,
+ IN LONG Period OPTIONAL,
+ OUT PBOOLEAN PreviousState OPTIONAL)
{
- PNTTIMER Timer;
- BOOLEAN Result;
- BOOLEAN State;
- LARGE_INTEGER TimerDueTime;
- KPROCESSOR_MODE PreviousMode;
- NTSTATUS Status = STATUS_SUCCESS;
+ PETIMER Timer;
+ KIRQL OldIrql;
+ BOOLEAN KillTimer = FALSE;
+ BOOLEAN State;
+ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ PETHREAD CurrentThread = PsGetCurrentThread();
+ NTSTATUS Status = STATUS_SUCCESS;
+ LARGE_INTEGER TimerDueTime;
+ PETHREAD TimerThread;
- DPRINT("NtSetTimer()\n");
+ DPRINT("NtSetTimer(TimerHandle: %x, DueTime: %d, Apc: %x, Period:
%d)\n", TimerHandle, DueTime->QuadPart, TimerApcRoutine, Period);
- PreviousMode = ExGetPreviousMode();
+ /* Check Parameter Validity */
+ if (PreviousMode != KernelMode) {
+ _SEH_TRY {
+ ProbeForRead(DueTime,
+ sizeof(LARGE_INTEGER),
+ sizeof(ULONG));
+ TimerDueTime = *DueTime;
+
+ if(PreviousState != NULL) {
+ ProbeForWrite(PreviousState,
+ sizeof(BOOLEAN),
+ sizeof(BOOLEAN));
+ }
+
+ } _SEH_HANDLE {
+ Status = _SEH_GetExceptionCode();
+ } _SEH_END;
+
+ if(!NT_SUCCESS(Status)) {
+ return Status;
+ }
+ }
+
+ /* Get the Timer Object */
+ Status = ObReferenceObjectByHandle(TimerHandle,
+ TIMER_ALL_ACCESS,
+ ExTimerType,
+ PreviousMode,
+ (PVOID*)&Timer,
+ NULL);
+
+ /* Check status */
+ if (NT_SUCCESS(Status)) {
+
+ /* Lock the Timer */
+ DPRINT("Timer Referencced: %x\n", Timer);
+ KeAcquireSpinLock(&Timer->Lock, &OldIrql);
+
+ /* Cancel Running Timer */
+ if (Timer->ApcAssociated) {
+
+ /*
+ * First, remove it from the Thread's Active List
+ * Get the Thread.
+ */
+ TimerThread = CONTAINING_RECORD(Timer->TimerApc.Thread,
ETHREAD, Tcb);
+ DPRINT("Thread already running. Removing from Thread:
%x\n", TimerThread);
+
+ /* Lock its active list */
+
KeAcquireSpinLockAtDpcLevel(&TimerThread->ActiveTimerListLock);
+
+ /* Remove it */
+ RemoveEntryList(&TimerThread->ActiveTimerListHead);
+
+ /* Unlock the list */
+
KeReleaseSpinLockFromDpcLevel(&TimerThread->ActiveTimerListLock);
+
+ /* Cancel the Timer */
+ KeCancelTimer(&Timer->KeTimer);
+ KeRemoveQueueDpc(&Timer->TimerDpc);
+ KeRemoveQueueApc(&Timer->TimerApc);
+ Timer->ApcAssociated = FALSE;
+ KillTimer = TRUE;
+
+ } else {
+
+ /* If timer was disabled, we still need to cancel it */
+ DPRINT("No APCs. Simply cancelling\n");
+ KeCancelTimer(&Timer->KeTimer);
+ }
+
+ /* Read the State */
+ State = KeReadStateTimer(&Timer->KeTimer);
- if(PreviousMode != KernelMode)
- {
- _SEH_TRY
- {
- ProbeForRead(DueTime,
- sizeof(LARGE_INTEGER),
- sizeof(ULONG));
- TimerDueTime = *DueTime;
+ /* Handle Wake Timers */
+ DPRINT("Doing Wake Semantics\n");
+ KeAcquireSpinLockAtDpcLevel(&ExpWakeListLock);
+ if (WakeTimer) {
+
+ /* Insert it into the list */
+ InsertTailList(&ExpWakeList, &Timer->WakeTimerListEntry);
+
[truncated at 1000 lines; 1583 more skipped]