- Use _SEH2_YIELD when returning from an exception instead of returning outside the...
[reactos.git] / reactos / ntoskrnl / ke / wait.c
index 2bc9db9..2e9c1c8 100644 (file)
 /*
- * 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 dispatch level wait-related code
- * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
+ * PURPOSE:         Manages waiting for Dispatcher Objects
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
  *                  Gunnar Dalsnes
  */
 
 /* INCLUDES ******************************************************************/
 
 #include <ntoskrnl.h>
-
 #define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
 
-/* GLOBALS ******************************************************************/
+/* PRIVATE FUNCTIONS *********************************************************/
 
-static KSPIN_LOCK DispatcherDatabaseLock;
+VOID
+FASTCALL
+KiWaitTest(IN PVOID ObjectPointer,
+           IN KPRIORITY Increment)
+{
+    PLIST_ENTRY WaitEntry, WaitList;
+    PKWAIT_BLOCK WaitBlock;
+    PKTHREAD WaitThread;
+    PKMUTANT FirstObject = ObjectPointer;
+    NTSTATUS WaitStatus;
 
-/* Tells us if the Timer or Event is a Syncronization or Notification Object */
-#define TIMER_OR_EVENT_TYPE 0x7L
+    /* Loop the Wait Entries */
+    WaitList = &FirstObject->Header.WaitListHead;
+    WaitEntry = WaitList->Flink;
+    while ((FirstObject->Header.SignalState > 0) && (WaitEntry != WaitList))
+    {
+        /* Get the current wait block */
+        WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry);
+        WaitThread = WaitBlock->Thread;
+        WaitStatus = STATUS_KERNEL_APC;
 
-/* One of the Reserved Wait Blocks, this one is for the Thread's Timer */
-#define TIMER_WAIT_BLOCK 0x3L
+        /* Check the current Wait Mode */
+        if (WaitBlock->WaitType == WaitAny)
+        {
+            /* Easy case, satisfy only this wait */
+            WaitStatus = (NTSTATUS)WaitBlock->WaitKey;
+            KiSatisfyObjectWait(FirstObject, WaitThread);
+        }
 
-/* FUNCTIONS *****************************************************************/
+        /* Now do the rest of the unwait */
+        KiUnwaitThread(WaitThread, WaitStatus, Increment);
+        WaitEntry = WaitList->Flink;
+    }
+}
 
-BOOLEAN
-__inline
+VOID
 FASTCALL
-KiCheckAlertability(BOOLEAN Alertable,
-                    PKTHREAD CurrentThread,
-                    KPROCESSOR_MODE WaitMode,
-                    PNTSTATUS Status)
+KiUnlinkThread(IN PKTHREAD Thread,
+               IN NTSTATUS WaitStatus)
 {
-    /* At this point, we have to do a wait, so make sure we can make the thread Alertable if requested */
-    if (Alertable) {
+    PKWAIT_BLOCK WaitBlock;
+    PKTIMER Timer;
 
-        /* If the Thread is Alerted, set the Wait Status accordingly */
-        if (CurrentThread->Alerted[(int)WaitMode]) {
+    /* Update wait status */
+    Thread->WaitStatus |= WaitStatus;
 
-            CurrentThread->Alerted[(int)WaitMode] = FALSE;
-            DPRINT("Thread was Alerted\n");
-            *Status = STATUS_ALERTED;
-            return TRUE;
+    /* Remove the Wait Blocks from the list */
+    WaitBlock = Thread->WaitBlockList;
+    do
+    {
+        /* Remove it */
+        RemoveEntryList(&WaitBlock->WaitListEntry);
 
-        /* If there are User APCs Pending, then we can't really be alertable */
-        } else if ((!IsListEmpty(&CurrentThread->ApcState.ApcListHead[UserMode])) &&
-                    (WaitMode != KernelMode)) {
+        /* Go to the next one */
+        WaitBlock = WaitBlock->NextWaitBlock;
+    } while (WaitBlock != Thread->WaitBlockList);
 
-            DPRINT("APCs are Pending\n");
-            CurrentThread->ApcState.UserApcPending = TRUE;
-            *Status = STATUS_USER_APC;
-            return TRUE;
-        }
+    /* Remove the thread from the wait list! */
+    if (Thread->WaitListEntry.Flink) RemoveEntryList(&Thread->WaitListEntry);
 
-    /* If there are User APCs Pending and we are waiting in usermode, then we must notify the caller */
-    } else if ((CurrentThread->ApcState.UserApcPending) && (WaitMode != KernelMode)) {
-            DPRINT("APCs are Pending\n");
-            *Status = STATUS_USER_APC;
-            return TRUE;
-    }
+    /* Check if there's a Thread Timer */
+    Timer = &Thread->Timer;
+    if (Timer->Header.Inserted) KxRemoveTreeTimer(Timer);
 
-    return FALSE;
+    /* Increment the Queue's active threads */
+    if (Thread->Queue) Thread->Queue->CurrentCount++;
 }
 
-/*
- * @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)
+/* Must be called with the dispatcher lock held */
+VOID
+FASTCALL
+KiUnwaitThread(IN PKTHREAD Thread,
+               IN NTSTATUS WaitStatus,
+               IN KPRIORITY Increment)
 {
-    PKWAIT_BLOCK TimerWaitBlock;
-    PKTIMER ThreadTimer;
-    PKTHREAD CurrentThread = KeGetCurrentThread();
-    NTSTATUS Status;
+    /* Unlink the thread */
+    KiUnlinkThread(Thread, WaitStatus);
 
-    DPRINT("Entering KeDelayExecutionThread\n");
+    /* Tell the scheduler do to the increment when it readies the thread */
+    ASSERT(Increment >= 0);
+    Thread->AdjustIncrement = (SCHAR)Increment;
+    Thread->AdjustReason = AdjustUnwait;
 
-    /* Check if the lock is already held */
-    if (CurrentThread->WaitNext)  {
+    /* Reschedule the Thread */
+    KiReadyThread(Thread);
+}
 
-        /* Lock is held, disable Wait Next */
-        DPRINT("Lock is held\n");
-        CurrentThread->WaitNext = FALSE;
+VOID
+FASTCALL
+KiAcquireFastMutex(IN PFAST_MUTEX FastMutex)
+{
+    /* Increase contention count */
+    FastMutex->Contention++;
 
-    } else {
+    /* Wait for the event */
+    KeWaitForSingleObject(&FastMutex->Gate,
+                          WrMutex,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+}
 
-        /* Lock not held, acquire it */
-        DPRINT("Lock is not held, acquiring\n");
-        CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
+VOID
+FASTCALL
+KiAcquireGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
+{
+    ULONG BitsToRemove, BitsToAdd;
+    LONG OldValue, NewValue;
+
+    /* We depend on these bits being just right */
+    C_ASSERT((GM_LOCK_WAITER_WOKEN * 2) == GM_LOCK_WAITER_INC);
+    
+    /* Increase the contention count */
+    GuardedMutex->Contention++;
+    
+    /* Start by unlocking the Guarded Mutex */
+    BitsToRemove = GM_LOCK_BIT;
+    BitsToAdd = GM_LOCK_WAITER_INC;
+    
+    /* Start change loop */
+    for (;;)
+    {
+        /* Loop sanity checks */
+        ASSERT((BitsToRemove == GM_LOCK_BIT) ||
+               (BitsToRemove == (GM_LOCK_BIT | GM_LOCK_WAITER_WOKEN)));
+        ASSERT((BitsToAdd == GM_LOCK_WAITER_INC) ||
+               (BitsToAdd == GM_LOCK_WAITER_WOKEN));
+        
+        /* Get the Count Bits */
+        OldValue = GuardedMutex->Count;
+        
+        /* Start internal bit change loop */
+        for (;;)
+        {
+            /* Check if the Guarded Mutex is locked */
+            if (OldValue & GM_LOCK_BIT)
+            {
+                /* Sanity check */
+                ASSERT((BitsToRemove == GM_LOCK_BIT) ||
+                       ((OldValue & GM_LOCK_WAITER_WOKEN) != 0));
+                
+                /* Unlock it by removing the Lock Bit */
+                NewValue = OldValue ^ BitsToRemove;
+                NewValue = InterlockedCompareExchange(&GuardedMutex->Count,
+                                                      NewValue,
+                                                      OldValue);
+                if (NewValue == OldValue) return;
+            }
+            else
+            {
+                /* The Guarded Mutex isn't locked, so simply set the bits */
+                NewValue = OldValue + BitsToAdd;
+                NewValue = InterlockedCompareExchange(&GuardedMutex->Count,
+                                                      NewValue,
+                                                      OldValue);
+                if (NewValue == OldValue) break;
+            }
+            
+            /* Old value changed, loop again */
+            OldValue = NewValue;
+        }
+        
+        /* Now we have to wait for it */
+        KeWaitForGate(&GuardedMutex->Gate, WrGuardedMutex, KernelMode);
+        ASSERT((GuardedMutex->Count & GM_LOCK_WAITER_WOKEN) != 0);
+        
+        /* Ok, the wait is done, so set the new bits */
+        BitsToRemove = GM_LOCK_BIT | GM_LOCK_WAITER_WOKEN;
+        BitsToAdd = GM_LOCK_WAITER_WOKEN;
     }
+}
 
-    /* Use built-in Wait block */
-    TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK];
-
-    /* Start Wait Loop */
-    do {
-
-        /* We are going to wait no matter what (that's the point), so test Alertability */
-        if (KiCheckAlertability(Alertable, CurrentThread, WaitMode, &Status))
-            break;
-
-        /* Set Timer */
-        ThreadTimer = &CurrentThread->Timer;
-
-        /* Setup the Wait Block */
-        CurrentThread->WaitBlockList = TimerWaitBlock;
-        TimerWaitBlock->Object = (PVOID)ThreadTimer;
-        TimerWaitBlock->Thread = CurrentThread;
-        TimerWaitBlock->WaitKey = (USHORT)STATUS_TIMEOUT;
-        TimerWaitBlock->WaitType = WaitAny;
-        TimerWaitBlock->NextWaitBlock = TimerWaitBlock;
+//
+// This routine exits the dispatcher after a compatible operation and
+// swaps the context to the next scheduled thread on the current CPU if
+// one is available.
+//
+// It does NOT attempt to scan for a new thread to schedule.
+//
+VOID
+FASTCALL
+KiExitDispatcher(IN KIRQL OldIrql)
+{
+    PKPRCB Prcb = KeGetCurrentPrcb();
+    PKTHREAD Thread, NextThread;
+    BOOLEAN PendingApc;
+
+    /* Make sure we're at synchronization level */
+    ASSERT(KeGetCurrentIrql() == SYNCH_LEVEL);
+
+    /* Check if we have deferred threads */
+    KiCheckDeferredReadyList(Prcb);
+
+    /* Check if we were called at dispatcher level or higher */
+    if (OldIrql >= DISPATCH_LEVEL)
+    {
+        /* Check if we have a thread to schedule, and that no DPC is active */
+        if ((Prcb->NextThread) && !(Prcb->DpcRoutineActive))
+        {
+            /* Request DPC interrupt */
+            HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
+        }
 
-        /* Link the timer to this Wait Block */
-        InitializeListHead(&ThreadTimer->Header.WaitListHead);
-        InsertTailList(&ThreadTimer->Header.WaitListHead, &TimerWaitBlock->WaitListEntry);
+        /* Lower IRQL and exit */
+        goto Quickie;
+    }
 
-        /* Insert the Timer into the Timer Lists and enable it */
-        if (!KiInsertTimer(ThreadTimer, *Interval)) {
+    /* Make sure there's a new thread scheduled */
+    if (!Prcb->NextThread) goto Quickie;
 
-            /* FIXME: The timer already expired, we should find a new ready thread */
-            Status = STATUS_SUCCESS;
-            break;
-        }
+    /* Lock the PRCB */
+    KiAcquirePrcbLock(Prcb);
 
-        /* Handle Kernel Queues */
-        if (CurrentThread->Queue) {
+    /* Get the next and current threads now */
+    NextThread = Prcb->NextThread;
+    Thread = Prcb->CurrentThread;
 
-            DPRINT("Waking Queue\n");
-            KiWakeQueue(CurrentThread->Queue);
-        }
+    /* Set current thread's swap busy to true */
+    KiSetThreadSwapBusy(Thread);
 
-        /* Block the Thread */
-        DPRINT("Blocking the Thread: %d, %d, %x\n", Alertable, WaitMode, KeGetCurrentThread());
-        KiBlockThread(&Status,
-                      Alertable,
-                      WaitMode,
-                      DelayExecution);
+    /* Switch threads in PRCB */
+    Prcb->NextThread = NULL;
+    Prcb->CurrentThread = NextThread;
 
-        /* Check if we were executing an APC or if we timed out */
-        if (Status != STATUS_KERNEL_APC) {
+    /* Set thread to running */
+    NextThread->State = Running;
 
-            /* This is a good thing */
-            if (Status == STATUS_TIMEOUT) Status = STATUS_SUCCESS;
+    /* Queue it on the ready lists */
+    KxQueueReadyThread(Thread, Prcb);
 
-            /* Return Status */
-            return Status;
-        }
+    /* Set wait IRQL */
+    Thread->WaitIrql = OldIrql;
 
-        DPRINT("Looping Again\n");
-        CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
+    /* Swap threads and check if APCs were pending */
+    PendingApc = KiSwapContext(Thread, NextThread);
+    if (PendingApc)
+    {
+        /* Lower only to APC */
+        KeLowerIrql(APC_LEVEL);
 
-    } while (TRUE);
+        /* Deliver APCs */
+        KiDeliverApc(KernelMode, NULL, NULL);
+        ASSERT(OldIrql == PASSIVE_LEVEL);
+    }
 
-    /* Release the Lock, we are done */
-    DPRINT("Returning from KeDelayExecutionThread(), %x. Status: %d\n", KeGetCurrentThread(), Status);
-    KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
-    return Status;
+    /* Lower IRQl back */
+Quickie:
+    KeLowerIrql(OldIrql);
 }
 
+/* PUBLIC FUNCTIONS **********************************************************/
+
 /*
  * @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
+KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode,
+                       IN BOOLEAN Alertable,
+                       IN PLARGE_INTEGER Interval OPTIONAL)
 {
-    PDISPATCHER_HEADER CurrentObject;
-    PKWAIT_BLOCK WaitBlock;
-    PKWAIT_BLOCK TimerWaitBlock;
-    PKTIMER ThreadTimer;
-    PKTHREAD CurrentThread = KeGetCurrentThread();
-    NTSTATUS Status;
+    PKTIMER Timer;
+    PKWAIT_BLOCK TimerBlock;
+    PKTHREAD Thread = KeGetCurrentThread();
     NTSTATUS WaitStatus;
+    BOOLEAN Swappable;
+    PLARGE_INTEGER OriginalDueTime;
+    LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
+    ULONG Hand = 0;
+
+    /* If this is a user-mode wait of 0 seconds, yield execution */
+    if (!(Interval->QuadPart) && (WaitMode != KernelMode))
+    {
+        /* Make sure the wait isn't alertable or interrupting an APC */
+        if (!(Alertable) && !(Thread->ApcState.UserApcPending))
+        {
+            /* Yield execution */
+            NtYieldExecution();
+        }
+    }
 
-    DPRINT("Entering KeWaitForSingleObject\n");
+    /* Setup the original time and timer/wait blocks */
+    OriginalDueTime = Interval;
+    Timer = &Thread->Timer;
+    TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
 
     /* Check if the lock is already held */
-    if (CurrentThread->WaitNext)  {
+    if (!Thread->WaitNext) goto WaitStart;
+
+    /*  Otherwise, we already have the lock, so initialize the wait */
+    Thread->WaitNext = FALSE;
+    KxDelayThreadWait();
+
+    /* Start wait loop */
+    for (;;)
+    {
+        /* Disable pre-emption */
+        Thread->Preempted = FALSE;
+
+        /* Check if a kernel APC is pending and we're below APC_LEVEL */
+        if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
+            (Thread->WaitIrql < APC_LEVEL))
+        {
+            /* Unlock the dispatcher */
+            KiReleaseDispatcherLock(Thread->WaitIrql);
+        }
+        else
+        {
+            /* Check if we have to bail out due to an alerted state */
+            WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
+            if (WaitStatus != STATUS_WAIT_0) break;
+
+            /* Check if the timer expired */
+            InterruptTime.QuadPart = KeQueryInterruptTime();
+            if ((ULONGLONG)InterruptTime.QuadPart >= Timer->DueTime.QuadPart)
+            {
+                /* It did, so we don't need to wait */
+                goto NoWait;
+            }
 
-        /* Lock is held, disable Wait Next */
-        DPRINT("Lock is held\n");
-        CurrentThread->WaitNext = FALSE;
+            /* It didn't, so activate it */
+            Timer->Header.Inserted = TRUE;
 
-    } else {
+            /* Handle Kernel Queues */
+            if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
 
-        /* Lock not held, acquire it */
-        DPRINT("Lock is not held, acquiring\n");
-        CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
-    }
+            /* Setup the wait information */
+            Thread->State = Waiting;
 
-    /* Start the actual Loop */
-    do {
+            /* Add the thread to the wait list */
+            KiAddThreadToWaitList(Thread, Swappable);
 
-        /* Get the current Wait Status */
-        WaitStatus = CurrentThread->WaitStatus;
+            /* Insert the timer and swap the thread */
+            ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
+            KiSetThreadSwapBusy(Thread);
+            KxInsertTimer(Timer, Hand);
+            WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
 
-        /* Append wait block to the KTHREAD wait block list */
-        CurrentThread->WaitBlockList = WaitBlock = &CurrentThread->WaitBlock[0];
+            /* Check if were swapped ok */
+            if (WaitStatus != STATUS_KERNEL_APC)
+            {
+                /* This is a good thing */
+                if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS;
 
-        /* Get the Current Object */
-        CurrentObject = (PDISPATCHER_HEADER)Object;
+                /* Return Status */
+                return WaitStatus;
+            }
 
-        /* Check if the Object is Signaled */
-        if (KiIsObjectSignaled(CurrentObject, CurrentThread)) {
+            /* Recalculate due times */
+            Interval = KiRecalculateDueTime(OriginalDueTime,
+                                            &DueTime,
+                                            &NewDueTime);
+        }
 
-            /* Just unwait this guy and exit */
-            if (CurrentObject->SignalState != (LONG)MINLONG) {
+WaitStart:
+        /* Setup a new wait */
+        Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
+        KxDelayThreadWait();
+        KiAcquireDispatcherLockAtDpcLevel();
+    }
 
-                /* It has a normal signal state, so unwait it and return */
-                KiSatisfyObjectWait(CurrentObject, CurrentThread);
-                Status = STATUS_WAIT_0;
-                goto DontWait;
+    /* We're done! */
+    KiReleaseDispatcherLock(Thread->WaitIrql);
+    return WaitStatus;
+
+NoWait:
+    /* There was nothing to wait for. Did we have a wait interval? */
+    if (!Interval->QuadPart)
+    {
+        /* Unlock the dispatcher and do a yield */
+        KiReleaseDispatcherLock(Thread->WaitIrql);
+        return NtYieldExecution();
+    }
 
-            } else {
+    /* Unlock the dispatcher and adjust the quantum for a no-wait */
+    KiReleaseDispatcherLockFromDpcLevel();
+    KiAdjustQuantumThread(Thread);
+    return STATUS_SUCCESS;
+}
 
-                /* Is this a Mutant? */
-                if (CurrentObject->Type == MutantObject) {
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+KeWaitForSingleObject(IN PVOID Object,
+                      IN KWAIT_REASON WaitReason,
+                      IN KPROCESSOR_MODE WaitMode,
+                      IN BOOLEAN Alertable,
+                      IN PLARGE_INTEGER Timeout OPTIONAL)
+{
+    PKTHREAD Thread = KeGetCurrentThread();
+    PKMUTANT CurrentObject = (PKMUTANT)Object;
+    PKWAIT_BLOCK WaitBlock = &Thread->WaitBlock[0];
+    PKWAIT_BLOCK TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
+    PKTIMER Timer = &Thread->Timer;
+    NTSTATUS WaitStatus;
+    BOOLEAN Swappable;
+    LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
+    PLARGE_INTEGER OriginalDueTime = Timeout;
+    ULONG Hand = 0;
 
-                    /* According to wasm.ru, we must raise this exception (tested and true) */
-                    KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
-                    ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+    /* Check if the lock is already held */
+    if (!Thread->WaitNext) goto WaitStart;
+
+    /*  Otherwise, we already have the lock, so initialize the wait */
+    Thread->WaitNext = FALSE;
+    KxSingleThreadWait();
+
+    /* Start wait loop */
+    for (;;)
+    {
+        /* Disable pre-emption */
+        Thread->Preempted = FALSE;
+
+        /* Check if a kernel APC is pending and we're below APC_LEVEL */
+        if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
+            (Thread->WaitIrql < APC_LEVEL))
+        {
+            /* Unlock the dispatcher */
+            KiReleaseDispatcherLock(Thread->WaitIrql);
+        }
+        else
+        {
+            /* Sanity check */
+            ASSERT(CurrentObject->Header.Type != QueueObject);
+
+            /* 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) ||
+                    (Thread == CurrentObject->OwnerThread))
+                {
+                    /* Just unwait this guy and exit */
+                    if (CurrentObject->Header.SignalState != (LONG)MINLONG)
+                    {
+                        /* It has a normal signal state. Unwait and return */
+                        KiSatisfyMutantWait(CurrentObject, Thread);
+                        WaitStatus = Thread->WaitStatus;
+                        goto DontWait;
+                    }
+                    else
+                    {
+                        /* Raise an exception */
+                        KiReleaseDispatcherLock(Thread->WaitIrql);
+                        ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+                   }
                 }
             }
-        }
-
-        /* Set up the Wait Block */
-        WaitBlock->Object = CurrentObject;
-        WaitBlock->Thread = CurrentThread;
-        WaitBlock->WaitKey = (USHORT)(STATUS_WAIT_0);
-        WaitBlock->WaitType = WaitAny;
-        WaitBlock->NextWaitBlock = WaitBlock;
-
-        /* Make sure we can satisfy the Alertable request */
-        if (KiCheckAlertability(Alertable, CurrentThread, WaitMode, &Status))
-            break;
-
-        /* Set the Wait Status */
-        CurrentThread->WaitStatus = Status;
-
-        /* Enable the Timeout Timer if there was any specified */
-        if (Timeout != NULL) {
-
-            /* However if 0 timeout was specified, then we must fail since we need to peform a wait */
-            if (!Timeout->QuadPart) {
-
-                /* Return a timeout */
-                Status = STATUS_TIMEOUT;
+            else if (CurrentObject->Header.SignalState > 0)
+            {
+                /* Another satisfied object */
+                KiSatisfyNonMutantWait(CurrentObject);
+                WaitStatus = STATUS_WAIT_0;
                 goto DontWait;
             }
 
-            /* 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;
+            /* Make sure we can satisfy the Alertable request */
+            WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
+            if (WaitStatus != STATUS_WAIT_0) break;
+
+            /* Enable the Timeout Timer if there was any specified */
+            if (Timeout)
+            {
+                /* Check if the timer expired */
+                InterruptTime.QuadPart = KeQueryInterruptTime();
+                if ((ULONGLONG)InterruptTime.QuadPart >=
+                    Timer->DueTime.QuadPart)
+                {
+                    /* It did, so we don't need to wait */
+                    WaitStatus = STATUS_TIMEOUT;
+                    goto DontWait;
+                }
 
-            /* Set up the Timer Wait Block */
-            TimerWaitBlock->Object = (PVOID)ThreadTimer;
-            TimerWaitBlock->Thread = CurrentThread;
-            TimerWaitBlock->WaitKey = STATUS_TIMEOUT;
-            TimerWaitBlock->WaitType = WaitAny;
-            TimerWaitBlock->NextWaitBlock = WaitBlock;
+                /* It didn't, so activate it */
+                Timer->Header.Inserted = TRUE;
+            }
 
-            /* Link the timer to this Wait Block */
-            InitializeListHead(&ThreadTimer->Header.WaitListHead);
-            InsertTailList(&ThreadTimer->Header.WaitListHead, &TimerWaitBlock->WaitListEntry);
+            /* Link the Object to this Wait Block */
+            InsertTailList(&CurrentObject->Header.WaitListHead,
+                           &WaitBlock->WaitListEntry);
 
-            /* Insert the Timer into the Timer Lists and enable it */
-            if (!KiInsertTimer(ThreadTimer, *Timeout)) {
+            /* Handle Kernel Queues */
+            if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
 
-                /* Return a timeout if we couldn't insert the timer for some reason */
-                Status = STATUS_TIMEOUT;
-                goto DontWait;
-            }
-        }
+            /* Setup the wait information */
+            Thread->State = Waiting;
 
-        /* Link the Object to this Wait Block */
-        InsertTailList(&CurrentObject->WaitListHead, &WaitBlock->WaitListEntry);
+            /* Add the thread to the wait list */
+            KiAddThreadToWaitList(Thread, Swappable);
 
-        /* Handle Kernel Queues */
-        if (CurrentThread->Queue) {
+            /* Activate thread swap */
+            ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
+            KiSetThreadSwapBusy(Thread);
 
-            DPRINT("Waking Queue\n");
-            KiWakeQueue(CurrentThread->Queue);
-        }
+            /* Check if we have a timer */
+            if (Timeout)
+            {
+                /* Insert it */
+                KxInsertTimer(Timer, Hand);
+            }
+            else
+            {
+                /* Otherwise, unlock the dispatcher */
+                KiReleaseDispatcherLockFromDpcLevel();
+            }
 
-        /* Block the Thread */
-        DPRINT("Blocking the Thread: %d, %d, %d, %x\n", Alertable, WaitMode, WaitReason, KeGetCurrentThread());
-        KiBlockThread(&Status,
-                      Alertable,
-                      WaitMode,
-                      (UCHAR)WaitReason);
+            /* Do the actual swap */
+            WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
 
-        /* Check if we were executing an APC */
-        if (Status != STATUS_KERNEL_APC) {
+            /* Check if we were executing an APC */
+            if (WaitStatus != STATUS_KERNEL_APC) return WaitStatus;
 
-            /* Return Status */
-            return Status;
+            /* Check if we had a timeout */
+            if (Timeout)
+            {
+                /* Recalculate due times */
+                Timeout = KiRecalculateDueTime(OriginalDueTime,
+                                               &DueTime,
+                                               &NewDueTime);
+            }
         }
+WaitStart:
+        /* Setup a new wait */
+        Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
+        KxSingleThreadWait();
+        KiAcquireDispatcherLockAtDpcLevel();
+    }
 
-        DPRINT("Looping Again\n");
-        CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
-
-    } while (TRUE);
-
-    /* Release the Lock, we are done */
-    DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n", KeGetCurrentThread(), Status);
-    KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
-    return Status;
+    /* Wait complete */
+    KiReleaseDispatcherLock(Thread->WaitIrql);
+    return WaitStatus;
 
 DontWait:
-    /* Adjust the Quantum */
-    KiAdjustQuantumThread(CurrentThread);
+    /* Release dispatcher lock but maintain high IRQL */
+    KiReleaseDispatcherLockFromDpcLevel();
 
-    /* Release & Return */
-    DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n. We did not wait.", KeGetCurrentThread(), Status);
-    KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
-    return Status;
+    /* Adjust the Quantum and return the wait status */
+    KiAdjustQuantumThread(Thread);
+    return WaitStatus;
 }
 
 /*
  * @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)
+NTSTATUS
+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)
 {
-    PDISPATCHER_HEADER CurrentObject;
+    PKMUTANT CurrentObject;
     PKWAIT_BLOCK WaitBlock;
-    PKWAIT_BLOCK TimerWaitBlock;
-    PKTIMER ThreadTimer;
-    PKTHREAD CurrentThread = KeGetCurrentThread();
-    ULONG AllObjectsSignaled;
-    ULONG WaitIndex;
-    NTSTATUS Status;
-    NTSTATUS WaitStatus;
-
-    DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
-            "PsGetCurrentThread() %x, Timeout %x\n", Count, Object, PsGetCurrentThread(), Timeout);
-
-    /* Set the Current Thread */
-    CurrentThread = KeGetCurrentThread();
-
-    /* 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();
-    }
-
-    /* Make sure the Wait Count is valid for the Thread and Maximum Wait Objects */
-    if (!WaitBlockArray) {
-
+    PKTHREAD Thread = KeGetCurrentThread();
+    PKWAIT_BLOCK TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
+    PKTIMER Timer = &Thread->Timer;
+    NTSTATUS WaitStatus = STATUS_SUCCESS;
+    BOOLEAN Swappable;
+    PLARGE_INTEGER OriginalDueTime = Timeout;
+    LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
+    ULONG Index, Hand = 0;
+
+    /* 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);
+        WaitBlockArray = &Thread->WaitBlock[0];
+    }
+    else
+    {
+        /* 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 {
-
-        /* Get the current Wait Status */
-        WaitStatus = CurrentThread->WaitStatus;
-
-        /* Append wait block to the KTHREAD wait block list */
-        CurrentThread->WaitBlockList = WaitBlock = WaitBlockArray;
-
-        /* Check if the wait is (already) satisfied */
-        AllObjectsSignaled = TRUE;
-
-        /* First, we'll try to satisfy the wait directly */
-        for (WaitIndex = 0; WaitIndex < Count; WaitIndex++) {
-
-            /* Get the Current Object */
-            CurrentObject = (PDISPATCHER_HEADER)Object[WaitIndex];
+    /* Sanity check */
+    ASSERT(Count != 0);
 
-            /* Check if the Object is Signaled */
-            if (KiIsObjectSignaled(CurrentObject, CurrentThread)) {
-
-                /* Check what kind of wait this is */
-                if (WaitType == WaitAny) {
-
-                    /* This is a Wait Any, so just unwait this guy and exit */
-                    if (CurrentObject->SignalState != (LONG)MINLONG) {
-
-                        /* It has a normal signal state, so unwait it and return */
-                        KiSatisfyObjectWait(CurrentObject, CurrentThread);
-                        Status = STATUS_WAIT_0 | WaitIndex;
+    /* Check if the lock is already held */
+    if (!Thread->WaitNext) goto WaitStart;
+
+    /*  Otherwise, we already have the lock, so initialize the wait */
+    Thread->WaitNext = FALSE;
+    /*  Note that KxMultiThreadWait is a macro, defined in ke_x.h, that  */
+    /*  uses  (and modifies some of) the following local                 */
+    /*  variables:                                                       */
+    /*  Thread, Index, WaitBlock, Timer, Timeout, Hand and Swappable.    */
+    /*  If it looks like this code doesn't actually wait for any objects */
+    /*  at all, it's because the setup is done by that macro.            */
+    KxMultiThreadWait();
+
+    /* Start wait loop */
+    for (;;)
+    {
+        /* Disable pre-emption */
+        Thread->Preempted = FALSE;
+
+        /* Check if a kernel APC is pending and we're below APC_LEVEL */
+        if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
+            (Thread->WaitIrql < APC_LEVEL))
+        {
+            /* Unlock the dispatcher */
+            KiReleaseDispatcherLock(Thread->WaitIrql);
+        }
+        else
+        {
+            /* Check what kind of wait this is */
+            Index = 0;
+            if (WaitType == WaitAny)
+            {
+                /* Loop blocks */
+                do
+                {
+                    /* Get the Current Object */
+                    CurrentObject = (PKMUTANT)Object[Index];
+                    ASSERT(CurrentObject->Header.Type != QueueObject);
+
+                    /* Check if the Object is a mutant */
+                    if (CurrentObject->Header.Type == MutantObject)
+                    {
+                        /* Check if it's signaled */
+                        if ((CurrentObject->Header.SignalState > 0) ||
+                            (Thread == CurrentObject->OwnerThread))
+                        {
+                            /* 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, Thread);
+                                WaitStatus = Thread->WaitStatus | Index;
+                                goto DontWait;
+                            }
+                            else
+                            {
+                                /* Raise an exception (see wasm.ru) */
+                                KiReleaseDispatcherLock(Thread->WaitIrql);
+                                ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+                            }
+                        }
+                    }
+                    else if (CurrentObject->Header.SignalState > 0)
+                    {
+                        /* Another signaled object, unwait and return */
+                        KiSatisfyNonMutantWait(CurrentObject);
+                        WaitStatus = Index;
                         goto DontWait;
+                    }
 
-                    } else {
-
-                        /* Is this a Mutant? */
-                        if (CurrentObject->Type == MutantObject) {
-
-                            /* According to wasm.ru, we must raise this exception (tested and true) */
-                            KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+                    /* Go to the next block */
+                    Index++;
+                } while (Index < Count);
+            }
+            else
+            {
+                /* Loop blocks */
+                do
+                {
+                    /* Get the Current Object */
+                    CurrentObject = (PKMUTANT)Object[Index];
+                    ASSERT(CurrentObject->Header.Type != QueueObject);
+
+                    /* Check if we're dealing with a mutant again */
+                    if (CurrentObject->Header.Type == MutantObject)
+                    {
+                        /* Check if it has an invalid count */
+                        if ((Thread == CurrentObject->OwnerThread) &&
+                            (CurrentObject->Header.SignalState == (LONG)MINLONG))
+                        {
+                            /* Raise an exception */
+                            KiReleaseDispatcherLock(Thread->WaitIrql);
                             ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
                         }
+                        else if ((CurrentObject->Header.SignalState <= 0) &&
+                                 (Thread != CurrentObject->OwnerThread))
+                        {
+                            /* We don't own it, can't satisfy the wait */
+                            break;
+                        }
+                    }
+                    else if (CurrentObject->Header.SignalState <= 0)
+                    {
+                        /* Not signaled, can't satisfy */
+                        break;
                     }
-                }
-
-            } else {
-
-                /* One of the objects isn't signaled... if this is a WaitAll, we will fail later */
-                AllObjectsSignaled = FALSE;
-            }
-
-            /* Set up a Wait Block for this Object */
-            WaitBlock->Object = CurrentObject;
-            WaitBlock->Thread = CurrentThread;
-            WaitBlock->WaitKey = (USHORT)(STATUS_WAIT_0 + WaitIndex);
-            WaitBlock->WaitType = (USHORT)WaitType;
-            WaitBlock->NextWaitBlock = WaitBlock + 1;
-
-            /* Move to the next Wait Block */
-            WaitBlock = WaitBlock->NextWaitBlock;
-        }
-
-        /* Return to the Root Wait Block */
-        WaitBlock--;
-        WaitBlock->NextWaitBlock = WaitBlockArray;
-
-        /* 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;
-
-            /* Satisfy their Waits and return to the caller */
-            KiSatisifyMultipleObjectWaits(WaitBlock);
-            Status = STATUS_WAIT_0;
-            goto DontWait;
-        }
-
-        /* Make sure we can satisfy the Alertable request */
-        if (KiCheckAlertability(Alertable, CurrentThread, WaitMode, &Status))
-            break;
-
-        /* Set the Wait Status */
-        CurrentThread->WaitStatus = Status;
-
-        /* Enable the Timeout Timer if there was any specified */
-        if (Timeout != NULL) {
-
-            /* However if 0 timeout was specified, then we must fail since we need to peform a wait */
-            if (!Timeout->QuadPart) {
 
-                /* Return a timeout */
-                Status = STATUS_TIMEOUT;
-                goto DontWait;
+                    /* Go to the next block */
+                    Index++;
+                } while (Index < Count);
+
+                /* Check if we've went through all the objects */
+                if (Index == Count)
+                {
+                    /* Loop wait blocks */
+                    WaitBlock = WaitBlockArray;
+                    do
+                    {
+                        /* Get the object and satisfy it */
+                        CurrentObject = (PKMUTANT)WaitBlock->Object;
+                        KiSatisfyObjectWait(CurrentObject, Thread);
+
+                        /* Go to the next block */
+                        WaitBlock = WaitBlock->NextWaitBlock;
+                    } while(WaitBlock != WaitBlockArray);
+
+                    /* Set the wait status and get out */
+                    WaitStatus = Thread->WaitStatus;
+                    goto DontWait;
+                }
             }
 
-            /* 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;
-
-            /* Set up the Timer Wait Block */
-            TimerWaitBlock->Object = (PVOID)ThreadTimer;
-            TimerWaitBlock->Thread = CurrentThread;
-            TimerWaitBlock->WaitKey = STATUS_TIMEOUT;
-            TimerWaitBlock->WaitType = WaitAny;
-            TimerWaitBlock->NextWaitBlock = WaitBlockArray;
-
-            /* Link the timer to this Wait Block */
-            InitializeListHead(&ThreadTimer->Header.WaitListHead);
+            /* Make sure we can satisfy the Alertable request */
+            WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
+            if (WaitStatus != STATUS_WAIT_0) break;
+
+            /* Enable the Timeout Timer if there was any specified */
+            if (Timeout)
+            {
+                /* Check if the timer expired */
+                InterruptTime.QuadPart = KeQueryInterruptTime();
+                if ((ULONGLONG)InterruptTime.QuadPart >=
+                    Timer->DueTime.QuadPart)
+                {
+                    /* It did, so we don't need to wait */
+                    WaitStatus = STATUS_TIMEOUT;
+                    goto DontWait;
+                }
 
-            /* Insert the Timer into the Timer Lists and enable it */
-            if (!KiInsertTimer(ThreadTimer, *Timeout)) {
+                /* It didn't, so activate it */
+                Timer->Header.Inserted = TRUE;
 
-                /* Return a timeout if we couldn't insert the timer for some reason */
-                Status = STATUS_TIMEOUT;
-                goto DontWait;
+                /* Link the wait blocks */
+                WaitBlock->NextWaitBlock = TimerBlock;
             }
-        }
-
-        /* 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->WaitListHead, &WaitBlock->WaitListEntry);
-
-            /* 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);
-        }
-
-        /* Block the Thread */
-        DPRINT("Blocking the Thread: %d, %d, %d, %x\n", Alertable, WaitMode, 
-                WaitReason, KeGetCurrentThread());
-        KiBlockThread(&Status,
-                      Alertable,
-                      WaitMode,
-                      (UCHAR)WaitReason);
-
-        /* Check if we were executing an APC */
-        DPRINT("Thread is back\n");
-        if (Status != STATUS_KERNEL_APC) {
-
-            /* Return Status */
-            return Status;
-        }
-
-        DPRINT("Looping Again\n");
-        CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
 
-    } while (TRUE);
+            /* Insert into Object's Wait List*/
+            WaitBlock = WaitBlockArray;
+            do
+            {
+                /* Get the Current Object */
+                CurrentObject = WaitBlock->Object;
 
-    /* Release the Lock, we are done */
-    DPRINT("Returning, %x. Status: %d\n",  KeGetCurrentThread(), Status);
-    KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
-    return Status;
+                /* Link the Object to this Wait Block */
+                InsertTailList(&CurrentObject->Header.WaitListHead,
+                               &WaitBlock->WaitListEntry);
 
-DontWait:
-    /* Adjust the Quantum */
-    KiAdjustQuantumThread(CurrentThread);
-
-    /* Release & Return */
-    DPRINT("Returning, %x. Status: %d\n. We did not wait.", 
-            KeGetCurrentThread(), Status);
-    KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
-    return Status;
-}
-
-VOID
-FASTCALL
-KiSatisfyObjectWait(PDISPATCHER_HEADER Object,
-                    PKTHREAD Thread)
+                /* Move to the next Wait Block */
+                WaitBlock = WaitBlock->NextWaitBlock;
+            } while (WaitBlock != WaitBlockArray);
 
-{
-    /* Special case for Mutants */
-    if (Object->Type == MutantObject) {
-
-        /* Decrease the Signal State */
-        Object->SignalState--;
-
-        /* Check if it's now non-signaled */
-        if (Object->SignalState == 0) {
+            /* Handle Kernel Queues */
+            if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
 
-            /* Set the Owner Thread */
-            ((PKMUTANT)Object)->OwnerThread = Thread;
+            /* Setup the wait information */
+            Thread->State = Waiting;
 
-            /* Disable APCs if needed */
-            Thread->KernelApcDisable -= ((PKMUTANT)Object)->ApcDisable;
+            /* Add the thread to the wait list */
+            KiAddThreadToWaitList(Thread, Swappable);
 
-            /* Check if it's abandoned */
-            if (((PKMUTANT)Object)->Abandoned) {
+            /* Activate thread swap */
+            ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
+            KiSetThreadSwapBusy(Thread);
 
-                /* Unabandon it */
-                ((PKMUTANT)Object)->Abandoned = FALSE;
-
-                /* Return Status */
-                Thread->WaitStatus = STATUS_ABANDONED;
+            /* Check if we have a timer */
+            if (Timeout)
+            {
+                /* Insert it */
+                KxInsertTimer(Timer, Hand);
+            }
+            else
+            {
+                /* Otherwise, unlock the dispatcher */
+                KiReleaseDispatcherLockFromDpcLevel();
             }
 
-            /* Insert it into the Mutant List */
-            InsertHeadList(&Thread->MutantListHead, &((PKMUTANT)Object)->MutantListEntry);
-        }
-
-    } else if ((Object->Type & TIMER_OR_EVENT_TYPE) == EventSynchronizationObject) {
-
-        /* These guys (Syncronization Timers and Events) just get un-signaled */
-        Object->SignalState = 0;
-
-    } else if (Object->Type == SemaphoreObject) {
-
-        /* These ones can have multiple signalings, so we only decrease it */
-        Object->SignalState--;
-    }
-}
-
-VOID
-FASTCALL
-KiWaitTest(PDISPATCHER_HEADER Object,
-           KPRIORITY Increment)
-{
-    PLIST_ENTRY WaitEntry;
-    PLIST_ENTRY WaitList;
-    PKWAIT_BLOCK CurrentWaitBlock;
-    PKWAIT_BLOCK NextWaitBlock;
-    PKTHREAD WaitThread;
-
-    /* Loop the Wait Entries */
-    DPRINT("KiWaitTest for Object: %x\n", Object);
-    WaitList = &Object->WaitListHead;
-    WaitEntry = WaitList->Flink;
-    while ((WaitEntry != WaitList) && (Object->SignalState > 0)) {
-
-        /* 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(Object, 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 */
-                DPRINT("Checking: %x %d\n", NextWaitBlock->Object, Object->SignalState);
-                if (!KiIsObjectSignaled(NextWaitBlock->Object, WaitThread)) {
+            /* Swap the thread */
+            WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
 
-                    /* It's not, move to the next one */
-                    DPRINT("One of the object is non-signaled, sorry.\n");
-                    goto SkipUnwait;
-                }
+            /* Check if we were executing an APC */
+            if (WaitStatus != STATUS_KERNEL_APC) return WaitStatus;
 
-                /* Go to the next Wait block */
-                NextWaitBlock = NextWaitBlock->NextWaitBlock;
+            /* Check if we had a timeout */
+            if (Timeout)
+            {
+                /* Recalculate due times */
+                Timeout = KiRecalculateDueTime(OriginalDueTime,
+                                               &DueTime,
+                                               &NewDueTime);
             }
-
-            /* All the objects are signaled, we can satisfy */
-            DPRINT("Satisfiying a Wait All\n");
-            WaitEntry = WaitEntry->Blink;
-            KiSatisifyMultipleObjectWaits(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);
-    ASSERT((Thread->State == Waiting) == (Thread->WaitBlockList != NULL));
-
-    /* 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++;
+WaitStart:
+        /* Setup a new wait */
+        Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
+        KxMultiThreadWait();
+        KiAcquireDispatcherLockAtDpcLevel();
     }
 
-    /* Reschedule the Thread */
-    DPRINT("Unblocking the Thread\n");
-    KiUnblockThread(Thread, &WaitStatus, 0);
-}
+    /* We are done */
+    KiReleaseDispatcherLock(Thread->WaitIrql);
+    return WaitStatus;
 
-VOID
-FASTCALL
-KiAcquireFastMutex(IN PFAST_MUTEX FastMutex)
-{
-    /* Increase contention count */
-    FastMutex->Contention++;
+DontWait:
+    /* Release dispatcher lock but maintain high IRQL */
+    KiReleaseDispatcherLockFromDpcLevel();
 
-    /* Wait for the event */
-    KeWaitForSingleObject(&FastMutex->Gate,
-                          WrMutex,
-                          KernelMode,
-                          FALSE,
-                          NULL);
+    /* Adjust the Quantum and return the wait status */
+    KiAdjustQuantumThread(Thread);
+    return WaitStatus;
 }
 
-BOOLEAN
-__inline
-FASTCALL
-KiIsObjectSignaled(PDISPATCHER_HEADER Object,
-                   PKTHREAD Thread)
+NTSTATUS
+NTAPI
+NtDelayExecution(IN BOOLEAN Alertable,
+                 IN PLARGE_INTEGER DelayInterval)
 {
-    /* Mutants are...well...mutants! */
-   if (Object->Type == MutantObject) {
-
-        /*
-         * Because Cutler hates mutants, they are actually signaled if the Signal State is <= 0
-         * Well, only if they are recursivly acquired (i.e if we own it right now).
-         * Of course, they are also signaled if their signal state is 1.
-         */
-        if ((Object->SignalState <= 0 && ((PKMUTANT)Object)->OwnerThread == Thread) ||
-            (Object->SignalState == 1)) {
-
-            /* Signaled Mutant */
-            return (TRUE);
-
-        } else {
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    LARGE_INTEGER SafeInterval;
+    NTSTATUS Status;
 
-            /* Unsignaled Mutant */
-            return (FALSE);
+    /* Check the previous mode */
+    if (PreviousMode != KernelMode)
+    {
+        /* Enter SEH for probing */
+        _SEH2_TRY
+        {
+            /* Probe and capture the time out */
+            SafeInterval = ProbeForReadLargeInteger(DelayInterval);
+            DelayInterval = &SafeInterval;
         }
-    }
-
-    /* Any other object is not a mutated freak, so let's use logic */
-   return (!Object->SignalState <= 0);
-}
-
-VOID
-__inline
-FASTCALL
-KiSatisifyMultipleObjectWaits(PKWAIT_BLOCK WaitBlock)
-{
-    PKWAIT_BLOCK FirstBlock = WaitBlock;
-    PKTHREAD WaitThread = WaitBlock->Thread;
-
-    /* Loop through all the Wait Blocks, and wake each Object */
-    do {
-
-        /* Wake the Object */
-        KiSatisfyObjectWait(WaitBlock->Object, WaitThread);
-        WaitBlock = WaitBlock->NextWaitBlock;
-    } while (WaitBlock != FirstBlock);
-}
-
-VOID
-__inline
-FASTCALL
-KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header,
-                             ULONG Type,
-                             ULONG Size,
-                             ULONG SignalState)
-{
-    Header->Type = (UCHAR)Type;
-    Header->Absolute = 0;
-    Header->Inserted = 0;
-    Header->Size = (UCHAR)Size;
-    Header->SignalState = SignalState;
-    InitializeListHead(&(Header->WaitListHead));
-}
-
-KIRQL
-__inline
-FASTCALL
-KeAcquireDispatcherDatabaseLock(VOID)
-{
-    KIRQL OldIrql;
-
-    KeAcquireSpinLock (&DispatcherDatabaseLock, &OldIrql);
-    return OldIrql;
-}
-
-VOID
-__inline
-FASTCALL
-KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID)
-{
-    KeAcquireSpinLockAtDpcLevel (&DispatcherDatabaseLock);
-}
-
-VOID
-__inline
-FASTCALL
-KeInitializeDispatcher(VOID)
-{
-    /* Initialize the Dispatcher Lock */
-    KeInitializeSpinLock(&DispatcherDatabaseLock);
-}
-
-VOID
-__inline
-FASTCALL
-KeReleaseDispatcherDatabaseLock(KIRQL OldIrql)
-{
-    /* If it's the idle thread, dispatch */
-    if (!KeIsExecutingDpc() && OldIrql < DISPATCH_LEVEL && KeGetCurrentThread() != NULL &&
-        KeGetCurrentThread() == KeGetCurrentPrcb()->IdleThread) {
-
-        KiDispatchThreadNoLock(Ready);
-        KeLowerIrql(OldIrql);
-
-    } else {
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+   }
 
-        /* Just release the spin lock */
-        KeReleaseSpinLock(&DispatcherDatabaseLock, OldIrql);
-    }
-}
+   /* Call the Kernel Function */
+   Status = KeDelayExecutionThread(PreviousMode,
+                                   Alertable,
+                                   DelayInterval);
 
-VOID
-__inline
-FASTCALL
-KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID)
-{
-    KeReleaseSpinLockFromDpcLevel(&DispatcherDatabaseLock);
+   /* Return Status */
+   return Status;
 }
 
 /* EOF */