- Implement KiRecalculateDueTime to handle cases where a timeout wait has been interu...
[reactos.git] / reactos / ntoskrnl / ke / wait.c
index 99dce85..92749c2 100644 (file)
@@ -1,16 +1,15 @@
 /*
- * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS Kernel
+ * LICENSE:         GPL - See COPYING in the top level directory
  * FILE:            ntoskrnl/ke/wait.c
  * PURPOSE:         Manages waiting for Dispatcher Objects
- * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
  *                  Gunnar Dalsnes
  */
 
 /* INCLUDES ******************************************************************/
 
 #include <ntoskrnl.h>
-
 #define NDEBUG
 #include <internal/debug.h>
 
@@ -20,47 +19,6 @@ KSPIN_LOCK DispatcherDatabaseLock;
 
 /* PRIVATE FUNCTIONS *********************************************************/
 
-/*
- * Rules for checking alertability:
- *  - For Alertable waits ONLY:
- *      * We don't wait and return STATUS_ALERTED if the thread is alerted
- *        in EITHER the specified wait mode OR in Kernel Mode.
- *  - For BOTH Alertable AND Non-Alertable waits:
- *      * We don't want and return STATUS_USER_APC if the User Mode APC list
- *        is not empty AND the wait mode is User Mode.
- */
-#define KiCheckAlertability()                                               \
-    if (Alertable)                                                          \
-    {                                                                       \
-        if (CurrentThread->Alerted[(int)WaitMode])                          \
-        {                                                                   \
-            CurrentThread->Alerted[(int)WaitMode] = FALSE;                  \
-            WaitStatus = STATUS_ALERTED;                                    \
-            break;                                                          \
-        }                                                                   \
-        else if ((WaitMode != KernelMode) &&                                \
-                (!IsListEmpty(&CurrentThread->ApcState.ApcListHead[UserMode])))\
-        {                                                                   \
-            CurrentThread->ApcState.UserApcPending = TRUE;                  \
-            WaitStatus = STATUS_USER_APC;                                   \
-            break;                                                          \
-        }                                                                   \
-        else if (CurrentThread->Alerted[KernelMode])                        \
-        {                                                                   \
-            CurrentThread->Alerted[KernelMode] = FALSE;                     \
-            WaitStatus = STATUS_ALERTED;                                    \
-            break;                                                          \
-        }                                                                   \
-    }                                                                       \
-    else if ((WaitMode != KernelMode) &&                                    \
-             (CurrentThread->ApcState.UserApcPending))                      \
-    {                                                                       \
-        WaitStatus = STATUS_USER_APC;                                       \
-        break;                                                              \
-    }                                                                       \
-
-/* PUBLIC FUNCTIONS **********************************************************/
-
 VOID
 FASTCALL
 KiWaitSatisfyAll(PKWAIT_BLOCK FirstBlock)
@@ -80,44 +38,255 @@ KiWaitSatisfyAll(PKWAIT_BLOCK FirstBlock)
 
         /* Move to the next block */
         WaitBlock = WaitBlock->NextWaitBlock;
+    } while (WaitBlock != FirstBlock);
+}
+
+VOID
+FASTCALL
+KiWaitTest(IN PVOID ObjectPointer,
+           IN KPRIORITY Increment)
+{
+    PLIST_ENTRY WaitEntry;
+    PLIST_ENTRY WaitList;
+    PKWAIT_BLOCK CurrentWaitBlock;
+    PKWAIT_BLOCK NextWaitBlock;
+    PKTHREAD WaitThread;
+    PKMUTANT FirstObject = ObjectPointer, Object;
+
+    /* Loop the Wait Entries */
+    WaitList = &FirstObject->Header.WaitListHead;
+    WaitEntry = WaitList->Flink;
+    while ((FirstObject->Header.SignalState > 0) &&
+           (WaitEntry != WaitList))
+    {
+        /* Get the current wait block */
+        CurrentWaitBlock = CONTAINING_RECORD(WaitEntry,
+                                             KWAIT_BLOCK,
+                                             WaitListEntry);
+        WaitThread = CurrentWaitBlock->Thread;
+
+        /* Check the current Wait Mode */
+        if (CurrentWaitBlock->WaitType == WaitAny)
+        {
+            /* Easy case, satisfy only this wait */
+            WaitEntry = WaitEntry->Blink;
+            KiSatisfyObjectWait(FirstObject, WaitThread);
+        }
+        else
+        {
+            /* Everything must be satisfied */
+            NextWaitBlock = CurrentWaitBlock->NextWaitBlock;
+
+            /* Loop first to make sure they are valid */
+            while (NextWaitBlock != CurrentWaitBlock)
+            {
+                /* Make sure this isn't a timeout block */
+                if (NextWaitBlock->WaitKey != STATUS_TIMEOUT)
+                {
+                    /* Get the object */
+                    Object = NextWaitBlock->Object;
+
+                    /* Check if this is a mutant */
+                    if ((Object->Header.Type == MutantObject) &&
+                        (Object->Header.SignalState <= 0) &&
+                        (WaitThread == Object->OwnerThread))
+                    {
+                        /* It's a signaled mutant */
+                    }
+                    else if (Object->Header.SignalState <= 0)
+                    {
+                        /* Skip the unwaiting */
+                        goto SkipUnwait;
+                    }
+                }
+
+                /* Go to the next Wait block */
+                NextWaitBlock = NextWaitBlock->NextWaitBlock;
+            }
+
+            /* All the objects are signaled, we can satisfy */
+            WaitEntry = WaitEntry->Blink;
+            KiWaitSatisfyAll(CurrentWaitBlock);
+        }
+
+        /* All waits satisfied, unwait the thread */
+        KiAbortWaitThread(WaitThread, CurrentWaitBlock->WaitKey, Increment);
+
+SkipUnwait:
+        /* Next entry */
+        WaitEntry = WaitEntry->Flink;
     }
-    while (WaitBlock != FirstBlock);
 }
 
+/* Must be called with the dispatcher lock held */
+VOID
+FASTCALL
+KiAbortWaitThread(IN PKTHREAD Thread,
+                  IN NTSTATUS WaitStatus,
+                  IN KPRIORITY Increment)
+{
+    PKWAIT_BLOCK WaitBlock;
+    PKTIMER Timer;
+    LONG NewPriority;
+
+    /* Update wait status */
+    Thread->WaitStatus |= WaitStatus;
+
+    /* Remove the Wait Blocks from the list */
+    WaitBlock = Thread->WaitBlockList;
+    do
+    {
+        /* Remove it */
+        RemoveEntryList(&WaitBlock->WaitListEntry);
+
+        /* Go to the next one */
+        WaitBlock = WaitBlock->NextWaitBlock;
+    } while (WaitBlock != Thread->WaitBlockList);
+
+    /* Remove the thread from the wait list! */
+    if (Thread->WaitListEntry.Flink) RemoveEntryList(&Thread->WaitListEntry);
+
+    /* Check if there's a Thread Timer */
+    Timer = &Thread->Timer;
+    if (Timer->Header.Inserted)
+    {
+        /* Remove the timer */
+        Timer->Header.Inserted = FALSE;
+        RemoveEntryList(&Timer->TimerListEntry);
+        //KiRemoveTimer(Timer);
+    }
+
+    /* Increment the Queue's active threads */
+    if (Thread->Queue) Thread->Queue->CurrentCount++;
+
+    /* Check if this is a non-RT thread */
+    if (Thread->Priority < LOW_REALTIME_PRIORITY)
+    {
+        /* Check if boosting is enabled and we can boost */
+        if (!(Thread->DisableBoost) && !(Thread->PriorityDecrement))
+        {
+            /* We can boost, so calculate the new priority */
+            NewPriority = Thread->BasePriority + Increment;
+            if (NewPriority > Thread->Priority)
+            {
+                /* Make sure the new priority wouldn't push the thread to RT */
+                if (NewPriority >= LOW_REALTIME_PRIORITY)
+                {
+                    /* Set it just before the RT zone */
+                    Thread->Priority = LOW_REALTIME_PRIORITY - 1;
+                }
+                else
+                {
+                    /* Otherwise, set our calculated priority */
+                    Thread->Priority = NewPriority;
+                }
+            }
+        }
+
+        /* Check if this is a high-priority thread */
+        if (Thread->BasePriority >= 14)
+        {
+            /* It is, simply reset the quantum */
+            Thread->Quantum = Thread->QuantumReset;
+        }
+        else
+        {
+            /* Otherwise, decrease quantum */
+            Thread->Quantum--;
+            if (Thread->Quantum <= 0)
+            {
+                /* We've went below 0, reset it */
+                Thread->Quantum = Thread->QuantumReset;
+
+                /* Apply per-quantum priority decrement */
+                Thread->Priority -= (Thread->PriorityDecrement + 1);
+                if (Thread->Priority < Thread->BasePriority)
+                {
+                    /* We've went too low, reset it */
+                    Thread->Priority = Thread->BasePriority;
+                }
+
+                /* Delete per-quantum decrement */
+                Thread->PriorityDecrement = 0;
+            }
+        }
+    }
+    else
+    {
+        /* For real time threads, just reset the quantum */
+        Thread->Quantum = Thread->QuantumReset;
+    }
+
+    /* Reschedule the Thread */
+    KiReadyThread(Thread);
+}
+
+VOID
+FASTCALL
+KiAcquireFastMutex(IN PFAST_MUTEX FastMutex)
+{
+    /* Increase contention count */
+    FastMutex->Contention++;
+
+    /* Wait for the event */
+    KeWaitForSingleObject(&FastMutex->Gate,
+                          WrMutex,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+}
+
+VOID
+FASTCALL
+KiExitDispatcher(IN KIRQL OldIrql)
+{
+    /* Check if it's the idle thread */
+    if (!(KeIsExecutingDpc()) &&
+        (OldIrql < DISPATCH_LEVEL) &&
+        (KeGetCurrentThread()) &&
+        (KeGetCurrentThread() == KeGetCurrentPrcb()->IdleThread))
+    {
+        /* Dispatch a new thread */
+        KiDispatchThreadNoLock(Ready);
+    }
+    else
+    {
+        /* Otherwise just release the lock */
+        KeReleaseDispatcherDatabaseLockFromDpcLevel();
+    }
+
+    /* Lower irql back */
+    KeLowerIrql(OldIrql);
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
 /*
  * @implemented
- *
- * FUNCTION: Puts the current thread into an alertable or nonalertable
- * wait state for a given internal
- * ARGUMENTS:
- *          WaitMode = Processor mode in which the caller is waiting
- *          Altertable = Specifies if the wait is alertable
- *          Interval = Specifies the interval to wait
- * RETURNS: Status
  */
 NTSTATUS
-STDCALL
-KeDelayExecutionThread(KPROCESSOR_MODE WaitMode,
-                       BOOLEAN Alertable,
-                       PLARGE_INTEGER Interval)
+NTAPI
+KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode,
+                       IN BOOLEAN Alertable,
+                       IN PLARGE_INTEGER Interval OPTIONAL)
 {
     PKWAIT_BLOCK TimerWaitBlock;
     PKTIMER ThreadTimer;
     PKTHREAD CurrentThread = KeGetCurrentThread();
     NTSTATUS WaitStatus = STATUS_SUCCESS;
-    DPRINT("Entering KeDelayExecutionThread\n");
+    BOOLEAN Swappable;
+    PLARGE_INTEGER OriginalDueTime = Interval;
+    LARGE_INTEGER DueTime, NewDueTime;
 
     /* Check if the lock is already held */
     if (CurrentThread->WaitNext)
     {
         /* Lock is held, disable Wait Next */
-        DPRINT("Lock is held\n");
         CurrentThread->WaitNext = FALSE;
     }
     else
     {
         /* Lock not held, acquire it */
-        DPRINT("Lock is not held, acquiring\n");
         CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
     }
 
@@ -127,106 +296,100 @@ KeDelayExecutionThread(KPROCESSOR_MODE WaitMode,
     /* Start Wait Loop */
     do
     {
-        /* Check if a kernel APC is pending and we were below APC_LEVEL */
+        /* Check if a kernel APC is pending and we're below APC_LEVEL */
         if ((CurrentThread->ApcState.KernelApcPending) &&
+            !(CurrentThread->SpecialApcDisable) &&
             (CurrentThread->WaitIrql < APC_LEVEL))
         {
             /* Unlock the dispatcher */
             KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
-            goto SkipWait;
         }
+        else
+        {
+            /* Check if we can do an alertable wait, if requested */
+            KiCheckAlertability();
 
-        /* Check if we can do an alertable wait, if requested */
-        KiCheckAlertability();
+            /* Check if we can swap the thread's stack */
+            CurrentThread->WaitListEntry.Flink = NULL;
+            KiCheckThreadStackSwap(WaitMode, CurrentThread, Swappable);
 
-        /* Set status */
-        CurrentThread->WaitStatus = STATUS_WAIT_0;
+            /* Set status */
+            CurrentThread->WaitStatus = STATUS_WAIT_0;
 
-        /* Set Timer */
-        ThreadTimer = &CurrentThread->Timer;
+            /* Set Timer */
+            ThreadTimer = &CurrentThread->Timer;
 
-        /* Setup the Wait Block */
-        CurrentThread->WaitBlockList = TimerWaitBlock;
-        TimerWaitBlock->NextWaitBlock = TimerWaitBlock;
+            /* Setup the Wait Block */
+            CurrentThread->WaitBlockList = TimerWaitBlock;
+            TimerWaitBlock->NextWaitBlock = TimerWaitBlock;
 
-        /* Link the timer to this Wait Block */
-        ThreadTimer->Header.WaitListHead.Flink = &TimerWaitBlock->WaitListEntry;
-        ThreadTimer->Header.WaitListHead.Blink = &TimerWaitBlock->WaitListEntry;
+            /* Link the timer to this Wait Block */
+            ThreadTimer->Header.WaitListHead.Flink =
+                &TimerWaitBlock->WaitListEntry;
+            ThreadTimer->Header.WaitListHead.Blink =
+                &TimerWaitBlock->WaitListEntry;
 
-        /* Insert the Timer into the Timer Lists and enable it */
-        if (!KiInsertTimer(ThreadTimer, *Interval))
-        {
-            /* FIXME: The timer already expired, we should find a new ready thread */
-            WaitStatus = STATUS_SUCCESS;
-            break;
-        }
+            /* Insert the Timer into the Timer Lists and enable it */
+            if (!KiInsertTimer(ThreadTimer, *Interval))
+            {
+                /* FIXME: We should find a new ready thread */
+                WaitStatus = STATUS_SUCCESS;
+                break;
+            }
 
-        /* Handle Kernel Queues */
-        if (CurrentThread->Queue)
-        {
-            DPRINT("Waking Queue\n");
-            KiWakeQueue(CurrentThread->Queue);
-        }
+            /* Save due time */
+            DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
 
-        /* Setup the wait information */
-        CurrentThread->Alertable = Alertable;
-        CurrentThread->WaitMode = WaitMode;
-        CurrentThread->WaitReason = DelayExecution;
-        CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart;
-        CurrentThread->State = Waiting;
+            /* Handle Kernel Queues */
+            if (CurrentThread->Queue) KiWakeQueue(CurrentThread->Queue);
 
-        /* Find a new thread to run */
-        DPRINT("Swapping threads\n");
-        WaitStatus = KiSwapThread();
+            /* Setup the wait information */
+            CurrentThread->Alertable = Alertable;
+            CurrentThread->WaitMode = WaitMode;
+            CurrentThread->WaitReason = DelayExecution;
+            CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart;
+            CurrentThread->State = Waiting;
 
-        /* Check if we were executing an APC or if we timed out */
-        if (WaitStatus != STATUS_KERNEL_APC)
-        {
-            /* This is a good thing */
-            if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS;
+            /* Find a new thread to run */
+            KiAddThreadToWaitList(CurrentThread, Swappable);
+            WaitStatus = KiSwapThread();
+            ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
 
-            /* Return Status */
-            return WaitStatus;
-        }
+            /* Check if we were executing an APC or if we timed out */
+            if (WaitStatus != STATUS_KERNEL_APC)
+            {
+                /* This is a good thing */
+                if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS;
 
-        /* FIXME: Fixup interval */
+                /* Return Status */
+                return WaitStatus;
+            }
+
+            /* Recalculate due times */
+            Interval = KiRecalculateDueTime(OriginalDueTime,
+                                            &DueTime,
+                                            &NewDueTime);
+        }
 
         /* Acquire again the lock */
-SkipWait:
-        DPRINT("Looping again\n");
         CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
-    }
-    while (TRUE);
+    } while (TRUE);
 
     /* Release the Lock, we are done */
-    DPRINT("Returning from KeDelayExecutionThread(), %x. Status: %d\n",
-            KeGetCurrentThread(), Status);
     KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
     return WaitStatus;
 }
 
 /*
  * @implemented
- *
- * FUNCTION: Puts the current thread into a wait state until the
- * given dispatcher object is set to signalled
- * ARGUMENTS:
- *         Object = Object to wait on
- *         WaitReason = Reason for the wait (debugging aid)
- *         WaitMode = Can be KernelMode or UserMode, if UserMode then
- *                    user-mode APCs can be delivered and the thread's
- *                    stack can be paged out
- *         Altertable = Specifies if the wait is a alertable
- *         Timeout = Optional timeout value
- * RETURNS: Status
  */
 NTSTATUS
-STDCALL
-KeWaitForSingleObject(PVOID Object,
-                      KWAIT_REASON WaitReason,
-                      KPROCESSOR_MODE WaitMode,
-                      BOOLEAN Alertable,
-                      PLARGE_INTEGER Timeout)
+NTAPI
+KeWaitForSingleObject(IN PVOID Object,
+                      IN KWAIT_REASON WaitReason,
+                      IN KPROCESSOR_MODE WaitMode,
+                      IN BOOLEAN Alertable,
+                      IN PLARGE_INTEGER Timeout OPTIONAL)
 {
     PKMUTANT CurrentObject;
     PKWAIT_BLOCK WaitBlock;
@@ -234,163 +397,170 @@ KeWaitForSingleObject(PVOID Object,
     PKTIMER ThreadTimer;
     PKTHREAD CurrentThread = KeGetCurrentThread();
     NTSTATUS WaitStatus = STATUS_SUCCESS;
-    DPRINT("Entering KeWaitForSingleObject\n");
+    BOOLEAN Swappable;
+    LARGE_INTEGER DueTime, NewDueTime;
+    PLARGE_INTEGER OriginalDueTime = Timeout;
 
     /* Check if the lock is already held */
     if (CurrentThread->WaitNext)
     {
         /* Lock is held, disable Wait Next */
-        DPRINT("Lock is held\n");
         CurrentThread->WaitNext = FALSE;
     }
     else
     {
         /* Lock not held, acquire it */
-        DPRINT("Lock is not held, acquiring\n");
         CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
     }
 
     /* Start the actual Loop */
+    WaitBlock = &CurrentThread->WaitBlock[0];
     do
     {
-        /* Check if a kernel APC is pending and we were below APC_LEVEL */
+        /* Check if a kernel APC is pending and we're below APC_LEVEL */
         if ((CurrentThread->ApcState.KernelApcPending) &&
+            !(CurrentThread->SpecialApcDisable) &&
             (CurrentThread->WaitIrql < APC_LEVEL))
         {
             /* Unlock the dispatcher */
             KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
-            goto SkipWait;
         }
+        else
+        {
+            /* Set default status */
+            CurrentThread->WaitStatus = STATUS_WAIT_0;
 
-        /* Set default status */
-        CurrentThread->WaitStatus = STATUS_WAIT_0;
-
-        /* Append wait block to the KTHREAD wait block list */
-        CurrentThread->WaitBlockList = WaitBlock = &CurrentThread->WaitBlock[0];
-
-        /* Get the Current Object */
-        CurrentObject = (PKMUTANT)Object;
+            /* Get the Current Object */
+            CurrentObject = (PKMUTANT)Object;
 
-        /* Check if it's a mutant */
-        if (CurrentObject->Header.Type == MutantObject)
-        {
-            /* Check its signal state or if we own it */
-            if ((CurrentObject->Header.SignalState > 0) ||
-                (CurrentThread == CurrentObject->OwnerThread))
+            /* Check if it's a mutant */
+            if (CurrentObject->Header.Type == MutantObject)
             {
-                /* Just unwait this guy and exit */
-                if (CurrentObject->Header.SignalState != (LONG)MINLONG)
+                /* Check its signal state or if we own it */
+                if ((CurrentObject->Header.SignalState > 0) ||
+                    (CurrentThread == CurrentObject->OwnerThread))
                 {
-                    /* It has a normal signal state, so unwait it and return */
-                    KiSatisfyMutantWait(CurrentObject, CurrentThread);
-                    WaitStatus = CurrentThread->WaitStatus;
-                    goto DontWait;
-                }
-                else
-                {
-                    /* According to wasm.ru, we must raise this exception (tested and true) */
-                    KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
-                    ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+                    /* Just unwait this guy and exit */
+                    if (CurrentObject->Header.SignalState != (LONG)MINLONG)
+                    {
+                        /* It has a normal signal state. Unwait and return */
+                        KiSatisfyMutantWait(CurrentObject, CurrentThread);
+                        WaitStatus = CurrentThread->WaitStatus;
+                        goto DontWait;
+                    }
+                    else
+                    {
+                        /* Raise an exception (see wasm.ru) */
+                        KeReleaseDispatcherDatabaseLock(CurrentThread->
+                                                        WaitIrql);
+                        ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+                   }
                 }
             }
-        }
-        else if (CurrentObject->Header.SignalState > 0)
-        {
-            /* Another satisfied object */
-            KiSatisfyNonMutantWait(CurrentObject, CurrentThread);
-            WaitStatus = STATUS_WAIT_0;
-            goto DontWait;
-        }
+            else if (CurrentObject->Header.SignalState > 0)
+            {
+                /* Another satisfied object */
+                KiSatisfyNonMutantWait(CurrentObject, CurrentThread);
+                WaitStatus = STATUS_WAIT_0;
+                goto DontWait;
+            }
 
-        /* Set up the Wait Block */
-        WaitBlock->Object = CurrentObject;
-        WaitBlock->Thread = CurrentThread;
-        WaitBlock->WaitKey = (USHORT)(STATUS_SUCCESS);
-        WaitBlock->WaitType = WaitAny;
-        WaitBlock->NextWaitBlock = WaitBlock;
+            /* Append wait block to the KTHREAD wait block list */
+            CurrentThread->WaitBlockList = WaitBlock;
 
-        /* Make sure we can satisfy the Alertable request */
-        KiCheckAlertability();
+            /* Set up the Wait Block */
+            WaitBlock->Object = CurrentObject;
+            WaitBlock->WaitKey = (USHORT)(STATUS_SUCCESS);
+            WaitBlock->WaitType = WaitAny;
 
-        /* Enable the Timeout Timer if there was any specified */
-        if (Timeout)
-        {
-            /* Fail if the timeout interval is actually 0 */
-            if (!Timeout->QuadPart)
+            /* Make sure we can satisfy the Alertable request */
+            KiCheckAlertability();
+
+            /* Check if we can swap the thread's stack */
+            CurrentThread->WaitListEntry.Flink = NULL;
+            KiCheckThreadStackSwap(WaitMode, CurrentThread, Swappable);
+
+            /* Enable the Timeout Timer if there was any specified */
+            if (Timeout)
             {
-                /* Return a timeout */
-                WaitStatus = STATUS_TIMEOUT;
-                goto DontWait;
-            }
+                /* Fail if the timeout interval is actually 0 */
+                if (!Timeout->QuadPart)
+                {
+                    /* Return a timeout */
+                    WaitStatus = STATUS_TIMEOUT;
+                    goto DontWait;
+                }
 
-            /* Point to Timer Wait Block and Thread Timer */
-            TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK];
-            ThreadTimer = &CurrentThread->Timer;
+                /* Point to Timer Wait Block and Thread Timer */
+                TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK];
+                ThreadTimer = &CurrentThread->Timer;
 
-            /* Connect the Timer Wait Block */
-            WaitBlock->NextWaitBlock = TimerWaitBlock;
+                /* Connect the Timer Wait Block */
+                WaitBlock->NextWaitBlock = TimerWaitBlock;
 
-            /* Set up the Timer Wait Block */
-            TimerWaitBlock->NextWaitBlock = WaitBlock;
+                /* Set up the Timer Wait Block */
+                TimerWaitBlock->NextWaitBlock = WaitBlock;
 
-            /* Link the timer to this Wait Block */
-            ThreadTimer->Header.WaitListHead.Flink = &TimerWaitBlock->WaitListEntry;
-            ThreadTimer->Header.WaitListHead.Blink = &TimerWaitBlock->WaitListEntry;
+                /* Link the timer to this Wait Block */
+                ThreadTimer->Header.WaitListHead.Flink =
+                    &TimerWaitBlock->WaitListEntry;
+                ThreadTimer->Header.WaitListHead.Blink =
+                    &TimerWaitBlock->WaitListEntry;
 
-            /* Insert the Timer into the Timer Lists and enable it */
-            if (!KiInsertTimer(ThreadTimer, *Timeout))
+                /* Insert the Timer into the Timer Lists and enable it */
+                if (!KiInsertTimer(ThreadTimer, *Timeout))
+                {
+                    /* Return a timeout if we couldn't insert the timer */
+                    WaitStatus = STATUS_TIMEOUT;
+                    goto DontWait;
+                }
+
+                /* Set the current due time */
+                DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
+            }
+            else
             {
-                /* Return a timeout if we couldn't insert the timer */
-                WaitStatus = STATUS_TIMEOUT;
-                goto DontWait;
+                /* No timer block, so just set our wait block as next */
+                WaitBlock->NextWaitBlock = WaitBlock;
             }
-        }
 
-        /* Link the Object to this Wait Block */
-        InsertTailList(&CurrentObject->Header.WaitListHead,
-                       &WaitBlock->WaitListEntry);
+            /* Link the Object to this Wait Block */
+            InsertTailList(&CurrentObject->Header.WaitListHead,
+                           &WaitBlock->WaitListEntry);
 
-        /* Handle Kernel Queues */
-        if (CurrentThread->Queue)
-        {
-            DPRINT("Waking Queue\n");
-            KiWakeQueue(CurrentThread->Queue);
-        }
+            /* Handle Kernel Queues */
+            if (CurrentThread->Queue) KiWakeQueue(CurrentThread->Queue);
 
-        /* Setup the wait information */
-        CurrentThread->Alertable = Alertable;
-        CurrentThread->WaitMode = WaitMode;
-        CurrentThread->WaitReason = WaitReason;
-        CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart;
-        CurrentThread->State = Waiting;
+            /* Setup the wait information */
+            CurrentThread->Alertable = Alertable;
+            CurrentThread->WaitMode = WaitMode;
+            CurrentThread->WaitReason = WaitReason;
+            CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart;
+            CurrentThread->State = Waiting;
 
-        /* Find a new thread to run */
-        DPRINT("Swapping threads\n");
-        WaitStatus = KiSwapThread();
+            /* Find a new thread to run */
+            KiAddThreadToWaitList(CurrentThread, Swappable);
+            WaitStatus = KiSwapThread();
+            ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
 
-        /* Check if we were executing an APC */
-        if (WaitStatus != STATUS_KERNEL_APC)
-        {
-            /* Return Status */
-            return WaitStatus;
-        }
+            /* Check if we were executing an APC */
+            if (WaitStatus != STATUS_KERNEL_APC) return WaitStatus;
 
-        /* Check if we had a timeout */
-        if (Timeout)
-        {
-             /* FIXME: Fixup interval */
+            /* Check if we had a timeout */
+            if (Timeout)
+            {
+                /* Recalculate due times */
+                Timeout = KiRecalculateDueTime(OriginalDueTime,
+                                               &DueTime,
+                                               &NewDueTime);
+            }
         }
 
         /* Acquire again the lock */
-SkipWait:
-        DPRINT("Looping again\n");
         CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
-    }
-    while (TRUE);
+    } while (TRUE);
 
     /* Release the Lock, we are done */
-    DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n",
-            KeGetCurrentThread(), WaitStatus);
     KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
     return WaitStatus;
 
@@ -399,8 +569,6 @@ DontWait:
     KiAdjustQuantumThread(CurrentThread);
 
     /* Release & Return */
-    DPRINT("Quick-return from KeWaitForMultipleObjects(), %x. Status: %d\n.",
-            KeGetCurrentThread(), WaitStatus);
     KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
     return WaitStatus;
 }
@@ -409,15 +577,15 @@ DontWait:
  * @implemented
  */
 NTSTATUS
-STDCALL
-KeWaitForMultipleObjects(ULONG Count,
-                         PVOID Object[],
-                         WAIT_TYPE WaitType,
-                         KWAIT_REASON WaitReason,
-                         KPROCESSOR_MODE WaitMode,
-                         BOOLEAN Alertable,
-                         PLARGE_INTEGER Timeout,
-                         PKWAIT_BLOCK WaitBlockArray)
+NTAPI
+KeWaitForMultipleObjects(IN ULONG Count,
+                         IN PVOID Object[],
+                         IN WAIT_TYPE WaitType,
+                         IN KWAIT_REASON WaitReason,
+                         IN KPROCESSOR_MODE WaitMode,
+                         IN BOOLEAN Alertable,
+                         IN PLARGE_INTEGER Timeout OPTIONAL,
+                         OUT PKWAIT_BLOCK WaitBlockArray OPTIONAL)
 {
     PKMUTANT CurrentObject;
     PKWAIT_BLOCK WaitBlock;
@@ -427,9 +595,9 @@ KeWaitForMultipleObjects(ULONG Count,
     ULONG AllObjectsSignaled;
     ULONG WaitIndex;
     NTSTATUS WaitStatus = STATUS_SUCCESS;
-    DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
-           "PsGetCurrentThread() %x, Timeout %x\n",
-           Count, Object, PsGetCurrentThread(), Timeout);
+    BOOLEAN Swappable;
+    PLARGE_INTEGER OriginalDueTime = Timeout;
+    LARGE_INTEGER DueTime, NewDueTime;
 
     /* Set the Current Thread */
     CurrentThread = KeGetCurrentThread();
@@ -438,239 +606,249 @@ KeWaitForMultipleObjects(ULONG Count,
     if (CurrentThread->WaitNext)
     {
         /* Lock is held, disable Wait Next */
-        DPRINT("Lock is held\n");
         CurrentThread->WaitNext = FALSE;
     }
     else
     {
         /* Lock not held, acquire it */
-        DPRINT("Lock is not held, acquiring\n");
         CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
     }
 
-    /* Make sure the Wait Count is valid for the Thread and Maximum Wait Objects */
+    /* Make sure the Wait Count is valid */
     if (!WaitBlockArray)
     {
         /* Check in regards to the Thread Object Limit */
-        if (Count > THREAD_WAIT_OBJECTS) KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
+        if (Count > THREAD_WAIT_OBJECTS)
+        {
+            /* Bugcheck */
+            KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
+        }
 
         /* Use the Thread's Wait Block */
         WaitBlockArray = &CurrentThread->WaitBlock[0];
     }
     else
     {
-        /* Using our own Block Array. Check in regards to System Object Limit */
-        if (Count > MAXIMUM_WAIT_OBJECTS) KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
+        /* Using our own Block Array, so check with the System Object Limit */
+        if (Count > MAXIMUM_WAIT_OBJECTS)
+        {
+            /* Bugcheck */
+            KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
+        }
     }
 
     /* Start the actual Loop */
     do
     {
-        /* Check if a kernel APC is pending and we were below APC_LEVEL */
+        /* Check if a kernel APC is pending and we're below APC_LEVEL */
         if ((CurrentThread->ApcState.KernelApcPending) &&
+            !(CurrentThread->SpecialApcDisable) &&
             (CurrentThread->WaitIrql < APC_LEVEL))
         {
             /* Unlock the dispatcher */
             KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
-            goto SkipWait;
         }
+        else
+        {
+            /* Append wait block to the KTHREAD wait block list */
+            CurrentThread->WaitBlockList = WaitBlock = WaitBlockArray;
 
-        /* Append wait block to the KTHREAD wait block list */
-        CurrentThread->WaitBlockList = WaitBlock = WaitBlockArray;
-
-        /* Set default wait status */
-        CurrentThread->WaitStatus = STATUS_WAIT_0;
-
-        /* Check if the wait is (already) satisfied */
-        AllObjectsSignaled = TRUE;
+            /* Set default wait status */
+            CurrentThread->WaitStatus = STATUS_WAIT_0;
 
-        /* First, we'll try to satisfy the wait directly */
-        for (WaitIndex = 0; WaitIndex < Count; WaitIndex++)
-        {
-            /* Get the Current Object */
-            CurrentObject = (PKMUTANT)Object[WaitIndex];
+            /* Check if the wait is (already) satisfied */
+            AllObjectsSignaled = TRUE;
 
-            /* Check the type of wait */
-            if (WaitType == WaitAny)
+            /* First, we'll try to satisfy the wait directly */
+            for (WaitIndex = 0; WaitIndex < Count; WaitIndex++)
             {
-                /* Check if the Object is a mutant */
-                if (CurrentObject->Header.Type == MutantObject)
+                /* Get the Current Object */
+                CurrentObject = (PKMUTANT)Object[WaitIndex];
+
+                /* Check the type of wait */
+                if (WaitType == WaitAny)
                 {
-                    /* Check if it's signaled */
-                    if ((CurrentObject->Header.SignalState > 0) ||
-                        (CurrentThread == CurrentObject->OwnerThread))
+                    /* Check if the Object is a mutant */
+                    if (CurrentObject->Header.Type == MutantObject)
                     {
-                        /* This is a Wait Any, so just unwait this and exit */
-                        if (CurrentObject->Header.SignalState != (LONG)MINLONG)
-                        {
-                            /* Normal signal state, so unwait it and return */
-                            KiSatisfyMutantWait(CurrentObject, CurrentThread);
-                            WaitStatus = CurrentThread->WaitStatus | WaitIndex;
-                            goto DontWait;
-                        }
-                        else
+                        /* Check if it's signaled */
+                        if ((CurrentObject->Header.SignalState > 0) ||
+                            (CurrentThread == CurrentObject->OwnerThread))
                         {
-                            /* According to wasm.ru, we must raise this exception (tested and true) */
-                            KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
-                            ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+                            /* This is a Wait Any, so unwait this and exit */
+                            if (CurrentObject->Header.SignalState !=
+                                (LONG)MINLONG)
+                            {
+                                /* Normal signal state, unwait it and return */
+                                KiSatisfyMutantWait(CurrentObject,
+                                                    CurrentThread);
+                                WaitStatus = CurrentThread->WaitStatus |
+                                             WaitIndex;
+                                goto DontWait;
+                            }
+                            else
+                            {
+                                /* Raise an exception (see wasm.ru) */
+                                KeReleaseDispatcherDatabaseLock(CurrentThread->
+                                                                WaitIrql);
+                                ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+                            }
                         }
                     }
+                    else if (CurrentObject->Header.SignalState > 0)
+                    {
+                        /* Another signaled object, unwait and return */
+                        KiSatisfyNonMutantWait(CurrentObject, CurrentThread);
+                        WaitStatus = WaitIndex;
+                        goto DontWait;
+                    }
                 }
-                else if (CurrentObject->Header.SignalState > 0)
-                {
-                    /* Another signaled object, unwait and return */
-                    KiSatisfyNonMutantWait(CurrentObject, CurrentThread);
-                    WaitStatus = WaitIndex;
-                    goto DontWait;
-                }
-            }
-            else
-            {
-                /* Check if we're dealing with a mutant again */
-                if (CurrentObject->Header.Type == MutantObject)
+                else
                 {
-                    /* Check if it has an invalid count */
-                    if ((CurrentThread == CurrentObject->OwnerThread) &&
-                        (CurrentObject->Header.SignalState == MINLONG))
+                    /* Check if we're dealing with a mutant again */
+                    if (CurrentObject->Header.Type == MutantObject)
                     {
-                        /* Raise an exception */
-                        KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
-                        ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+                        /* Check if it has an invalid count */
+                        if ((CurrentThread == CurrentObject->OwnerThread) &&
+                            (CurrentObject->Header.SignalState == MINLONG))
+                        {
+                            /* Raise an exception */
+                            KeReleaseDispatcherDatabaseLock(CurrentThread->
+                                                            WaitIrql);
+                            ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+                        }
+                        else if ((CurrentObject->Header.SignalState <= 0) &&
+                                 (CurrentThread != CurrentObject->OwnerThread))
+                        {
+                            /* We don't own it, can't satisfy the wait */
+                            AllObjectsSignaled = FALSE;
+                        }
                     }
-                    else if ((CurrentObject->Header.SignalState <= 0) &&
-                             (CurrentThread != CurrentObject->OwnerThread))
+                    else if (CurrentObject->Header.SignalState <= 0)
                     {
-                        /* We don't own it, can't satisfy the wait */
+                        /* Not signaled, can't satisfy */
                         AllObjectsSignaled = FALSE;
                     }
                 }
-                else if (CurrentObject->Header.SignalState <= 0)
-                {
-                    /* Not signaled, can't satisfy */
-                    AllObjectsSignaled = FALSE;
-                }
-            }
-
-            /* Set up a Wait Block for this Object */
-            WaitBlock->Object = CurrentObject;
-            WaitBlock->Thread = CurrentThread;
-            WaitBlock->WaitKey = (USHORT)WaitIndex;
-            WaitBlock->WaitType = (USHORT)WaitType;
-            WaitBlock->NextWaitBlock = WaitBlock + 1;
 
-            /* Move to the next Wait Block */
-            WaitBlock = WaitBlock->NextWaitBlock;
-        }
+                /* Set up a Wait Block for this Object */
+                WaitBlock->Object = CurrentObject;
+                WaitBlock->Thread = CurrentThread;
+                WaitBlock->WaitKey = (USHORT)WaitIndex;
+                WaitBlock->WaitType = (USHORT)WaitType;
+                WaitBlock->NextWaitBlock = WaitBlock + 1;
 
-        /* Return to the Root Wait Block */
-        WaitBlock--;
-        WaitBlock->NextWaitBlock = WaitBlockArray;
+                /* Move to the next Wait Block */
+                WaitBlock = WaitBlock->NextWaitBlock;
+            }
 
-        /* Check if this is a Wait All and all the objects are signaled */
-        if ((WaitType == WaitAll) && (AllObjectsSignaled))
-        {
             /* Return to the Root Wait Block */
-            WaitBlock = CurrentThread->WaitBlockList;
+            WaitBlock--;
+            WaitBlock->NextWaitBlock = WaitBlockArray;
 
-            /* Satisfy their Waits and return to the caller */
-            KiWaitSatisfyAll(WaitBlock);
-            WaitStatus = CurrentThread->WaitStatus;
-            goto DontWait;
-        }
-
-        /* Make sure we can satisfy the Alertable request */
-        KiCheckAlertability();
-
-        /* Enable the Timeout Timer if there was any specified */
-        if (Timeout)
-        {
-            /* Make sure the timeout interval isn't actually 0 */
-            if (!Timeout->QuadPart)
+            /* Check if this is a Wait All and all the objects are signaled */
+            if ((WaitType == WaitAll) && (AllObjectsSignaled))
             {
-                /* Return a timeout */
-                WaitStatus = STATUS_TIMEOUT;
+                /* Return to the Root Wait Block */
+                WaitBlock = CurrentThread->WaitBlockList;
+
+                /* Satisfy their Waits and return to the caller */
+                KiWaitSatisfyAll(WaitBlock);
+                WaitStatus = CurrentThread->WaitStatus;
                 goto DontWait;
             }
 
-            /* Point to Timer Wait Block and Thread Timer */
-            TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK];
-            ThreadTimer = &CurrentThread->Timer;
+            /* Make sure we can satisfy the Alertable request */
+            KiCheckAlertability();
 
-            /* Connect the Timer Wait Block */
-            WaitBlock->NextWaitBlock = TimerWaitBlock;
+            /* Check if we can swap the thread's stack */
+            CurrentThread->WaitListEntry.Flink = NULL;
+            KiCheckThreadStackSwap(WaitMode, CurrentThread, Swappable);
 
-            /* Set up the Timer Wait Block */
-            TimerWaitBlock->NextWaitBlock = WaitBlockArray;
+            /* Enable the Timeout Timer if there was any specified */
+            if (Timeout)
+            {
+                /* Make sure the timeout interval isn't actually 0 */
+                if (!Timeout->QuadPart)
+                {
+                    /* Return a timeout */
+                    WaitStatus = STATUS_TIMEOUT;
+                    goto DontWait;
+                }
 
-            /* Initialize the list head */
-            InitializeListHead(&ThreadTimer->Header.WaitListHead);
+                /* Point to Timer Wait Block and Thread Timer */
+                TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK];
+                ThreadTimer = &CurrentThread->Timer;
 
-            /* Insert the Timer into the Timer Lists and enable it */
-            if (!KiInsertTimer(ThreadTimer, *Timeout))
-            {
-                /* Return a timeout if we couldn't insert the timer */
-                WaitStatus = STATUS_TIMEOUT;
-                goto DontWait;
+                /* Connect the Timer Wait Block */
+                WaitBlock->NextWaitBlock = TimerWaitBlock;
+
+                /* Set up the Timer Wait Block */
+                TimerWaitBlock->NextWaitBlock = WaitBlockArray;
+
+                /* Initialize the list head */
+                InitializeListHead(&ThreadTimer->Header.WaitListHead);
+
+                /* Insert the Timer into the Timer Lists and enable it */
+                if (!KiInsertTimer(ThreadTimer, *Timeout))
+                {
+                    /* Return a timeout if we couldn't insert the timer */
+                    WaitStatus = STATUS_TIMEOUT;
+                    goto DontWait;
+                }
+
+                /* Set the current due time */
+                DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
             }
-        }
 
-        /* Insert into Object's Wait List*/
-        WaitBlock = CurrentThread->WaitBlockList;
-        do
-        {
-            /* Get the Current Object */
-            CurrentObject = WaitBlock->Object;
+            /* Insert into Object's Wait List*/
+            WaitBlock = CurrentThread->WaitBlockList;
+            do
+            {
+                /* Get the Current Object */
+                CurrentObject = WaitBlock->Object;
 
-            /* Link the Object to this Wait Block */
-            InsertTailList(&CurrentObject->Header.WaitListHead,
-                           &WaitBlock->WaitListEntry);
+                /* Link the Object to this Wait Block */
+                InsertTailList(&CurrentObject->Header.WaitListHead,
+                               &WaitBlock->WaitListEntry);
 
-            /* Move to the next Wait Block */
-            WaitBlock = WaitBlock->NextWaitBlock;
-        }
-        while (WaitBlock != WaitBlockArray);
+                /* Move to the next Wait Block */
+                WaitBlock = WaitBlock->NextWaitBlock;
+            } while (WaitBlock != WaitBlockArray);
 
-        /* Handle Kernel Queues */
-        if (CurrentThread->Queue)
-        {
-            DPRINT("Waking Queue\n");
-            KiWakeQueue(CurrentThread->Queue);
-        }
+            /* Handle Kernel Queues */
+            if (CurrentThread->Queue) KiWakeQueue(CurrentThread->Queue);
 
-        /* Setup the wait information */
-        CurrentThread->Alertable = Alertable;
-        CurrentThread->WaitMode = WaitMode;
-        CurrentThread->WaitReason = WaitReason;
-        CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart;
-        CurrentThread->State = Waiting;
+            /* Setup the wait information */
+            CurrentThread->Alertable = Alertable;
+            CurrentThread->WaitMode = WaitMode;
+            CurrentThread->WaitReason = WaitReason;
+            CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart;
+            CurrentThread->State = Waiting;
 
-        /* Find a new thread to run */
-        DPRINT("Swapping threads\n");
-        WaitStatus = KiSwapThread();
+            /* Find a new thread to run */
+            KiAddThreadToWaitList(CurrentThread, Swappable);
+            WaitStatus = KiSwapThread();
+            ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
 
-        /* Check if we were executing an APC */
-        DPRINT("Thread is back\n");
-        if (WaitStatus != STATUS_KERNEL_APC)
-        {
-            /* Return Status */
-            return WaitStatus;
-        }
+            /* Check if we were executing an APC */
+            if (WaitStatus != STATUS_KERNEL_APC) return WaitStatus;
 
-        /* Check if we had a timeout */
-        if (Timeout)
-        {
-             /* FIXME: Fixup interval */
-        }
+            /* Check if we had a timeout */
+            if (Timeout)
+            {
+                /* Recalculate due times */
+                Timeout = KiRecalculateDueTime(OriginalDueTime,
+                                               &DueTime,
+                                               &NewDueTime);
+            }
 
-        /* Acquire again the lock */
-SkipWait:
-        DPRINT("Looping again\n");
-        CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
-    }
-    while (TRUE);
+            /* Acquire again the lock */
+            CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
+        }
+    } while (TRUE);
 
     /* Release the Lock, we are done */
-    DPRINT("Returning, %x. Status: %d\n",  KeGetCurrentThread(), WaitStatus);
     KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
     return WaitStatus;
 
@@ -679,177 +857,8 @@ DontWait:
     KiAdjustQuantumThread(CurrentThread);
 
     /* Release & Return */
-    DPRINT("Returning, %x. Status: %d\n. We did not wait.",
-             KeGetCurrentThread(), WaitStatus);
     KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
     return WaitStatus;
 }
 
-VOID
-FASTCALL
-KiWaitTest(PVOID ObjectPointer,
-           KPRIORITY Increment)
-{
-    PLIST_ENTRY WaitEntry;
-    PLIST_ENTRY WaitList;
-    PKWAIT_BLOCK CurrentWaitBlock;
-    PKWAIT_BLOCK NextWaitBlock;
-    PKTHREAD WaitThread;
-    PKMUTANT FirstObject = ObjectPointer, Object;
-
-    /* Loop the Wait Entries */
-    DPRINT("KiWaitTest for Object: %x\n", FirstObject);
-    WaitList = &FirstObject->Header.WaitListHead;
-    WaitEntry = WaitList->Flink;
-    while ((FirstObject->Header.SignalState > 0) && (WaitEntry != WaitList))
-    {
-        /* Get the current wait block */
-        CurrentWaitBlock = CONTAINING_RECORD(WaitEntry,
-                                             KWAIT_BLOCK,
-                                             WaitListEntry);
-        WaitThread = CurrentWaitBlock->Thread;
-
-        /* Check the current Wait Mode */
-        if (CurrentWaitBlock->WaitType == WaitAny)
-        {
-            /* Easy case, satisfy only this wait */
-            DPRINT("Satisfiying a Wait any\n");
-            WaitEntry = WaitEntry->Blink;
-            KiSatisfyObjectWait(FirstObject, WaitThread);
-        }
-        else
-        {
-            /* Everything must be satisfied */
-            DPRINT("Checking for a Wait All\n");
-            NextWaitBlock = CurrentWaitBlock->NextWaitBlock;
-
-            /* Loop first to make sure they are valid */
-            while (NextWaitBlock != CurrentWaitBlock)
-            {
-                /* Check if the object is signaled */
-                Object = NextWaitBlock->Object;
-                DPRINT("Checking: %p %d\n",
-                        Object, Object->Header.SignalState);
-                if (NextWaitBlock->WaitKey != STATUS_TIMEOUT)
-                {
-                    /* Check if this is a mutant */
-                    if ((Object->Header.Type == MutantObject) &&
-                        (Object->Header.SignalState <= 0) &&
-                        (WaitThread == Object->OwnerThread))
-                    {
-                        /* It's a signaled mutant */
-                    }
-                    else if (Object->Header.SignalState <= 0)
-                    {
-                        /* Skip the unwaiting */
-                        goto SkipUnwait;
-                    }
-                }
-
-                /* Go to the next Wait block */
-                NextWaitBlock = NextWaitBlock->NextWaitBlock;
-            }
-
-            /* All the objects are signaled, we can satisfy */
-            DPRINT("Satisfiying a Wait All\n");
-            WaitEntry = WaitEntry->Blink;
-            KiWaitSatisfyAll(CurrentWaitBlock);
-        }
-
-        /* All waits satisfied, unwait the thread */
-        DPRINT("Unwaiting the Thread\n");
-        KiAbortWaitThread(WaitThread, CurrentWaitBlock->WaitKey, Increment);
-
-SkipUnwait:
-        /* Next entry */
-        WaitEntry = WaitEntry->Flink;
-    }
-
-    DPRINT("Done\n");
-}
-
-/* Must be called with the dispatcher lock held */
-VOID
-FASTCALL
-KiAbortWaitThread(PKTHREAD Thread,
-                  NTSTATUS WaitStatus,
-                  KPRIORITY Increment)
-{
-    PKWAIT_BLOCK WaitBlock;
-
-    /* If we are blocked, we must be waiting on something also */
-    DPRINT("KiAbortWaitThread: %x, Status: %x, %x \n",
-            Thread, WaitStatus, Thread->WaitBlockList);
-
-    /* Remove the Wait Blocks from the list */
-    DPRINT("Removing waits\n");
-    WaitBlock = Thread->WaitBlockList;
-    do
-    {
-        /* Remove it */
-        DPRINT("Removing Waitblock: %x, %x\n",
-                WaitBlock, WaitBlock->NextWaitBlock);
-        RemoveEntryList(&WaitBlock->WaitListEntry);
-
-        /* Go to the next one */
-        WaitBlock = WaitBlock->NextWaitBlock;
-    } while (WaitBlock != Thread->WaitBlockList);
-
-    /* Check if there's a Thread Timer */
-    if (Thread->Timer.Header.Inserted)
-    {
-        /* Cancel the Thread Timer with the no-lock fastpath */
-        DPRINT("Removing the Thread's Timer\n");
-        Thread->Timer.Header.Inserted = FALSE;
-        RemoveEntryList(&Thread->Timer.TimerListEntry);
-    }
-
-    /* Increment the Queue's active threads */
-    if (Thread->Queue)
-    {
-        DPRINT("Incrementing Queue's active threads\n");
-        Thread->Queue->CurrentCount++;
-    }
-
-    /* Reschedule the Thread */
-    DPRINT("Unblocking the Thread\n");
-    KiUnblockThread(Thread, &WaitStatus, 0);
-}
-
-VOID
-FASTCALL
-KiAcquireFastMutex(IN PFAST_MUTEX FastMutex)
-{
-    /* Increase contention count */
-    FastMutex->Contention++;
-
-    /* Wait for the event */
-    KeWaitForSingleObject(&FastMutex->Gate,
-                          WrMutex,
-                          KernelMode,
-                          FALSE,
-                          NULL);
-}
-
-VOID
-FASTCALL
-KiExitDispatcher(KIRQL OldIrql)
-{
-    /* If it's the idle thread, dispatch */
-    if (!(KeIsExecutingDpc()) &&
-        (OldIrql < DISPATCH_LEVEL) &&
-        (KeGetCurrentThread()) &&
-        (KeGetCurrentThread() == KeGetCurrentPrcb()->IdleThread))
-    {
-        KiDispatchThreadNoLock(Ready);
-    }
-    else
-    {
-        KeReleaseDispatcherDatabaseLockFromDpcLevel();    
-    }
-
-    /* Lower irql back */
-    KeLowerIrql(OldIrql);
-}
-
 /* EOF */