[HEADERS]
[reactos.git] / reactos / ntoskrnl / ke / wait.c
index 8970ca7..a4737b0 100644 (file)
 
 #include <ntoskrnl.h>
 #define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
 
 /* PRIVATE FUNCTIONS *********************************************************/
 
-VOID
-FASTCALL
-KiWaitSatisfyAll(PKWAIT_BLOCK FirstBlock)
-{
-    PKWAIT_BLOCK WaitBlock = FirstBlock;
-    PKTHREAD WaitThread = WaitBlock->Thread;
-
-    /* Loop through all the Wait Blocks, and wake each Object */
-    do
-    {
-        /* Make sure it hasn't timed out */
-        if (WaitBlock->WaitKey != STATUS_TIMEOUT)
-        {
-            /* Wake the Object */
-            KiSatisfyObjectWait((PKMUTANT)WaitBlock->Object, WaitThread);
-        }
-
-        /* Move to the next block */
-        WaitBlock = WaitBlock->NextWaitBlock;
-    } while (WaitBlock != FirstBlock);
-}
-
 VOID
 FASTCALL
 KiWaitTest(IN PVOID ObjectPointer,
@@ -99,13 +77,7 @@ KiUnlinkThread(IN PKTHREAD Thread,
 
     /* 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);
-    }
+    if (Timer->Header.Inserted) KxRemoveTreeTimer(Timer);
 
     /* Increment the Queue's active threads */
     if (Thread->Queue) Thread->Queue->CurrentCount++;
@@ -115,7 +87,7 @@ KiUnlinkThread(IN PKTHREAD Thread,
 VOID
 FASTCALL
 KiUnwaitThread(IN PKTHREAD Thread,
-               IN NTSTATUS WaitStatus,
+               IN LONG_PTR WaitStatus,
                IN KPRIORITY Increment)
 {
     /* Unlink the thread */
@@ -138,13 +110,83 @@ KiAcquireFastMutex(IN PFAST_MUTEX FastMutex)
     FastMutex->Contention++;
 
     /* Wait for the event */
-    KeWaitForSingleObject(&FastMutex->Gate,
+    KeWaitForSingleObject(&FastMutex->Event,
                           WrMutex,
                           KernelMode,
                           FALSE,
                           NULL);
 }
 
+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;
+    }
+}
+
 //
 // This routine exits the dispatcher after a compatible operation and
 // swaps the context to the next scheduled thread on the current CPU if
@@ -161,7 +203,7 @@ KiExitDispatcher(IN KIRQL OldIrql)
     BOOLEAN PendingApc;
 
     /* Make sure we're at synchronization level */
-    ASSERT_IRQL_EQUAL(SYNCH_LEVEL);
+    ASSERT(KeGetCurrentIrql() == SYNCH_LEVEL);
 
     /* Check if we have deferred threads */
     KiCheckDeferredReadyList(Prcb);
@@ -234,89 +276,123 @@ KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode,
                        IN BOOLEAN Alertable,
                        IN PLARGE_INTEGER Interval OPTIONAL)
 {
-    PKTIMER ThreadTimer;
+    PKTIMER Timer;
+    PKWAIT_BLOCK TimerBlock;
     PKTHREAD Thread = KeGetCurrentThread();
     NTSTATUS WaitStatus;
     BOOLEAN Swappable;
-    PLARGE_INTEGER OriginalDueTime = Interval;
-    LARGE_INTEGER DueTime, NewDueTime;
+    PLARGE_INTEGER OriginalDueTime;
+    LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
+    ULONG Hand = 0;
 
-    /* Check if the lock is already held */
-    if (Thread->WaitNext)
-    {
-        /* Lock is held, disable Wait Next */
-        Thread->WaitNext = FALSE;
-        Swappable = KxDelayThreadWait(Thread, Alertable, WaitMode);
-    }
-    else
+    /* If this is a user-mode wait of 0 seconds, yield execution */
+    if (!(Interval->QuadPart) && (WaitMode != KernelMode))
     {
-        /* Lock not held, acquire it */
-WaitStart:
-        Thread->WaitIrql = KiAcquireDispatcherLock();
-        Swappable = KxDelayThreadWait(Thread, Alertable, WaitMode);
+        /* Make sure the wait isn't alertable or interrupting an APC */
+        if (!(Alertable) && !(Thread->ApcState.UserApcPending))
+        {
+            /* Yield execution */
+            NtYieldExecution();
+        }
     }
 
-    /* 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);
-        goto WaitStart;
-    }
+    /* Setup the original time and timer/wait blocks */
+    OriginalDueTime = Interval;
+    Timer = &Thread->Timer;
+    TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
 
-    /* Check if we have to bail out due to an alerted state */
-    WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
-    if (WaitStatus != STATUS_WAIT_0)
-    {
-        /* Unlock the dispatcher and return */
-        KiReleaseDispatcherLock(Thread->WaitIrql);
-        return WaitStatus;
-    }
+    /* Check if the lock is already held */
+    if (!Thread->WaitNext) goto WaitStart;
 
-    /* Set Timer */
-    ThreadTimer = &Thread->Timer;
+    /*  Otherwise, we already have the lock, so initialize the wait */
+    Thread->WaitNext = FALSE;
+    KxDelayThreadWait();
 
-    /* Insert the Timer into the Timer Lists and enable it */
-    if (!KiInsertTimer(ThreadTimer, *Interval))
+    /* Start wait loop */
+    for (;;)
     {
-        /* FIXME: We should find a new ready thread */
-        KiReleaseDispatcherLock(Thread->WaitIrql);
-        return STATUS_WAIT_0;
-    }
+        /* 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;
 
-    /* Save due time */
-    DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
+            /* 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;
+            }
 
-    /* Handle Kernel Queues */
-    if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
+            /* It didn't, so activate it */
+            Timer->Header.Inserted = TRUE;
 
-    /* Setup the wait information */
-    Thread->State = Waiting;
+            /* Handle Kernel Queues */
+            if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
 
-    /* Add the thread to the wait list */
-    KiAddThreadToWaitList(Thread, Swappable);
+            /* Setup the wait information */
+            Thread->State = Waiting;
 
-    /* Swap the thread */
-    ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
-    KiSetThreadSwapBusy(Thread);
-    WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
+            /* Add the thread to the wait list */
+            KiAddThreadToWaitList(Thread, Swappable);
 
-    /* Check if we were executing an APC or if we timed out */
-    if (WaitStatus == STATUS_KERNEL_APC)
-    {
-        /* Recalculate due times */
-        Interval = KiRecalculateDueTime(OriginalDueTime,
-                                        &DueTime,
-                                        &NewDueTime);
-        goto WaitStart;
-    }
+            /* Insert the timer and swap the thread */
+            ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
+            KiSetThreadSwapBusy(Thread);
+            KxInsertTimer(Timer, Hand);
+            WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
+
+            /* Check if were swapped ok */
+            if (WaitStatus != STATUS_KERNEL_APC)
+            {
+                /* This is a good thing */
+                if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS;
+
+                /* Return Status */
+                return WaitStatus;
+            }
 
-    /* This is a good thing */
-    if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS;
+            /* Recalculate due times */
+            Interval = KiRecalculateDueTime(OriginalDueTime,
+                                            &DueTime,
+                                            &NewDueTime);
+        }
+
+WaitStart:
+        /* Setup a new wait */
+        Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
+        KxDelayThreadWait();
+        KiAcquireDispatcherLockAtDpcLevel();
+    }
 
-    /* Return Status */
+    /* 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();
+    }
+
+    /* Unlock the dispatcher and adjust the quantum for a no-wait */
+    KiReleaseDispatcherLockFromDpcLevel();
+    KiAdjustQuantumThread(Thread);
+    return STATUS_SUCCESS;
 }
 
 /*
@@ -330,157 +406,147 @@ KeWaitForSingleObject(IN PVOID Object,
                       IN BOOLEAN Alertable,
                       IN PLARGE_INTEGER Timeout OPTIONAL)
 {
-    PKMUTANT CurrentObject;
-    PKWAIT_BLOCK WaitBlock;
-    PKTIMER ThreadTimer;
     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;
+    LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
     PLARGE_INTEGER OriginalDueTime = Timeout;
-
-    /* Get wait block */
-    WaitBlock = &Thread->WaitBlock[0];
+    ULONG Hand = 0;
 
     /* Check if the lock is already held */
-    if (Thread->WaitNext)
-    {
-        /* Lock is held, disable Wait Next */
-        Thread->WaitNext = FALSE;
-        Swappable = KxSingleThreadWait(Thread,
-                                       WaitBlock,
-                                       Object,
-                                       Timeout,
-                                       Alertable,
-                                       WaitReason,
-                                       WaitMode);
-    }
-    else
-    {
-StartWait:
-        /* Lock not held, acquire it */
-        Thread->WaitIrql = KiAcquireDispatcherLock();
-        Swappable = KxSingleThreadWait(Thread,
-                                       WaitBlock,
-                                       Object,
-                                       Timeout,
-                                       WaitReason,
-                                       WaitMode,
-                                       Alertable);
-    }
+    if (!Thread->WaitNext) goto WaitStart;
 
-    /* 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 and wait again */
-        KiReleaseDispatcherLock(Thread->WaitIrql);
-        goto StartWait;
-    }
-
-    /* Get the Current Object */
-    CurrentObject = (PKMUTANT)Object;
-    ASSERT(CurrentObject->Header.Type != QueueObject);
+    /*  Otherwise, we already have the lock, so initialize the wait */
+    Thread->WaitNext = FALSE;
+    KxSingleThreadWait();
 
-    /* Check if it's a mutant */
-    if (CurrentObject->Header.Type == MutantObject)
+    /* Start wait loop */
+    for (;;)
     {
-        /* Check its signal state or if we own it */
-        if ((CurrentObject->Header.SignalState > 0) ||
-            (Thread == CurrentObject->OwnerThread))
+        /* 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))
         {
-            /* Just unwait this guy and exit */
-            if (CurrentObject->Header.SignalState != (LONG)MINLONG)
+            /* 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);
+                   }
+                }
+            }
+            else if (CurrentObject->Header.SignalState > 0)
             {
-                /* It has a normal signal state. Unwait and return */
-                KiSatisfyMutantWait(CurrentObject, Thread);
-                WaitStatus = Thread->WaitStatus;
+                /* Another satisfied object */
+                KiSatisfyNonMutantWait(CurrentObject);
+                WaitStatus = STATUS_WAIT_0;
                 goto DontWait;
             }
-            else
+
+            /* 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)
             {
-                /* Raise an exception */
-                KiReleaseDispatcherLock(Thread->WaitIrql);
-                ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
-           }
-        }
-    }
-    else if (CurrentObject->Header.SignalState > 0)
-    {
-        /* Another satisfied object */
-        KiSatisfyNonMutantWait(CurrentObject, Thread);
-        WaitStatus = STATUS_WAIT_0;
-        goto DontWait;
-    }
+                /* 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;
+                }
 
-    /* Make sure we can satisfy the Alertable request */
-    WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
-    if (WaitStatus != STATUS_WAIT_0)
-    {
-        /* Unlock the dispatcher and return */
-        KiReleaseDispatcherLock(Thread->WaitIrql);
-        return WaitStatus;
-    }
+                /* It didn't, so activate it */
+                Timer->Header.Inserted = TRUE;
+            }
 
-    /* Enable the Timeout Timer if there was any specified */
-    if (Timeout)
-    {
-        /* Fail if the timeout interval is actually 0 */
-        if (!Timeout->QuadPart)
-        {
-            /* Return a timeout */
-            WaitStatus = STATUS_TIMEOUT;
-            goto DontWait;
-        }
+            /* Link the Object to this Wait Block */
+            InsertTailList(&CurrentObject->Header.WaitListHead,
+                           &WaitBlock->WaitListEntry);
 
-        /* Insert the Timer into the Timer Lists and enable it */
-        ThreadTimer = &Thread->Timer;
-        if (!KiInsertTimer(ThreadTimer, *Timeout))
-        {
-            /* Return a timeout if we couldn't insert the timer */
-            WaitStatus = STATUS_TIMEOUT;
-            goto DontWait;
-        }
+            /* Handle Kernel Queues */
+            if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
 
-        /* Set the current due time */
-        DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
-    }
+            /* Setup the wait information */
+            Thread->State = Waiting;
 
-    /* Link the Object to this Wait Block */
-    InsertTailList(&CurrentObject->Header.WaitListHead,
-                   &WaitBlock->WaitListEntry);
+            /* Add the thread to the wait list */
+            KiAddThreadToWaitList(Thread, Swappable);
 
-    /* Handle Kernel Queues */
-    if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
+            /* Activate thread swap */
+            ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
+            KiSetThreadSwapBusy(Thread);
 
-    /* Setup the wait information */
-    Thread->State = Waiting;
+            /* Check if we have a timer */
+            if (Timeout)
+            {
+                /* Insert it */
+                KxInsertTimer(Timer, Hand);
+            }
+            else
+            {
+                /* Otherwise, unlock the dispatcher */
+                KiReleaseDispatcherLockFromDpcLevel();
+            }
 
-    /* Add the thread to the wait list */
-    KiAddThreadToWaitList(Thread, Swappable);
+            /* Do the actual swap */
+            WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
 
-    /* Swap the thread */
-    ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
-    KiSetThreadSwapBusy(Thread);
-    WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
+            /* Check if we were executing an APC */
+            if (WaitStatus != STATUS_KERNEL_APC) return WaitStatus;
 
-    /* Check if we were executing an APC */
-    if (WaitStatus == STATUS_KERNEL_APC)
-    {
-        /* Check if we had a timeout */
-        if (Timeout)
-        {
-            /* Recalculate due times */
-            Timeout = KiRecalculateDueTime(OriginalDueTime,
-                                           &DueTime,
-                                           &NewDueTime);
+            /* Check if we had a timeout */
+            if (Timeout)
+            {
+                /* Recalculate due times */
+                Timeout = KiRecalculateDueTime(OriginalDueTime,
+                                               &DueTime,
+                                               &NewDueTime);
+            }
         }
-
-        /* Wait again */
-        goto StartWait;
+WaitStart:
+        /* Setup a new wait */
+        Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
+        KxSingleThreadWait();
+        KiAcquireDispatcherLockAtDpcLevel();
     }
 
     /* Wait complete */
+    KiReleaseDispatcherLock(Thread->WaitIrql);
     return WaitStatus;
 
 DontWait:
@@ -508,15 +574,14 @@ KeWaitForMultipleObjects(IN ULONG Count,
 {
     PKMUTANT CurrentObject;
     PKWAIT_BLOCK WaitBlock;
-    PKWAIT_BLOCK TimerWaitBlock;
-    PKTIMER ThreadTimer;
     PKTHREAD Thread = KeGetCurrentThread();
-    ULONG AllObjectsSignaled;
-    ULONG WaitIndex;
+    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;
+    LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
+    ULONG Index, Hand = 0;
 
     /* Make sure the Wait Count is valid */
     if (!WaitBlockArray)
@@ -525,7 +590,7 @@ KeWaitForMultipleObjects(IN ULONG Count,
         if (Count > THREAD_WAIT_OBJECTS)
         {
             /* Bugcheck */
-            KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
+            KeBugCheck(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
         }
 
         /* Use the Thread's Wait Block */
@@ -537,7 +602,7 @@ KeWaitForMultipleObjects(IN ULONG Count,
         if (Count > MAXIMUM_WAIT_OBJECTS)
         {
             /* Bugcheck */
-            KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
+            KeBugCheck(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
         }
     }
 
@@ -545,219 +610,227 @@ KeWaitForMultipleObjects(IN ULONG Count,
     ASSERT(Count != 0);
 
     /* Check if the lock is already held */
-    if (Thread->WaitNext)
-    {
-        /* Lock is held, disable Wait Next */
-        Thread->WaitNext = FALSE;
-    }
-    else
-    {
-        /* Lock not held, acquire it */
-StartWait:
-        Thread->WaitIrql = KiAcquireDispatcherLock();
-    }
-
-    /* Prepare for the wait */
-    Swappable = KxMultiThreadWait(Thread,
-                                  WaitBlockArray,
-                                  Alertable,
-                                  WaitReason,
-                                  WaitMode);
-
-    /* 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);
-        goto StartWait;
-    }
-
-    /* Append wait block to the KTHREAD wait block list */
-    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 = (PKMUTANT)Object[WaitIndex];
-        ASSERT(CurrentObject->Header.Type != QueueObject);
-
-        /* Check the type of wait */
-        if (WaitType == WaitAny)
+    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))
         {
-            /* Check if the Object is a mutant */
-            if (CurrentObject->Header.Type == MutantObject)
+            /* Unlock the dispatcher */
+            KiReleaseDispatcherLock(Thread->WaitIrql);
+        }
+        else
+        {
+            /* Check what kind of wait this is */
+            Index = 0;
+            if (WaitType == WaitAny)
             {
-                /* Check if it's signaled */
-                if ((CurrentObject->Header.SignalState > 0) ||
-                    (Thread == CurrentObject->OwnerThread))
+                /* Loop blocks */
+                do
                 {
-                    /* This is a Wait Any, so unwait this and exit */
-                    if (CurrentObject->Header.SignalState !=
-                        (LONG)MINLONG)
+                    /* 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)
                     {
-                        /* Normal signal state, unwait it and return */
-                        KiSatisfyMutantWait(CurrentObject, Thread);
-                        WaitStatus = Thread->WaitStatus | WaitIndex;
-                        goto DontWait;
+                        /* 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
+                    else if (CurrentObject->Header.SignalState > 0)
                     {
-                        /* Raise an exception (see wasm.ru) */
-                        KiReleaseDispatcherLock(Thread->WaitIrql);
-                        ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+                        /* Another signaled object, unwait and return */
+                        KiSatisfyNonMutantWait(CurrentObject);
+                        WaitStatus = Index;
+                        goto DontWait;
                     }
-                }
-            }
-            else if (CurrentObject->Header.SignalState > 0)
-            {
-                /* Another signaled object, unwait and return */
-                KiSatisfyNonMutantWait(CurrentObject, Thread);
-                WaitStatus = WaitIndex;
-                goto DontWait;
+
+                    /* Go to the next block */
+                    Index++;
+                } while (Index < Count);
             }
-        }
-        else
-        {
-            /* Check if we're dealing with a mutant again */
-            if (CurrentObject->Header.Type == MutantObject)
+            else
             {
-                /* Check if it has an invalid count */
-                if ((Thread == CurrentObject->OwnerThread) &&
-                    (CurrentObject->Header.SignalState == MINLONG))
+                /* Loop blocks */
+                do
                 {
-                    /* 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 */
-                    AllObjectsSignaled = FALSE;
-                }
-            }
-            else if (CurrentObject->Header.SignalState <= 0)
-            {
-                /* Not signaled, can't satisfy */
-                AllObjectsSignaled = FALSE;
-            }
-        }
+                    /* Get the Current Object */
+                    CurrentObject = (PKMUTANT)Object[Index];
+                    ASSERT(CurrentObject->Header.Type != QueueObject);
 
-        /* Set up a Wait Block for this Object */
-        WaitBlock = &WaitBlockArray[WaitIndex];
-        WaitBlock->Object = CurrentObject;
-        WaitBlock->Thread = Thread;
-        WaitBlock->WaitKey = (USHORT)WaitIndex;
-        WaitBlock->WaitType = (UCHAR)WaitType;
-        WaitBlock->NextWaitBlock = &WaitBlockArray[WaitIndex + 1];
-    }
+                    /* 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;
+                    }
 
-    /* Check if this is a Wait All and all the objects are signaled */
-    if ((WaitType == WaitAll) && (AllObjectsSignaled))
-    {
-        /* Return to the Root Wait Block */
-        WaitBlock->NextWaitBlock = &WaitBlockArray[0];
+                    /* Go to the next block */
+                    Index++;
+                } while (Index < Count);
 
-        /* Satisfy their Waits and return to the caller */
-        KiWaitSatisfyAll(WaitBlock);
-        WaitStatus = Thread->WaitStatus;
-        goto DontWait;
-    }
+                /* 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);
 
-    /* Make sure we can satisfy the Alertable request */
-    WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
-    if (WaitStatus != STATUS_WAIT_0)
-    {
-        /* Unlock the dispatcher and return */
-        KiReleaseDispatcherLock(Thread->WaitIrql);
-        return WaitStatus;
-    }
+                        /* Go to the next block */
+                        WaitBlock = WaitBlock->NextWaitBlock;
+                    } while(WaitBlock != 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;
-        }
+                    /* Set the wait status and get out */
+                    WaitStatus = Thread->WaitStatus;
+                    goto DontWait;
+                }
+            }
 
-        /* Link timer wait block */
-        TimerWaitBlock = &Thread->WaitBlock[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;
 
-        /* Use this the timer block for linking below */
-        WaitBlock = TimerWaitBlock;
+            /* 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 */
-        ThreadTimer = &Thread->Timer;
-        if (!KiInsertTimer(ThreadTimer, *Timeout))
-        {
-            /* Return a timeout if we couldn't insert the timer */
-            WaitStatus = STATUS_TIMEOUT;
-            goto DontWait;
-        }
+                /* It didn't, so activate it */
+                Timer->Header.Inserted = TRUE;
 
-        /* Set the current due time */
-        DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
-    }
+                /* Link the wait blocks */
+                WaitBlock->NextWaitBlock = TimerBlock;
+            }
 
-    /* Link to the Root Wait Block */
-    WaitBlock->NextWaitBlock = &WaitBlockArray[0];
+            /* Insert into Object's Wait List*/
+            WaitBlock = WaitBlockArray;
+            do
+            {
+                /* Get the Current Object */
+                CurrentObject = WaitBlock->Object;
 
-    /* Insert into Object's Wait List*/
-    WaitBlock = &WaitBlockArray[0];
-    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 (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
 
-    /* Handle Kernel Queues */
-    if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
+            /* Setup the wait information */
+            Thread->State = Waiting;
 
-    /* Setup the wait information */
-    Thread->State = Waiting;
+            /* Add the thread to the wait list */
+            KiAddThreadToWaitList(Thread, Swappable);
 
-    /* Add the thread to the wait list */
-    KiAddThreadToWaitList(Thread, Swappable);
+            /* Activate thread swap */
+            ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
+            KiSetThreadSwapBusy(Thread);
 
-    /* Swap the thread */
-    ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
-    KiSetThreadSwapBusy(Thread);
-    WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
+            /* Check if we have a timer */
+            if (Timeout)
+            {
+                /* Insert it */
+                KxInsertTimer(Timer, Hand);
+            }
+            else
+            {
+                /* Otherwise, unlock the dispatcher */
+                KiReleaseDispatcherLockFromDpcLevel();
+            }
 
-    /* Check if we were executing an APC */
-    if (WaitStatus == STATUS_KERNEL_APC)
-    {
-        /* Check if we had a timeout */
-        if (Timeout)
-        {
-            /* Recalculate due times */
-            Timeout = KiRecalculateDueTime(OriginalDueTime,
-                                           &DueTime,
-                                           &NewDueTime);
+            /* Swap the thread */
+            WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
+
+            /* Check if we were executing an APC */
+            if (WaitStatus != STATUS_KERNEL_APC) return WaitStatus;
+
+            /* Check if we had a timeout */
+            if (Timeout)
+            {
+                /* Recalculate due times */
+                Timeout = KiRecalculateDueTime(OriginalDueTime,
+                                               &DueTime,
+                                               &NewDueTime);
+            }
         }
 
-        /* Wait again */
-        goto StartWait;
+WaitStart:
+        /* Setup a new wait */
+        Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
+        KxMultiThreadWait();
+        KiAcquireDispatcherLockAtDpcLevel();
     }
 
     /* We are done */
+    KiReleaseDispatcherLock(Thread->WaitIrql);
     return WaitStatus;
 
 DontWait:
@@ -776,25 +849,24 @@ NtDelayExecution(IN BOOLEAN Alertable,
 {
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     LARGE_INTEGER SafeInterval;
-    NTSTATUS Status = STATUS_SUCCESS;
+    NTSTATUS Status;
 
     /* Check the previous mode */
-    if(PreviousMode != KernelMode)
+    if (PreviousMode != KernelMode)
     {
         /* Enter SEH for probing */
-        _SEH_TRY
+        _SEH2_TRY
         {
             /* Probe and capture the time out */
             SafeInterval = ProbeForReadLargeInteger(DelayInterval);
             DelayInterval = &SafeInterval;
         }
-        _SEH_HANDLE
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            /* Get SEH exception */
-            Status = _SEH_GetExceptionCode();
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
         }
-        _SEH_END;
-        if (!NT_SUCCESS(Status)) return Status;
+        _SEH2_END;
    }
 
    /* Call the Kernel Function */