convert DefaultSetInfoBufferCheck and DefaultQueryInfoBufferCheck to inlined functions
[reactos.git] / reactos / ntoskrnl / ex / timer.c
index dd3a665..d89cc50 100644 (file)
-/* $Id: nttimer.c 12779 2005-01-04 04:45:00Z gdalsnes $
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/ex/timer.c
- * PURPOSE:         User-mode timers
- * PROGRAMMER:      David Welch (welch@mcmail.com)
- * UPDATE HISTORY:
- *                  Created 22/05/98
+ * PURPOSE:         Executive Timer Implementation
+ *
+ * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
+ *                  David Welch (welch@mcmail.com)
  */
 
 /* INCLUDES *****************************************************************/
 
 #include <ntoskrnl.h>
+#define NDEBUG
 #include <internal/debug.h>
 
-
 /* TYPES ********************************************************************/
 
-typedef struct _NTTIMER
+/* Executive Timer Object */
+typedef struct _ETIMER
 {
-   KTIMER Timer;
-   KDPC Dpc;
-   KAPC Apc;
-   BOOLEAN Running;
-} NTTIMER, *PNTTIMER;
-
+    KTIMER KeTimer;
+    KAPC TimerApc;
+    KDPC TimerDpc;
+    LIST_ENTRY ActiveTimerListEntry;
+    KSPIN_LOCK Lock;
+    BOOLEAN ApcAssociated;
+    BOOLEAN WakeTimer;
+    LIST_ENTRY WakeTimerListEntry;
+} ETIMER, *PETIMER;
 
 /* GLOBALS ******************************************************************/
 
+/* Timer Object Type */
 POBJECT_TYPE ExTimerType = NULL;
 
-static GENERIC_MAPPING ExpTimerMapping = {
-       STANDARD_RIGHTS_READ | TIMER_QUERY_STATE,
-       STANDARD_RIGHTS_WRITE | TIMER_MODIFY_STATE,
-       STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
-       TIMER_ALL_ACCESS};
+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
+};
 
+/* Timer Information Classes */
 static const INFORMATION_CLASS_INFO ExTimerInfoClass[] =
 {
-  ICI_SQ_SAME( sizeof(TIMER_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* TimerBasicInformation */
+    /* 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)
+VOID
+STDCALL
+ExTimerRundown(VOID)
 {
-  DPRINT("ExpCreateTimer(ObjectBody %x, Parent %x, RemainingPath %S)\n",
-        ObjectBody, Parent, RemainingPath);
+    PETHREAD Thread = PsGetCurrentThread();
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentEntry;
+    PETIMER Timer;
+
+    /* Lock the Thread's Active Timer List*/
+    KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql);
 
-  if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
+    while (!IsListEmpty(&Thread->ActiveTimerListHead))
     {
-      return(STATUS_UNSUCCESSFUL);
-    }
+        /* Remove a Timer */
+        CurrentEntry = RemoveTailList(&Thread->ActiveTimerListHead);
 
-  return(STATUS_SUCCESS);
-}
+        /* Get the Timer */
+        Timer = CONTAINING_RECORD(CurrentEntry, ETIMER, ActiveTimerListEntry);
+        DPRINT("Timer, ThreadList: 0x%p, 0x%p\n", Timer, Thread);
 
+        /* Mark it as deassociated */
+        ASSERT (Timer->ApcAssociated);
+        Timer->ApcAssociated = FALSE;
 
-VOID STDCALL
-ExpDeleteTimer(PVOID ObjectBody)
-{
-   KIRQL OldIrql;
-   PNTTIMER Timer = ObjectBody;
+        /* Unlock the list */
+        KeReleaseSpinLockFromDpcLevel(&Thread->ActiveTimerListLock);
+
+        /* Lock the Timer */
+        KeAcquireSpinLockAtDpcLevel(&Timer->Lock);
 
-   DPRINT("ExpDeleteTimer()\n");
+        /* Cancel the timer and remove its DPC and APC */
+        ASSERT(&Thread->Tcb == Timer->TimerApc.Thread);
+        KeCancelTimer(&Timer->KeTimer);
+        KeRemoveQueueDpc(&Timer->TimerDpc);
+        KeRemoveQueueApc(&Timer->TimerApc);
 
-   OldIrql = KeRaiseIrqlToDpcLevel();
+        /* Unlock the Timer */
+        KeReleaseSpinLock(&Timer->Lock, OldIrql);
 
-   KeCancelTimer(&Timer->Timer);
-   KeRemoveQueueDpc(&Timer->Dpc);
-   KeRemoveQueueApc(&Timer->Apc);
-   Timer->Running = FALSE;
+        /* Dereference it */
+        ObDereferenceObject(Timer);
+
+        /* Loop again */
+        KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql);
+    }
 
-   KeLowerIrql(OldIrql);
+    /* Release lock and return */
+    KeReleaseSpinLock(&Thread->ActiveTimerListLock, OldIrql);
+    return;
 }
 
+VOID
+STDCALL
+ExpDeleteTimer(PVOID ObjectBody)
+{
+    KIRQL OldIrql;
+    PETIMER Timer = ObjectBody;
+    DPRINT("ExpDeleteTimer(Timer: 0x%p)\n", Timer);
+
+    /* Check if it has a Wait List */
+    if (Timer->WakeTimer)
+    {
+        /* Lock the Wake List */
+        KeAcquireSpinLock(&ExpWakeListLock, &OldIrql);
+
+        /* Check again, since it might've changed before we locked */
+        if (Timer->WakeTimer)
+        {
+            /* Remove it from the Wait List */
+            DPRINT("Removing wake list\n");
+            RemoveEntryList(&Timer->WakeTimerListEntry);
+            Timer->WakeTimer = FALSE;
+        }
+
+        /* Release the Wake List */
+        KeReleaseSpinLock(&ExpWakeListLock, 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(Dpc: 0x%p)\n", Dpc);
+
+    /* Get the Timer Object */
+    Timer = (PETIMER)DeferredContext;
 
-   DPRINT("ExpTimerDpcRoutine()\n");
+    /* Lock the Timer */
+    KeAcquireSpinLock(&Timer->Lock, &OldIrql);
 
-   Timer = (PNTTIMER)DeferredContext;
+    /* Queue the APC */
+    if(Timer->ApcAssociated)
+    {
+        DPRINT("Queuing APC\n");
+        KeInsertQueueApc(&Timer->TimerApc,
+                         SystemArgument1,
+                         SystemArgument2,
+                         IO_NO_INCREMENT);
+    }
 
-   if ( Timer->Running )
-     {
-       KeInsertQueueApc(&Timer->Apc,
-                       SystemArgument1,
-                       SystemArgument2,
-                       IO_NO_INCREMENT);
-     }
+    /* Release the Timer */
+    KeReleaseSpinLock(&Timer->Lock, OldIrql);
+    return;
 }
 
 
-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;
+    KIRQL OldIrql;
+    PETHREAD CurrentThread = PsGetCurrentThread();
+
+    /* We need to find out which Timer we are */
+    Timer = CONTAINING_RECORD(Apc, ETIMER, TimerApc);
+    DPRINT("ExpTimerApcKernelRoutine(Apc: 0x%p. Timer: 0x%p)\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->KeTimer.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);
 
-VOID INIT_FUNCTION
+        /* Dereference the Timer Object */
+        ObDereferenceObject(Timer);
+        return;
+    }
+
+    /* Release spinlocks */
+    KeReleaseSpinLockFromDpcLevel(&CurrentThread->ActiveTimerListLock);
+    KeReleaseSpinLock(&Timer->Lock, OldIrql);
+}
+
+VOID
+INIT_FUNCTION
+STDCALL
 ExpInitializeTimerImplementation(VOID)
 {
-   ASSERT(!ExTimerType)
-   ExTimerType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
-
-   RtlCreateUnicodeString(&ExTimerType->TypeName, L"Timer");
-
-   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);
+    OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
+    UNICODE_STRING Name;
+
+    DPRINT("Creating Timer Object Type\n");
+  
+    /* Create the Event Pair Object Type */
+    RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
+    RtlInitUnicodeString(&Name, L"Timer");
+    ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
+    ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
+    ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(ETIMER);
+    ObjectTypeInitializer.GenericMapping = ExpTimerMapping;
+    ObjectTypeInitializer.PoolType = NonPagedPool;
+    ObjectTypeInitializer.ValidAccessMask = TIMER_ALL_ACCESS;
+    ObjectTypeInitializer.DeleteProcedure = ExpDeleteTimer;
+    ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &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;
-   
-   PreviousMode = ExGetPreviousMode();
-   
-   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;
-     
-     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();
-
-     State = KeCancelTimer(&Timer->Timer);
-     KeRemoveQueueDpc(&Timer->Dpc);
-     KeRemoveQueueApc(&Timer->Apc);
-     Timer->Running = FALSE;
-
-     KeLowerIrql(OldIrql);
-     ObDereferenceObject(Timer);
-
-     if(CurrentState != NULL)
-     {
-       _SEH_TRY
-       {
-         *CurrentState = State;
-       }
-       _SEH_HANDLE
-       {
-         Status = _SEH_GetExceptionCode();
-       }
-       _SEH_END;
-     }
-   }
-
-   return Status;
-}
+    PETIMER Timer;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    BOOLEAN State;
+    KIRQL OldIrql;
+    PETHREAD TimerThread;
+    BOOLEAN KillTimer = FALSE;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PAGED_CODE();
+    DPRINT("NtCancelTimer(0x%p, 0x%x)\n", TimerHandle, CurrentState);
+
+    /* Check Parameter Validity */
+    if(CurrentState && PreviousMode != KernelMode)
+    {
+        _SEH_TRY
+        {
+            ProbeForWriteBoolean(CurrentState);
+        }
+        _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+
+        if(!NT_SUCCESS(Status)) return Status;
+    }
+
+    /* Get the Timer Object */
+    Status = ObReferenceObjectByHandle(TimerHandle,
+                                       TIMER_MODIFY_STATE,
+                                       ExTimerType,
+                                       PreviousMode,
+                                       (PVOID*)&Timer,
+                                       NULL);
+
+    /* Check for success */
+    if(NT_SUCCESS(Status))
+    {
+        DPRINT("Timer Referenced: 0x%p\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: 0x%p\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);
+        }
+
+        /* Handle a Wake Timer */
+        if (Timer->WakeTimer)
+        {
+            /* Lock the Wake List */
+            KeAcquireSpinLockAtDpcLevel(&ExpWakeListLock);
+
+            /* Check again, since it might've changed before we locked */
+            if (Timer->WakeTimer)
+            {
+                /* Remove it from the Wait List */
+                DPRINT("Removing wake list\n");
+                RemoveEntryList(&Timer->WakeTimerListEntry);
+                Timer->WakeTimer = FALSE;
+            }
+
+            /* Release the Wake List */
+            KeReleaseSpinLockFromDpcLevel(&ExpWakeListLock);
+        }
+
+        /* Unlock the Timer */
+        KeReleaseSpinLock(&Timer->Lock, OldIrql);
+
+        /* Read the old State */
+        State = KeReadStateTimer(&Timer->KeTimer);
+
+        /* Dereference the Object */
+        ObDereferenceObject(Timer);
+
+        /* Dereference if it was previously enabled */
+        if (KillTimer) ObDereferenceObject(Timer);
+        DPRINT1("Timer disabled\n");
+
+        /* Make sure it's safe to write to the handle */
+        if(CurrentState)
+        {
+            _SEH_TRY
+            {
+                *CurrentState = State;
+            }
+            _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+            {
+                Status = _SEH_GetExceptionCode();
+            }
+            _SEH_END;
+        }
+    }
 
+    /* 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;
-   
-   DPRINT("NtCreateTimer()\n");
-   
-   PreviousMode = ExGetPreviousMode();
-   
-   if(PreviousMode != KernelMode)
-   {
-     _SEH_TRY
-     {
-       ProbeForWrite(TimerHandle,
-                     sizeof(HANDLE),
-                     sizeof(ULONG));
-     }
-     _SEH_HANDLE
-     {
-       Status = _SEH_GetExceptionCode();
-     }
-     _SEH_END;
-
-     if(!NT_SUCCESS(Status))
-     {
-       return Status;
-     }
-   }
-
-   Status = ObCreateObject(PreviousMode,
-                          ExTimerType,
-                          ObjectAttributes,
-                          PreviousMode,
-                          NULL,
-                          sizeof(NTTIMER),
-                          0,
-                          0,
-                          (PVOID*)&Timer);
-   if(NT_SUCCESS(Status))
-   {
-     KeInitializeTimerEx(&Timer->Timer,
-                        TimerType);
-
-     KeInitializeDpc(&Timer->Dpc,
-                    &ExpTimerDpcRoutine,
-                    Timer);
-
-     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;
-}
+    PETIMER Timer;
+    HANDLE hTimer;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
+    PAGED_CODE();
+    DPRINT("NtCreateTimer(Handle: 0x%p, Type: %d)\n", TimerHandle, TimerType);
+
+    /* Check Parameter Validity */
+    if (PreviousMode != KernelMode)
+    {
+        _SEH_TRY
+        {
+            ProbeForWriteHandle(TimerHandle);
+        }
+        _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+
+        if(!NT_SUCCESS(Status)) return Status;
+    }
 
+    /* Check for correct timer type */
+    if ((TimerType != NotificationTimer) && (TimerType != SynchronizationTimer))
+    {
+        DPRINT1("Invalid Timer Type!\n");
+        return STATUS_INVALID_PARAMETER_4;
+    }
 
-NTSTATUS STDCALL
+    /* Create the Object */
+    Status = ObCreateObject(PreviousMode,
+                            ExTimerType,
+                            ObjectAttributes,
+                            PreviousMode,
+                            NULL,
+                            sizeof(ETIMER),
+                            0,
+                            0,
+                            (PVOID*)&Timer);
+
+    /* Check for Success */
+    if(NT_SUCCESS(Status))
+    {
+        /* Initialize the Kernel Timer */
+        DPRINT("Initializing Timer: 0x%p\n", Timer);
+        KeInitializeTimerEx(&Timer->KeTimer, TimerType);
+
+        /* Initialize the Timer Lock */
+        KeInitializeSpinLock(&Timer->Lock);
+
+        /* Initialize the DPC */
+        KeInitializeDpc(&Timer->TimerDpc, ExpTimerDpcRoutine, Timer);
+
+        /* Set Initial State */
+        Timer->ApcAssociated = FALSE;
+        Timer->WakeTimer = FALSE;
+
+        /* Insert the Timer */
+        Status = ObInsertObject((PVOID)Timer,
+                                NULL,
+                                DesiredAccess,
+                                0,
+                                NULL,
+                                &hTimer);
+        DPRINT("Timer Inserted\n");
+
+        /* Make sure it's safe to write to the handle */
+        _SEH_TRY
+        {
+            *TimerHandle = hTimer;
+        }
+        _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+    }
+
+    /* Return to Caller */
+    return Status;
+}
+
+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;
-
-   DPRINT("NtOpenTimer()\n");
-
-   PreviousMode = ExGetPreviousMode();
-
-   if(PreviousMode != KernelMode)
-   {
-     _SEH_TRY
-     {
-       ProbeForWrite(TimerHandle,
-                     sizeof(HANDLE),
-                     sizeof(ULONG));
-     }
-     _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;
+    HANDLE hTimer;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
+    PAGED_CODE();
+    DPRINT("NtOpenTimer(TimerHandle: 0x%p)\n", TimerHandle);
+
+    /* Check Parameter Validity */
+    if (PreviousMode != KernelMode)
+    {
+        _SEH_TRY
+        {
+            ProbeForWriteHandle(TimerHandle);
+        }
+        _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+
+        if(!NT_SUCCESS(Status)) return Status;
+    }
+
+    /* 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_EXCEPT(_SEH_ExSystemExceptionFilter)
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+    }
+
+    /* 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;
-
-   PreviousMode = ExGetPreviousMode();
-
-   DefaultQueryInfoBufferCheck(TimerInformationClass,
-                               ExTimerInfoClass,
-                               TimerInformation,
-                               TimerInformationLength,
-                               ReturnLength,
-                               PreviousMode,
-                               &Status);
-   if(!NT_SUCCESS(Status))
-   {
-     DPRINT1("NtQueryTimer() failed, Status: 0x%x\n", Status);
-     return Status;
-   }
-
-   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;
-
-         _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);
-           }
-         }
-         _SEH_HANDLE
-         {
-           Status = _SEH_GetExceptionCode();
-         }
-         _SEH_END;
-         break;
-       }
+    PETIMER Timer;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
+    PTIMER_BASIC_INFORMATION BasicInfo = (PTIMER_BASIC_INFORMATION)TimerInformation;
+    PAGED_CODE();
+    DPRINT("NtQueryTimer(TimerHandle: 0x%p, Class: %d)\n", TimerHandle, TimerInformationClass);
+
+    /* Check Validity */
+    Status = DefaultQueryInfoBufferCheck(TimerInformationClass,
+                                         ExTimerInfoClass,
+                                         sizeof(ExTimerInfoClass) / sizeof(ExTimerInfoClass[0]),
+                                         TimerInformation,
+                                         TimerInformationLength,
+                                         ReturnLength,
+                                         PreviousMode);
+    if(!NT_SUCCESS(Status))
+    {
+        DPRINT1("NtQueryTimer() failed, Status: 0x%x\n", Status);
+        return Status;
+    }
 
-       default:
-         Status = STATUS_NOT_IMPLEMENTED;
-         break;
-     }
+    /* Get the Timer Object */
+    Status = ObReferenceObjectByHandle(TimerHandle,
+                                       TIMER_QUERY_STATE,
+                                       ExTimerType,
+                                       PreviousMode,
+                                       (PVOID*)&Timer,
+                                       NULL);
 
-     ObDereferenceObject(Timer);
-   }
+    /* Check for Success */
+    if(NT_SUCCESS(Status))
+    {
+        /* Return the Basic Information */
+        _SEH_TRY
+        {
+            /* Return the remaining time, corrected */
+            BasicInfo->TimeRemaining.QuadPart = Timer->KeTimer.DueTime.QuadPart -
+                                                KeQueryInterruptTime();
+
+            /* Return the current state */
+            BasicInfo->SignalState = KeReadStateTimer(&Timer->KeTimer);
+
+            /* Return the buffer length if requested */
+            if(ReturnLength != NULL) *ReturnLength = sizeof(TIMER_BASIC_INFORMATION);
+
+            DPRINT("Returning Information for Timer: 0x%p. Time Remaining: %I64x\n",
+                    Timer, BasicInfo->TimeRemaining.QuadPart);
+        }
+        _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+
+        /* Dereference Object */
+        ObDereferenceObject(Timer);
+    }
 
-   return Status;
+    /* 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;
-
-   DPRINT("NtSetTimer()\n");
-
-   PreviousMode = ExGetPreviousMode();
-
-   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;
-     }
-   }
-
-   Status = ObReferenceObjectByHandle(TimerHandle,
-                                     TIMER_ALL_ACCESS,
-                                     ExTimerType,
-                                     PreviousMode,
-                                     (PVOID*)&Timer,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       return Status;
-     }
-
-   State = KeReadStateTimer(&Timer->Timer);
-
-   if (Timer->Running == TRUE)
-     {
-       /* cancel running timer */
-       const KIRQL OldIrql = KeRaiseIrqlToDpcLevel();
-       KeCancelTimer(&Timer->Timer);
-       KeRemoveQueueDpc(&Timer->Dpc);
-       KeRemoveQueueApc(&Timer->Apc);
-       Timer->Running = FALSE;
-       KeLowerIrql(OldIrql);
-     }
-
-   if (TimerApcRoutine)
-     {
-       KeInitializeApc(&Timer->Apc,
-                      KeGetCurrentThread(),
-                      OriginalApcEnvironment,
-                      &ExpTimerApcKernelRoutine,
-                      (PKRUNDOWN_ROUTINE)NULL,
-                      (PKNORMAL_ROUTINE)TimerApcRoutine,
-                      PreviousMode,
-                      TimerContext);
-     }
-
-   Result = KeSetTimerEx(&Timer->Timer,
-                        TimerDueTime,
-                        Period,
-                        TimerApcRoutine ? &Timer->Dpc : 0 );
-   if (Result)
-     {
-       ObDereferenceObject(Timer);
-       DPRINT1( "KeSetTimer says the timer was already running, this shouldn't be\n" );
-       return STATUS_UNSUCCESSFUL;
-     }
-
-   Timer->Running = TRUE;
-
-   ObDereferenceObject(Timer);
-
-   if (PreviousState != NULL)
-   {
-     _SEH_TRY
-     {
-       *PreviousState = State;
-     }
-     _SEH_HANDLE
-     {
-       Status = _SEH_GetExceptionCode();
-     }
-     _SEH_END;
-   }
-
-   return Status;
+    PETIMER Timer;
+    KIRQL OldIrql;
+    BOOLEAN State;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    PETHREAD CurrentThread = PsGetCurrentThread();
+    LARGE_INTEGER TimerDueTime;
+    PETHREAD TimerThread;
+    BOOLEAN KillTimer = FALSE;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PAGED_CODE();
+    DPRINT("NtSetTimer(TimerHandle: 0x%p, DueTime: %I64x, Apc: 0x%p, Period: %d)\n",
+            TimerHandle, DueTime->QuadPart, TimerApcRoutine, Period);
+
+    /* Check Parameter Validity */
+    if (PreviousMode != KernelMode)
+    {
+        _SEH_TRY
+        {
+            TimerDueTime = ProbeForReadLargeInteger(DueTime);
+
+            if(PreviousState)
+            {
+                ProbeForWriteBoolean(PreviousState);
+            }
+        }
+        _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+
+        if(!NT_SUCCESS(Status)) return Status;
+    }
+
+    /* Check for a valid Period */
+    if (Period < 0)
+    {
+        DPRINT1("Invalid Period for timer\n");
+        return STATUS_INVALID_PARAMETER_6;
+    }
+
+    /* Get the Timer Object */
+    Status = ObReferenceObjectByHandle(TimerHandle,
+                                       TIMER_MODIFY_STATE,
+                                       ExTimerType,
+                                       PreviousMode,
+                                       (PVOID*)&Timer,
+                                       NULL);
+
+    /* 
+     * Tell the user we don't support Wake Timers...
+     * when we have the ability to use/detect the Power Management 
+     * functionatliy required to support them, make this check dependent
+     * on the actual PM capabilities
+     */
+    if (WakeTimer) Status = STATUS_TIMER_RESUME_IGNORED;
+
+    /* Check status */
+    if (NT_SUCCESS(Status))
+    {
+        /* Lock the Timer */
+        DPRINT("Timer Referencced: 0x%p\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: 0x%p\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);
+
+        /* Handle Wake Timers */
+        DPRINT("Doing Wake Semantics\n");
+        KeAcquireSpinLockAtDpcLevel(&ExpWakeListLock);
+        if (WakeTimer && !Timer->WakeTimer)
+        {
+            /* Insert it into the list */
+            Timer->WakeTimer = TRUE;
+            InsertTailList(&ExpWakeList, &Timer->WakeTimerListEntry);
+        }
+        else if (!WakeTimer && Timer->WakeTimer)
+        {
+            /* Remove it from the list */
+            RemoveEntryList(&Timer->WakeTimerListEntry);
+            Timer->WakeTimer = FALSE;
+        }
+        KeReleaseSpinLockFromDpcLevel(&ExpWakeListLock);
+
+        /* Set up the APC Routine if specified */
+        if (TimerApcRoutine)
+        {
+            /* Initialize the APC */
+            DPRINT("Initializing APC: 0x%p\n", Timer->TimerApc);
+            KeInitializeApc(&Timer->TimerApc,
+                            &CurrentThread->Tcb,
+                            CurrentApcEnvironment,
+                            &ExpTimerApcKernelRoutine,
+                            (PKRUNDOWN_ROUTINE)NULL,
+                            (PKNORMAL_ROUTINE)TimerApcRoutine,
+                            PreviousMode,
+                            TimerContext);
+
+            /* Lock the Thread's Active List and Insert */
+            KeAcquireSpinLockAtDpcLevel(&CurrentThread->ActiveTimerListLock);
+            InsertTailList(&CurrentThread->ActiveTimerListHead,
+                           &Timer->ActiveTimerListEntry);
+            KeReleaseSpinLockFromDpcLevel(&CurrentThread->ActiveTimerListLock);
+
+         }
+
+        /* Enable and Set the Timer */
+        DPRINT("Setting Kernel Timer\n");
+        KeSetTimerEx(&Timer->KeTimer,
+                     TimerDueTime,
+                     Period,
+                     TimerApcRoutine ? &Timer->TimerDpc : 0);
+        Timer->ApcAssociated = TimerApcRoutine ? TRUE : FALSE;
+
+        /* Unlock the Timer */
+        KeReleaseSpinLock(&Timer->Lock, OldIrql);
+
+        /* Dereference if it was previously enabled */
+        if (!TimerApcRoutine) ObDereferenceObject(Timer);
+        if (KillTimer) ObDereferenceObject(Timer);
+        DPRINT("Finished Setting the Timer\n");
+
+        /* Make sure it's safe to write to the handle */
+        if(PreviousState != NULL)
+        {
+            _SEH_TRY
+            {
+                *PreviousState = State;
+            }
+            _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+            {
+                Status = _SEH_GetExceptionCode();
+            }
+            _SEH_END;
+        }
+    }
+
+    /* Return to Caller */
+    return Status;
 }
 
 /* EOF */