KD System Rewrite:
[reactos.git] / reactos / ntoskrnl / ke / timer.c
index 5911f93..49504f9 100644 (file)
@@ -1,18 +1,11 @@
-/* $Id: timer.c,v 1.92 2004/11/28 12:59:00 ekohl Exp $
- *
- * COPYRIGHT:      See COPYING in the top level directory
- * PROJECT:        ReactOS kernel
- * FILE:           ntoskrnl/ke/timer.c
- * PURPOSE:        Handle timers
- * PROGRAMMER:     David Welch (welch@mcmail.com)
- * UPDATE HISTORY:
- *                 28/05/98: Created
- *                 12/3/99:  Phillip Susi: enabled the timers, fixed spin lock
- */
-
-/* NOTES ******************************************************************/
 /*
- * System time units are 100-nanosecond intervals
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            ntoskrnl/ke/timer.c
+ * PURPOSE:         Handle Kernel Timers (Kernel-part of Executive Timers)
+ * 
+ * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net) - Reimplemented some parts, fixed many bugs.
+ *                  David Welch (welch@mcmail.com) &  Phillip Susi - Original Implementation.
  */
 
 /* INCLUDES ***************************************************************/
 #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;
-
-/*
- * Number of timer interrupts since initialisation
- */
-volatile ULONGLONG KeTickCount = 0;
-volatile ULONG KiRawTicks = 0;
-
-/*
- * 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
-
-
-
-/*
- * PURPOSE: List of timers
- */
-static LIST_ENTRY AbsoluteTimerListHead;
-static LIST_ENTRY RelativeTimerListHead;
-static KSPIN_LOCK TimerListLock;
-static KDPC ExpireTimerDpc;
-
-/* must raise IRQL to PROFILE_LEVEL and grab spin lock there, to sync with ISR */
+LIST_ENTRY KiTimerListHead;
 
-extern HANDLE PsIdleThreadHandle;
-
-#define MICROSECONDS_PER_TICK (10000)
-#define TICKS_TO_CALIBRATE (1)
-#define CALIBRATE_PERIOD (MICROSECONDS_PER_TICK * TICKS_TO_CALIBRATE)
 #define SYSTEM_TIME_UNITS_PER_MSEC (10000)
 
-static BOOLEAN TimerInitDone = FALSE;
-
 /* FUNCTIONS **************************************************************/
 
+BOOLEAN STDCALL KiInsertTimer(PKTIMER Timer, LARGE_INTEGER DueTime);
+VOID STDCALL KiHandleExpiredTimer(PKTIMER Timer);
 
-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;
-}
-
-
-NTSTATUS STDCALL
-NtQueryPerformanceCounter(IN PLARGE_INTEGER Counter,
-                         IN PLARGE_INTEGER Frequency)
+/*
+ * @implemented
+ *
+ * FUNCTION: Removes a timer from the system timer list
+ * ARGUMENTS:
+ *       Timer = timer to cancel
+ * RETURNS: True if the timer was running
+ *          False otherwise
+ */
+BOOLEAN 
+STDCALL
+KeCancelTimer(PKTIMER Timer)
 {
-  LARGE_INTEGER PerfCounter;
-  LARGE_INTEGER PerfFrequency;
-  NTSTATUS      Status;
-
-  PerfCounter = KeQueryPerformanceCounter(&PerfFrequency);
-
-  if (Counter != NULL)
-    {
-      Status = MmCopyToCaller(&Counter->QuadPart, &PerfCounter.QuadPart, sizeof(PerfCounter.QuadPart));
-      if (!NT_SUCCESS(Status))
-        {
-         return(Status);
-        }
+    KIRQL OldIrql;
+    BOOLEAN Inserted = FALSE;
+   
+    DPRINT("KeCancelTimer(Timer %x)\n",Timer);
+
+    /* Lock the Database and Raise IRQL */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    /* Check if it's inserted, and remove it if it is */
+    if ((Inserted = Timer->Header.Inserted)) {
+        
+        /* Remove from list */
+        DPRINT("Timer was inserted, removing\n");
+        RemoveEntryList(&Timer->TimerListEntry);
+        Timer->Header.Inserted = FALSE;
+        
+    } else {
+    
+        DPRINT("Timer was not inserted\n");
     }
 
-  if (Frequency != NULL)
-  {
-      Status = MmCopyToCaller(&Frequency->QuadPart, &PerfFrequency.QuadPart, sizeof(PerfFrequency.QuadPart));
-      if (!NT_SUCCESS(Status))
-        {
-         return(Status);
-        }
-  }
-
-  return(STATUS_SUCCESS);
-}
-
+    /* Release Dispatcher Lock */
+    KeReleaseDispatcherDatabaseLock(OldIrql);
 
-NTSTATUS STDCALL
-NtDelayExecution(IN ULONG Alertable,
-                IN TIME* Interval)
-{
-   NTSTATUS Status;
-   LARGE_INTEGER Timeout;
-
-   Status = MmCopyFromCaller(&Timeout, Interval, sizeof(Timeout));
-   if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-
-   Timeout = *((PLARGE_INTEGER)Interval);
-   DPRINT("NtDelayExecution(Alertable %d, Internal %x) IntervalP %x\n",
-         Alertable, Internal, Timeout);
-   
-   DPRINT("Execution delay is %d/%d\n", 
-         Timeout.u.HighPart, Timeout.u.LowPart);
-   Status = KeDelayExecutionThread(UserMode, (BOOLEAN)Alertable, &Timeout);
-   return(Status);
+    /* Return the old state */
+    DPRINT("Old State: %d\n", Inserted);
+    return(Inserted);
 }
 
-
 /*
  * @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
+ *
+ * FUNCTION: Initalizes a kernel timer object
  * 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
+ *          Timer = caller supplied storage for the timer
+ * NOTE: This function initializes a notification timer
  */
-{
-   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));
-}
-
+VOID 
+STDCALL
+KeInitializeTimer (PKTIMER Timer)
 
-/*
- * @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(CLOCK_INCREMENT);
+    /* Call the New Function */
+    KeInitializeTimerEx(Timer, NotificationTimer);
 }
 
-
 /*
- * 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
+ *
+ * FUNCTION: Initializes a kernel timer object
+ * ARGUMENTS:
+ *          Timer = caller supplied storage for the timer
+ *          Type = the type of timer (notification or synchronization)
+ * NOTE: When a notification type expires all waiting threads are released
+ * and the timer remains signalled until it is explicitly reset. When a 
+ * syncrhonization timer expires its state is set to signalled until a
+ * single waiting thread is released and then the timer is reset.
  */
-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)
+VOID 
+STDCALL
+KeInitializeTimerEx (PKTIMER Timer,
+                     TIMER_TYPE Type)
 {
-  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;
+    DPRINT("KeInitializeTimerEx(%x, %d)\n", Timer, Type);
+    
+    /* Initialize the Dispatch Header */
+    KeInitializeDispatcherHeader(&Timer->Header,
+                                 TimerNotificationObject + Type,
+                                 sizeof(KTIMER) / sizeof(ULONG),
+                                 FALSE);
+   
+    /* Initalize the Other data */
+    Timer->DueTime.QuadPart = 0;
+    Timer->Period = 0;
 }
 
+
 /*
  * @implemented
  */
-ULONG
+BOOLEAN 
 STDCALL
-NtGetTickCount(VOID)
+KeReadStateTimer (PKTIMER Timer)
 {
-  LARGE_INTEGER TickCount;
-  KeQueryTickCount(&TickCount);
-  return TickCount.u.LowPart;
+    /* Return the Signal State */
+    return (BOOLEAN)Timer->Header.SignalState;
 }
 
 /*
  * @implemented
- */
-BOOLEAN STDCALL
-KeSetTimer (PKTIMER            Timer,
-           LARGE_INTEGER       DueTime,
-           PKDPC               Dpc)
-/*
+ *
  * FUNCTION: Sets the absolute or relative interval at which a timer object
  * is to be set to the signaled state and optionally supplies a 
  * CustomTimerDpc to be executed when the timer expires.
@@ -269,19 +142,19 @@ KeSetTimer (PKTIMER               Timer,
  * RETURNS: True if the timer was already in the system timer queue
  *          False otherwise
  */
+BOOLEAN 
+STDCALL
+KeSetTimer (PKTIMER Timer,
+            LARGE_INTEGER DueTime,
+            PKDPC Dpc)
 {
-   return(KeSetTimerEx(Timer, DueTime, 0, Dpc));
+    /* Call the newer function and supply a period of 0 */
+    return KeSetTimerEx(Timer, DueTime, 0, Dpc);
 }
 
 /*
  * @implemented
- */
-BOOLEAN STDCALL
-KeSetTimerEx (PKTIMER          Timer,
-             LARGE_INTEGER     DueTime,
-             LONG              Period,
-             PKDPC             Dpc)
-/*
+ *
  * FUNCTION: Sets the absolute or relative interval at which a timer object
  * is to be set to the signaled state and optionally supplies a 
  * CustomTimerDpc to be executed when the timer expires.
@@ -293,586 +166,218 @@ KeSetTimerEx (PKTIMER           Timer,
  * RETURNS: True if the timer was already in the system timer queue
  *          False otherwise
  */
-{
-   KIRQL oldlvl;
-   LARGE_INTEGER Time;
-   BOOLEAN AlreadyInList;
-
-   DPRINT("KeSetTimerEx(Timer %x), DueTime: \n",Timer);
-
-   ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
-
-   KeAcquireSpinLock(&TimerListLock, &oldlvl);
-
-   Timer->Dpc = Dpc;
-   if (DueTime.QuadPart < 0)
-     {
-        Timer->Header.Absolute = 0;
-       Timer->DueTime.QuadPart = KeQueryInterruptTime() - DueTime.QuadPart;
-     }
-   else
-     {
-        KeQuerySystemTime(&Time);
-        Timer->Header.Absolute = 1;
-       if (DueTime.QuadPart >= Time.QuadPart)
-         {
-            Timer->DueTime.QuadPart = DueTime.QuadPart;
-         }
-       else
-         {
-           Timer->DueTime.QuadPart = Time.QuadPart;
-         }
-     }
-   Timer->Period = Period;
-   Timer->Header.SignalState = FALSE;
-   AlreadyInList = (Timer->TimerListEntry.Flink == NULL) ? FALSE : TRUE;
-   ASSERT((Timer->TimerListEntry.Flink == NULL && Timer->TimerListEntry.Blink == NULL) ||
-          (Timer->TimerListEntry.Flink != NULL && Timer->TimerListEntry.Blink != NULL));
-   if (AlreadyInList)
-     {
-       RemoveEntryList(&Timer->TimerListEntry);
-     }
-   if (Timer->Header.Absolute)
-     {
-       InsertAscendingList(&AbsoluteTimerListHead, 
-                           KTIMER,
-                           TimerListEntry, 
-                           Timer,
-                           DueTime.QuadPart);
-
-     }
-   else
-     {
-       InsertAscendingList(&RelativeTimerListHead, 
-                          KTIMER,
-                          TimerListEntry, 
-                          Timer, 
-                          DueTime.QuadPart);
-
-     }
-
-   KeReleaseSpinLock(&TimerListLock, oldlvl);
-
-   return AlreadyInList;
-}
-
-/*
- * @implemented
- */
-BOOLEAN STDCALL
-KeCancelTimer (PKTIMER Timer)
-/*
- * FUNCTION: Removes a timer from the system timer list
- * ARGUMENTS:
- *       Timer = timer to cancel
- * RETURNS: True if the timer was running
- *          False otherwise
- */
-{
-   KIRQL oldlvl;
-   
-   DPRINT("KeCancelTimer(Timer %x)\n",Timer);
-
-   KeAcquireSpinLock(&TimerListLock, &oldlvl);
-
-   if (Timer->TimerListEntry.Flink == NULL)
-     {
-       KeReleaseSpinLock(&TimerListLock, oldlvl);
-       return(FALSE);
-     }
-   if (Timer->Header.Absolute)
-     {
-       ASSERT(&Timer->TimerListEntry != &AbsoluteTimerListHead);
-     }
-   else
-     {
-       ASSERT(&Timer->TimerListEntry != &RelativeTimerListHead);
-     }
-   ASSERT(Timer->TimerListEntry.Flink != &Timer->TimerListEntry);
-   RemoveEntryList(&Timer->TimerListEntry);
-   Timer->TimerListEntry.Flink = Timer->TimerListEntry.Blink = NULL;
-   KeReleaseSpinLock(&TimerListLock, oldlvl);
-
-   return(TRUE);
-}
-
-/*
- * @implemented
- */
-BOOLEAN STDCALL
-KeReadStateTimer (PKTIMER      Timer)
-{
-   return (BOOLEAN)(Timer->Header.SignalState);
-}
-
-/*
- * @implemented
- */
-VOID STDCALL
-KeInitializeTimer (PKTIMER     Timer)
-/*
- * FUNCTION: Initalizes a kernel timer object
- * ARGUMENTS:
- *          Timer = caller supplied storage for the timer
- * NOTE: This function initializes a notification timer
- */
-{
-   KeInitializeTimerEx(Timer, NotificationTimer);
-}
-
-/*
- * @implemented
- */
-VOID STDCALL
-KeInitializeTimerEx (PKTIMER           Timer,
-                    TIMER_TYPE Type)
-/*
- * FUNCTION: Initializes a kernel timer object
- * ARGUMENTS:
- *          Timer = caller supplied storage for the timer
- *          Type = the type of timer (notification or synchronization)
- * NOTE: When a notification type expires all waiting threads are released
- * and the timer remains signalled until it is explicitly reset. When a 
- * syncrhonization timer expires its state is set to signalled until a
- * single waiting thread is released and then the timer is reset.
- */
-{
-   ULONG IType;
-
-   if (Type == NotificationTimer)
-     {
-       IType = InternalNotificationTimer;
-     }
-   else if (Type == SynchronizationTimer)
-     {
-       IType = InternalSynchronizationTimer;
-     }
-   else
-     {
-       ASSERT(FALSE);
-       return;
-     }
-
-   KeInitializeDispatcherHeader(&Timer->Header,
-                               IType,
-                               sizeof(KTIMER) / sizeof(ULONG),
-                               FALSE);
-   Timer->TimerListEntry.Flink = Timer->TimerListEntry.Blink = NULL;
-}
-
-/*
- * @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;
-}
-
-/*
- * @implemented
- */
-ULONG
+BOOLEAN 
 STDCALL
-KeQueryRuntimeThread(
-       IN PKTHREAD Thread,
-       OUT PULONG UserTime
-       )
+KeSetTimerEx (PKTIMER Timer,
+              LARGE_INTEGER DueTime,
+              LONG Period,
+              PKDPC Dpc)
 {
-       /* Return the User Time */
-       *UserTime = Thread->UserTime;
-       
-       /* Return the Kernel Time */
-       return Thread->KernelTime;
+    KIRQL OldIrql;
+    BOOLEAN Inserted;
+
+    DPRINT("KeSetTimerEx(Timer %x, DueTime %I64d, Period %d, Dpc %x)\n", Timer, DueTime.QuadPart, Period, Dpc);
+    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
+
+    /* Lock the Database and Raise IRQL */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    /* Check if it's inserted, and remove it if it is */
+    if ((Inserted = Timer->Header.Inserted)) {
+        
+        /* Remove from list */
+        DPRINT("Timer was already inserted\n");
+        RemoveEntryList(&Timer->TimerListEntry);
+        Timer->Header.Inserted = FALSE;        
+    }
+    
+    /* Set Default Timer Data */ 
+    Timer->Dpc = Dpc;
+    Timer->Period = Period;
+    Timer->Header.SignalState = FALSE;
+    
+    /* Insert it */
+    if (!KiInsertTimer(Timer, DueTime)) {
+
+       KiHandleExpiredTimer(Timer);
+    };
+
+    /* Release Dispatcher Lock */
+    KeReleaseDispatcherDatabaseLock(OldIrql);
+
+    /* Return old state */
+    DPRINT("Old State: %d\n", Inserted);
+    return Inserted;
 }
 
-/*
- * @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;
-}
-
-/*
- * We enter this function at IRQL DISPATCH_LEVEL, and with the
- * TimerListLock held.
- */
-STATIC VOID 
-HandleExpiredTimer(PKTIMER Timer)
+KiExpireTimers(PKDPC Dpc,
+               PVOID DeferredContext,
+               PVOID SystemArgument1,
+               PVOID SystemArgument2)
 {
-   DPRINT("HandleExpiredTime(Timer %x)\n", Timer);
-   if (Timer->Dpc != NULL)
-     {
-       DPRINT("Timer->Dpc %x Timer->Dpc->DeferredRoutine %x\n",
-              Timer->Dpc, Timer->Dpc->DeferredRoutine);
-       KeInsertQueueDpc(Timer->Dpc,
-                        NULL,
-                        NULL);
-       DPRINT("Finished dpc routine\n");
-     }
-
-   ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
-
-   KeAcquireDispatcherDatabaseLockAtDpcLevel();
-   Timer->Header.SignalState = TRUE;
-   KiDispatcherObjectWake(&Timer->Header);
-   KeReleaseDispatcherDatabaseLockFromDpcLevel();
-
-   if (Timer->Period != 0)
-     {
-       Timer->DueTime.QuadPart += 
-        Timer->Period * SYSTEM_TIME_UNITS_PER_MSEC;
-       if (Timer->Header.Absolute)
-         {
-           InsertAscendingList(&AbsoluteTimerListHead, 
-                               KTIMER,
-                               TimerListEntry,
-                               Timer, 
-                                    DueTime.QuadPart);
-         }
-       else
-         {
-           InsertAscendingList(&RelativeTimerListHead, 
-                               KTIMER,
-                               TimerListEntry, 
-                               Timer,
-                                    DueTime.QuadPart);
-         }
-     }
-}
-
-VOID STDCALL
-KeExpireTimers(PKDPC Dpc,
-              PVOID Context1,
-              PVOID Arg1,
-              PVOID Arg2)
-{
-   PLIST_ENTRY current_entry = NULL;
-   PKTIMER current = NULL;
-   ULONG Eip = (ULONG)Arg1;
-   LARGE_INTEGER InterruptTime;
-   LARGE_INTEGER SystemTime;
-   LIST_ENTRY TimerList;
-
-   DPRINT("KeExpireTimers()\n");
-
-   ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
-
-   InitializeListHead(&TimerList);
-
-   KeAcquireSpinLockAtDpcLevel(&TimerListLock);
-
-   InterruptTime.QuadPart = KeQueryInterruptTime();
-   KeQuerySystemTime(&SystemTime);
-
-   current_entry = RelativeTimerListHead.Flink;
-   ASSERT(current_entry);
-   while (current_entry != &RelativeTimerListHead)
-     {
-       current = CONTAINING_RECORD(current_entry, KTIMER, TimerListEntry);
-       ASSERT(current);
-       ASSERT(current_entry != &RelativeTimerListHead);
-       ASSERT(current_entry->Flink != current_entry);
-       if ((ULONGLONG)InterruptTime.QuadPart < current->DueTime.QuadPart)
-         {
-          break;
-        }
-       current_entry = current_entry->Flink;
-       RemoveEntryList(&current->TimerListEntry);
-       InsertTailList(&TimerList, &current->TimerListEntry);
-     }
-
-   current_entry = AbsoluteTimerListHead.Flink;
-   ASSERT(current_entry);
-   while (current_entry != &AbsoluteTimerListHead)
-     {
-       current = CONTAINING_RECORD(current_entry, KTIMER, TimerListEntry);
-       ASSERT(current);
-       ASSERT(current_entry != &AbsoluteTimerListHead);
-       ASSERT(current_entry->Flink != current_entry);
-       if ((ULONGLONG)SystemTime.QuadPart < current->DueTime.QuadPart)
-         {
-          break;
-        }
-       current_entry = current_entry->Flink;
-       RemoveEntryList(&current->TimerListEntry);
-       InsertTailList(&TimerList, &current->TimerListEntry);
-     }
-
-   while (!IsListEmpty(&TimerList))
-     {
-       current_entry = RemoveHeadList(&TimerList);
-       current = CONTAINING_RECORD(current_entry, KTIMER, TimerListEntry);
-       current->TimerListEntry.Flink = current->TimerListEntry.Blink = NULL;
-       HandleExpiredTimer(current);
-     }
-
-   KiAddProfileEvent(ProfileTime, Eip);
-
-   KeReleaseSpinLockFromDpcLevel(&TimerListLock);
-}
+    PKTIMER Timer;
+    ULONGLONG InterruptTime;
+    LIST_ENTRY ExpiredTimerList;
+    PLIST_ENTRY CurrentEntry = NULL;
+    KIRQL OldIrql;
+
+    DPRINT("KiExpireTimers(Dpc: %x)\n", Dpc);
+    
+    /* Initialize the Expired Timer List */
+    InitializeListHead(&ExpiredTimerList);
+
+    /* Lock the Database and Raise IRQL */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+    
+    /* Query Interrupt Times */ 
+    InterruptTime = KeQueryInterruptTime();
+
+    /* Loop through the Timer List and remove Expired Timers. Insert them into the Expired Listhead */
+    CurrentEntry = KiTimerListHead.Flink;
+    while (CurrentEntry != &KiTimerListHead) {
+    
+        /* Get the Current Timer */
+        Timer = CONTAINING_RECORD(CurrentEntry, KTIMER, TimerListEntry);
+        DPRINT("Looping for Timer: %x. Duetime: %I64d. InterruptTime %I64d \n", Timer, Timer->DueTime.QuadPart, InterruptTime);
+        
+        /* Check if we have to Expire it */
+        if (InterruptTime < Timer->DueTime.QuadPart) break;
+        
+        CurrentEntry = CurrentEntry->Flink;
+       
+        /* Remove it from the Timer List, add it to the Expired List */
+        RemoveEntryList(&Timer->TimerListEntry);
+        InsertTailList(&ExpiredTimerList, &Timer->TimerListEntry);
+    }
+    
+    /* Expire the Timers */
+    while ((CurrentEntry = RemoveHeadList(&ExpiredTimerList)) != &ExpiredTimerList) {
+        
+        /* Get the Timer */
+        Timer = CONTAINING_RECORD(CurrentEntry, KTIMER, TimerListEntry);
+        DPRINT("Expiring Timer: %x\n", Timer);
+        
+        /* Expire it */
+        KiHandleExpiredTimer(Timer);
+    }
 
+    DPRINT("Timers expired\n");
 
-VOID INIT_FUNCTION
-KeInitializeTimerImpl(VOID)
-/*
- * FUNCTION: Initializes timer irq handling
- * NOTE: This is only called once from main()
- */
-{
-   TIME_FIELDS TimeFields;
-
-   DPRINT("KeInitializeTimerImpl()\n");
-   InitializeListHead(&AbsoluteTimerListHead);
-   InitializeListHead(&RelativeTimerListHead);
-   KeInitializeSpinLock(&TimerListLock);
-   KeInitializeDpc(&ExpireTimerDpc, KeExpireTimers, 0);
-   /*
-    * Calculate the starting time for the system clock
-    */
-   HalQueryRealTimeClock(&TimeFields);
-   RtlTimeFieldsToTime(&TimeFields, &SystemBootTime);
-
-   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;
-
-   TimerInitDone = TRUE;
-   DPRINT("Finished KeInitializeTimerImpl()\n");
+    /* Release Dispatcher Lock */
+    KeReleaseDispatcherDatabaseLock(OldIrql);
 }
 
 /*
- * @unimplemented
+ * We enter this function at IRQL DISPATCH_LEVEL, and with the
+ * Dispatcher Lock held!
  */
-VOID
-FASTCALL
-KeSetTimeUpdateNotifyRoutine(
-    IN PTIME_UPDATE_NOTIFY_ROUTINE NotifyRoutine
-    )
+VOID 
+STDCALL
+KiHandleExpiredTimer(PKTIMER Timer)
 {
-       UNIMPLEMENTED;
-}
 
+    LARGE_INTEGER DueTime;
+    DPRINT("HandleExpiredTime(Timer %x)\n", Timer);
+    
+    if(Timer->Header.Inserted) {
 
-/*
- * 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)
-   {
-      InterlockedIncrement((PLONG)&CurrentThread->UserTime);
-      InterlockedIncrement((PLONG)&CurrentProcess->UserTime);
-      Pcr->PrcbData.UserTime++;
-   }
-   else
-   {
-      if (Irql > DISPATCH_LEVEL)
-      {
-         Pcr->PrcbData.InterruptTime++;
-      }
-      else if (Irql == DISPATCH_LEVEL)
-      {
-         Pcr->PrcbData.DpcTime++;
-      }
-      else
-      {
-         InterlockedIncrement((PLONG)&CurrentThread->KernelTime);
-         InterlockedIncrement((PLONG)&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);
-   }
+       /* First of all, remove the Timer */
+       Timer->Header.Inserted = FALSE;
+       RemoveEntryList(&Timer->TimerListEntry);
+    }
+    
+    /* Set it as Signaled */
+    DPRINT("Setting Timer as Signaled\n");
+    Timer->Header.SignalState = TRUE;
+    KiWaitTest(&Timer->Header, IO_NO_INCREMENT);   
+
+    /* If the Timer is periodic, reinsert the timer with the new due time */
+    if (Timer->Period) {
+        
+        /* Reinsert the Timer */
+        DueTime.QuadPart = Timer->Period * -SYSTEM_TIME_UNITS_PER_MSEC;
+        if (!KiInsertTimer(Timer, DueTime)) {
+
+           /* FIXME: I will think about how to handle this and fix it ASAP -- Alex */
+           DPRINT("CRITICAL UNHANDLED CASE: TIMER ALREADY EXPIRED!!!\n");
+        };
+    }
+    
+    /* Check if the Timer has a DPC */
+    if (Timer->Dpc) {
+
+        DPRINT("Timer->Dpc %x Timer->Dpc->DeferredRoutine %x\n", Timer->Dpc, Timer->Dpc->DeferredRoutine);
+        
+        /* Insert the DPC */
+        KeInsertQueueDpc(Timer->Dpc,
+                         NULL,
+                         NULL);
+        
+        DPRINT("Finished dpc routine\n");
+    }
 }
 
-
 /*
- * 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
+ * Note: This function is called with the Dispatcher Lock held.
  */
-VOID 
+BOOLEAN
 STDCALL
-KeUpdateSystemTime(
-    IN PKTRAP_FRAME  TrapFrame,
-    IN KIRQL  Irql
-    )
-/*
- * FUNCTION: Handles a timer interrupt
- */
-{
-   LARGE_INTEGER Time;
-
-   ASSERT(KeGetCurrentIrql() == PROFILE_LEVEL);
-
-   KiRawTicks++;
-   
-   if (TimerInitDone == 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(&ExpireTimerDpc, (PVOID)TrapFrame->Eip, 0);
-}
-
-
-VOID
-KiSetSystemTime(PLARGE_INTEGER NewSystemTime)
+KiInsertTimer(PKTIMER Timer,
+              LARGE_INTEGER DueTime)
 {
-  LARGE_INTEGER OldSystemTime;
-  LARGE_INTEGER DeltaTime;
-  KIRQL OldIrql;
-  PLIST_ENTRY current_entry = NULL;
-  PKTIMER current = NULL;
-
-  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 all relative timers */
-  current_entry = RelativeTimerListHead.Flink;
-  ASSERT(current_entry);
-  while (current_entry != &RelativeTimerListHead)
-    {
-      current = CONTAINING_RECORD(current_entry, KTIMER, TimerListEntry);
-      ASSERT(current);
-      ASSERT(current_entry != &RelativeTimerListHead);
-      ASSERT(current_entry->Flink != current_entry);
-
-      current->DueTime.QuadPart += DeltaTime.QuadPart;
-
-      current_entry = current_entry->Flink;
+    LARGE_INTEGER SystemTime;
+    LARGE_INTEGER DifferenceTime;
+    ULONGLONG InterruptTime;
+    
+    DPRINT("KiInsertTimer(Timer %x DueTime %I64d)\n", Timer, DueTime.QuadPart);
+    
+    /* Set default data */
+    Timer->Header.Inserted = TRUE;
+    Timer->Header.Absolute = FALSE;
+    if (!Timer->Period) Timer->Header.SignalState = FALSE;
+    
+    /* Convert to relative time if needed */
+    if (DueTime.u.HighPart >= 0) {
+        
+        /* Get System Time */
+        KeQuerySystemTime(&SystemTime);
+        
+        /* Do the conversion */
+        DifferenceTime.QuadPart = SystemTime.QuadPart - DueTime.QuadPart;
+        DPRINT("Time Difference is: %I64d\n", DifferenceTime.QuadPart);
+        
+        /* Make sure it hasn't already expired */
+        if (DifferenceTime.u.HighPart >= 0) {
+        
+            /* Cancel everything */
+            DPRINT("Timer already expired: %d\n", DifferenceTime.u.HighPart);
+            Timer->Header.SignalState = TRUE;
+            Timer->Header.Inserted = FALSE;
+            return FALSE;
+        }
+        
+        /* Set the time as Absolute */
+        Timer->Header.Absolute = TRUE;
+        DueTime = DifferenceTime;
     }
-
-  KeReleaseDispatcherDatabaseLock(OldIrql);
-
-  /*
-   * NOTE: Expired timers will be processed at the next clock tick!
-   */
+    
+    /* Get the Interrupt Time */
+    InterruptTime = KeQueryInterruptTime();
+    
+    /* Set the Final Due Time */
+    Timer->DueTime.QuadPart = InterruptTime - DueTime.QuadPart;
+    DPRINT("Final Due Time is: %I64d\n", Timer->DueTime.QuadPart);
+    
+    /* Now insert it into the Timer List */    
+    DPRINT("Inserting Timer into list\n");
+    InsertAscendingList(&KiTimerListHead, 
+                        KTIMER,
+                        TimerListEntry, 
+                        Timer,
+                        DueTime.QuadPart);
+    
+    return TRUE;
 }
-
 /* EOF */