- 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@mcmail.com) + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Reimplemented + * David Welch (welch@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]