- Invert CONFIG_SMP defines as requested by Hartmut
[reactos.git] / reactos / ntoskrnl / ke / wait.c
index aabd42d..2430d30 100644 (file)
 /*
- * COPYRIGHT:            See COPYING in the top level directory
- * PROJECT:              ReactOS project
- * FILE:                 ntoskrnl/ke/wait.c
- * PURPOSE:              Manages non-busy waiting
- * PROGRAMMER:           David Welch (welch@mcmail.com)
- * REVISION HISTORY:
- *           21/07/98: Created
- *          12/1/99:  Phillip Susi: Fixed wake code in KeDispatcherObjectWake
- *                so that things like KeWaitForXXX() return the correct value
- */
-
-/* NOTES ********************************************************************
- * 
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS Kernel
+ * FILE:            ntoskrnl/ke/wait.c
+ * PURPOSE:         Manages waiting for Dispatcher Objects
+ * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
+ *                  Gunnar Dalsnes
  */
 
 /* INCLUDES ******************************************************************/
 
-#include <ddk/ntddk.h>
-#include <internal/ke.h>
-#include <internal/ps.h>
-#include <internal/ob.h>
-#include <internal/id.h>
-#include <ntos/ntdef.h>
+#include <ntoskrnl.h>
 
 #define NDEBUG
 #include <internal/debug.h>
 
 /* GLOBALS ******************************************************************/
 
-static KSPIN_LOCK DispatcherDatabaseLock;
-static BOOLEAN WaitSet = FALSE;
-static KIRQL oldlvl = PASSIVE_LEVEL;
-static PKTHREAD Owner = NULL; 
+KSPIN_LOCK DispatcherDatabaseLock;
 
-/* FUNCTIONS *****************************************************************/
+/* Tells us if the Timer or Event is a Syncronization or Notification Object */
+#define TIMER_OR_EVENT_TYPE 0x7L
 
-VOID KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header,
-                                 ULONG Type,
-                                 ULONG Size,
-                                 ULONG SignalState)
-{
-   Header->Type = Type;
-   Header->Absolute = 0;
-   Header->Inserted = 0;
-   Header->Size = Size;
-   Header->SignalState = SignalState;
-   InitializeListHead(&(Header->WaitListHead));
-}
+/* One of the Reserved Wait Blocks, this one is for the Thread's Timer */
+#define TIMER_WAIT_BLOCK 0x3L
 
-VOID KeAcquireDispatcherDatabaseLock(BOOLEAN Wait)
-/*
- * PURPOSE: Acquires the dispatcher database lock for the caller
- */
-{
-   DPRINT("KeAcquireDispatcherDatabaseLock(Wait %x)\n",Wait);
-   if (WaitSet && Owner == KeGetCurrentThread())
-     {
-       return;
-     }
-   KeAcquireSpinLock(&DispatcherDatabaseLock, &oldlvl);
-   WaitSet = Wait;
-   Owner = KeGetCurrentThread();
-}
+/* FUNCTIONS *****************************************************************/
 
-VOID KeReleaseDispatcherDatabaseLockAtDpcLevel(BOOLEAN Wait)
+BOOLEAN
+__inline
+FASTCALL
+KiCheckAlertability(BOOLEAN Alertable,
+                    PKTHREAD Thread,
+                    KPROCESSOR_MODE WaitMode,
+                    PNTSTATUS Status)
 {
-  DPRINT("KeReleaseDispatcherDatabaseLockAtDpcLevel(Wait %x)\n", Wait);
-  assert(Wait == WaitSet);
-  if (!Wait)
+    /*
+     * At this point, we have to do a wait, so make sure we can make
+     * the thread Alertable if requested.
+     */
+    if (Alertable)
     {
-      Owner = NULL;
-      KeReleaseSpinLockFromDpcLevel(&DispatcherDatabaseLock);
+        /* If the Thread is Alerted, set the Wait Status accordingly */
+        if (Thread->Alerted[(int)WaitMode])
+        {
+            Thread->Alerted[(int)WaitMode] = FALSE;
+            DPRINT("Thread was Alerted in the specified Mode\n");
+            *Status = STATUS_ALERTED;
+            return TRUE;
+        }
+        else if ((WaitMode != KernelMode) &&
+                (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])))
+        {
+            /* If there are User APCs Pending, then we can't really be alertable */
+            DPRINT("APCs are Pending\n");
+            Thread->ApcState.UserApcPending = TRUE;
+            *Status = STATUS_USER_APC;
+            return TRUE;
+        }
+        else if (Thread->Alerted[KernelMode])
+        {
+            /* 
+             * The thread is not alerted in the mode given, but it is alerted
+             * in kernel-mode.
+             */
+            Thread->Alerted[KernelMode] = FALSE;
+            DPRINT("Thread was Alerted in Kernel-Mode\n");
+            *Status = STATUS_ALERTED;
+            return TRUE;
+        }
+    }
+    else if ((WaitMode != KernelMode) &&
+             (Thread->ApcState.UserApcPending))
+    {
+        /*
+         * If there are User APCs Pending and we are waiting in usermode,
+         * then we must notify the caller
+         */
+        DPRINT("APCs are Pending\n");
+        *Status = STATUS_USER_APC;
+        return TRUE;
     }
-}
 
-VOID KeReleaseDispatcherDatabaseLock(BOOLEAN Wait)
-{
-   DPRINT("KeReleaseDispatcherDatabaseLock(Wait %x)\n",Wait);  
-   assert(Wait==WaitSet);
-   if (!Wait)
-     {
-       Owner = NULL;
-       KeReleaseSpinLock(&DispatcherDatabaseLock, oldlvl);
-     }
+    /* Stay in the loop */
+    return FALSE;
 }
 
-VOID KiSideEffectsBeforeWake(DISPATCHER_HEADER* hdr,
-                            PKTHREAD Thread)
 /*
- * FUNCTION: Perform side effects on object before a wait for a thread is
- *           satisfied
+ * @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)
 {
-   switch (hdr->Type)
-     {
-      case InternalSynchronizationEvent:
-       hdr->SignalState = 0;
-       break;
-       
-      case InternalSemaphoreType:
-       hdr->SignalState--;
-       break;
-       
-      case InternalProcessType:
-       break;
-       
-      case InternalThreadType:
-       break;
-       
-      case InternalNotificationEvent:
-       break;
-       
-      case InternalSynchronizationTimer:
-       hdr->SignalState = FALSE;
-       break;
-       
-      case InternalNotificationTimer:
-       break;
-       
-      case InternalMutexType:
-         {
-            PKMUTEX Mutex;
-            
-            Mutex = CONTAINING_RECORD(hdr, KMUTEX, Header);
-            hdr->SignalState--;
-            assert(hdr->SignalState <= 1);
-            Mutex->OwnerThread = Thread;
-         }
-       break;
-       
-      default:
-       DbgPrint("(%s:%d) Dispatcher object %x has unknown type\n",
-                __FILE__,__LINE__,hdr);
-       KeBugCheck(0);
-     }
+    PKWAIT_BLOCK TimerWaitBlock;
+    PKTIMER ThreadTimer;
+    PKTHREAD CurrentThread = KeGetCurrentThread();
+    NTSTATUS Status;
+    DPRINT("Entering KeDelayExecutionThread\n");
+
+    /* 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();
+    }
 
-}
+    /* Use built-in Wait block */
+    TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK];
 
-static BOOLEAN KiIsObjectSignalled(DISPATCHER_HEADER* hdr,
-                                  PKTHREAD Thread)
-{
-   if (hdr->Type == InternalMutexType)
-     {
-        PKMUTEX Mutex;
-       
-       Mutex = CONTAINING_RECORD(hdr, KMUTEX, Header);
-       
-       assert(hdr->SignalState <= 1);
-       if ((hdr->SignalState < 1 && Mutex->OwnerThread == Thread) ||
-           hdr->SignalState == 1)
-         {
-            KiSideEffectsBeforeWake(hdr,
-                                    Thread);
-            return(TRUE);
-         }
-       else
-         {
-            return(FALSE);
-         }
-     }
-   if (hdr->SignalState <= 0)
-     {
-       return(FALSE);
-     }
-   else
-     {
-       KiSideEffectsBeforeWake(hdr, Thread);
-       return(TRUE);
-     }
-}
+    /* Start Wait Loop */
+    do
+    {
+        /* Check if a kernel APC is pending and we were below APC_LEVEL */
+        if ((CurrentThread->ApcState.KernelApcPending) &&
+            (CurrentThread->WaitIrql < APC_LEVEL))
+        {
+            /* Unlock the dispatcher */
+            KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+            goto SkipWait;
+        }
 
-VOID KeRemoveAllWaitsThread(PETHREAD Thread, NTSTATUS WaitStatus)
-{  
-   PKWAIT_BLOCK WaitBlock;
-   BOOLEAN WasWaiting = FALSE;
-   
-   KeAcquireDispatcherDatabaseLock(FALSE);
-   
-   WaitBlock = (PKWAIT_BLOCK)Thread->Tcb.WaitBlockList;
-   if (WaitBlock != NULL)
-     {
-       WasWaiting = TRUE;
-     }   
-   while (WaitBlock != NULL)
-     {
-       RemoveEntryList(&WaitBlock->WaitListEntry);
-       WaitBlock = WaitBlock->NextWaitBlock;
-     }
-   Thread->Tcb.WaitBlockList = NULL;
-   
-   if (WasWaiting)
-     {
-       PsUnblockThread(Thread, &WaitStatus);
-     }
-   
-   KeReleaseDispatcherDatabaseLock(FALSE);
-}
+        /* Chceck if we can do an alertable wait, if requested */
+        if (KiCheckAlertability(Alertable, CurrentThread, WaitMode, &Status)) break;
 
-static BOOLEAN KeDispatcherObjectWakeAll(DISPATCHER_HEADER* hdr)
-{
-   PKWAIT_BLOCK current;
-   PLIST_ENTRY current_entry;
-   PKWAIT_BLOCK PrevBlock;
-   NTSTATUS Status;
-
-   DPRINT("KeDispatcherObjectWakeAll(hdr %x)\n",hdr);
-   
-   if (IsListEmpty(&hdr->WaitListHead))
-     {
-       return(FALSE);
-     }
-   
-   while (!IsListEmpty(&(hdr->WaitListHead)))
-     {
-       current_entry = RemoveHeadList(&hdr->WaitListHead);
-       current = CONTAINING_RECORD(current_entry,
-                                   KWAIT_BLOCK,
-                                   WaitListEntry);
-        DPRINT("Waking %x\n",current->Thread);
-        if (current->WaitType == WaitAny)
-          {
-             DPRINT("WaitAny: Remove all wait blocks.\n");
-            for( PrevBlock = current->Thread->WaitBlockList; PrevBlock; PrevBlock = PrevBlock->NextWaitBlock )
-              if( PrevBlock != current )
-                RemoveEntryList( &(PrevBlock->WaitListEntry) );
-            current->Thread->WaitBlockList = 0;
-          }
-        else
-          {
-            DPRINT("WaitAll: Remove the current wait block only.\n");
-            
-            PrevBlock = current->Thread->WaitBlockList;
-            if (PrevBlock == current)
-              {
-                 DPRINT( "WaitAll: Current block is list head.\n" );
-                 current->Thread->WaitBlockList = current->NextWaitBlock;
-              }
-            else
-              {
-                 DPRINT( "WaitAll: Current block is not list head.\n" );
-                 while ( PrevBlock && PrevBlock->NextWaitBlock != current)
-                   {
-                      PrevBlock = PrevBlock->NextWaitBlock;
-                   }
-                 if (PrevBlock)
-                   {
-                      PrevBlock->NextWaitBlock = current->NextWaitBlock;
-                   }
-              }
-         }     
-       KiSideEffectsBeforeWake(hdr, current->Thread);
-       Status = current->WaitKey;
-       if (current->Thread->WaitBlockList == NULL)
-         {
-            PsUnblockThread(CONTAINING_RECORD(current->Thread,ETHREAD,Tcb), 
-                            &Status);
-         }
-     }
-   return(TRUE);
-}
+        /* Set Timer */
+        ThreadTimer = &CurrentThread->Timer;
 
-static BOOLEAN KeDispatcherObjectWakeOne(DISPATCHER_HEADER* hdr)
-{
-   PKWAIT_BLOCK current;
-   PLIST_ENTRY current_entry;
-   PKWAIT_BLOCK PrevBlock;
-   NTSTATUS Status;
-
-   DPRINT("KeDispatcherObjectWakeOn(hdr %x)\n",hdr);
-   DPRINT("hdr->WaitListHead.Flink %x hdr->WaitListHead.Blink %x\n",
-         hdr->WaitListHead.Flink,hdr->WaitListHead.Blink);
-   if (IsListEmpty(&(hdr->WaitListHead)))
-     {
-       return(FALSE);
-     }
-   current_entry = RemoveHeadList(&(hdr->WaitListHead));
-   current = CONTAINING_RECORD(current_entry,KWAIT_BLOCK,
-                              WaitListEntry);
-   DPRINT("current_entry %x current %x\n",current_entry,current);
-
-   if (current->WaitType == WaitAny)
-     {
-        DPRINT("WaitAny: Remove all wait blocks.\n");
-       for( PrevBlock = current->Thread->WaitBlockList; PrevBlock; PrevBlock = PrevBlock->NextWaitBlock )
-         if( PrevBlock != current )
-           RemoveEntryList( &(PrevBlock->WaitListEntry) );
-       current->Thread->WaitBlockList = 0;
-     }
-   else
-     {
-        DPRINT("WaitAll: Remove the current wait block only.\n");
-
-        PrevBlock = current->Thread->WaitBlockList;
-        if (PrevBlock == current)
-           {
-              DPRINT( "WaitAll: Current block is list head.\n" );
-              current->Thread->WaitBlockList = current->NextWaitBlock;
-           }
-        else
-           {
-              DPRINT( "WaitAll: Current block is not list head.\n" );
-              while ( PrevBlock && PrevBlock->NextWaitBlock != current)
-                {
-                   PrevBlock = PrevBlock->NextWaitBlock;
-                }
-              if (PrevBlock)
-                {
-                   PrevBlock->NextWaitBlock = current->NextWaitBlock;
-                }
-          }
-     }
-
-   DPRINT("Waking %x\n",current->Thread);
-   KiSideEffectsBeforeWake(hdr, current->Thread);
-   Status = current->WaitKey;
-   PsUnblockThread(CONTAINING_RECORD(current->Thread, ETHREAD, Tcb), 
-                  &Status);
-   return(TRUE);
-}
+        /* 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;
 
-BOOLEAN KeDispatcherObjectWake(DISPATCHER_HEADER* hdr)
-/*
- * FUNCTION: Wake threads waiting on a dispatcher object
- * NOTE: The exact semantics of waking are dependant on the type of object
- */
-{
-   BOOL Ret;
-
-   DPRINT("Entering KeDispatcherObjectWake(hdr %x)\n",hdr);
-//   DPRINT("hdr->WaitListHead %x hdr->WaitListHead.Flink %x\n",
-//       &hdr->WaitListHead,hdr->WaitListHead.Flink);
-   DPRINT("hdr->Type %x\n",hdr->Type);
-   switch (hdr->Type)
-     {
-      case InternalNotificationEvent:
-       return(KeDispatcherObjectWakeAll(hdr));
-       
-      case InternalNotificationTimer:
-       return(KeDispatcherObjectWakeAll(hdr));
-       
-      case InternalSynchronizationEvent:
-       return(KeDispatcherObjectWakeOne(hdr));
-
-
-      case InternalSynchronizationTimer:
-       return(KeDispatcherObjectWakeOne(hdr));
-       
-      case InternalSemaphoreType:
-       DPRINT("hdr->SignalState %d\n", hdr->SignalState);
-       if(hdr->SignalState>0)
-       {
-          do
-            {
-               DPRINT("Waking one semaphore waiter\n");
-               Ret = KeDispatcherObjectWakeOne(hdr);
-            } while(hdr->SignalState > 0 &&  Ret) ;
-          return(Ret);
-       }
-       else return FALSE;
-       
-      case InternalProcessType:
-       return(KeDispatcherObjectWakeAll(hdr));
-
-      case InternalThreadType:
-       return(KeDispatcherObjectWakeAll(hdr));
-       
-      case InternalMutexType:
-       return(KeDispatcherObjectWakeOne(hdr));
-     }
-   DbgPrint("Dispatcher object %x has unknown type %d\n", hdr, hdr->Type);
-   KeBugCheck(0);
-   return(FALSE);
-}
+        /* Link the timer to this Wait Block */
+        InitializeListHead(&ThreadTimer->Header.WaitListHead);
+        InsertTailList(&ThreadTimer->Header.WaitListHead, &TimerWaitBlock->WaitListEntry);
 
+        /* Insert the Timer into the Timer Lists and enable it */
+        if (!KiInsertTimer(ThreadTimer, *Interval))
+        {
+            /* FIXME: The timer already expired, we should find a new ready thread */
+            Status = STATUS_SUCCESS;
+            break;
+        }
+
+        /* Handle Kernel Queues */
+        if (CurrentThread->Queue)
+        {
+            DPRINT("Waking Queue\n");
+            KiWakeQueue(CurrentThread->Queue);
+        }
+
+        /* Setup the wait information */
+        CurrentThread->Alertable = Alertable;
+        CurrentThread->WaitMode = WaitMode;
+        CurrentThread->WaitReason = DelayExecution;
+        CurrentThread->WaitTime = 0;
+        CurrentThread->State = Waiting;
+
+        /* Find a new thread to run */
+        DPRINT("Swapping threads\n");
+        Status = KiSwapThread();
+
+        /* Check if we were executing an APC or if we timed out */
+        if (Status != STATUS_KERNEL_APC)
+        {
+            /* This is a good thing */
+            if (Status == STATUS_TIMEOUT) Status = STATUS_SUCCESS;
+
+            /* Return Status */
+            return Status;
+        }
+
+        /* FIXME: Fixup interval */
+
+        /* Acquire again the lock */
+SkipWait:
+        DPRINT("Looping again\n");
+        CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
+    }
+    while (TRUE);
+
+    /* Release the Lock, we are done */
+    DPRINT("Returning from KeDelayExecutionThread(), %x. Status: %d\n",
+            KeGetCurrentThread(), Status);
+    KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+    return Status;
+}
 
-NTSTATUS STDCALL KeWaitForSingleObject (PVOID          Object,
-                                       KWAIT_REASON    WaitReason,
-                                       KPROCESSOR_MODE WaitMode,
-                                       BOOLEAN         Alertable,
-                                       PLARGE_INTEGER  Timeout)
 /*
+ * @implemented
+ *
  * FUNCTION: Puts the current thread into a wait state until the
- * given dispatcher object is set to signalled 
+ * given dispatcher object is set to signalled
  * ARGUMENTS:
  *         Object = Object to wait on
  *         WaitReason = Reason for the wait (debugging aid)
@@ -392,345 +222,648 @@ NTSTATUS STDCALL KeWaitForSingleObject (PVOID           Object,
  *         Timeout = Optional timeout value
  * RETURNS: Status
  */
+NTSTATUS
+STDCALL
+KeWaitForSingleObject(PVOID Object,
+                      KWAIT_REASON WaitReason,
+                      KPROCESSOR_MODE WaitMode,
+                      BOOLEAN Alertable,
+                      PLARGE_INTEGER Timeout)
 {
-   DISPATCHER_HEADER* hdr = (DISPATCHER_HEADER *)Object;
-   PKTHREAD CurrentThread;
-   NTSTATUS Status;
-   KIRQL WaitIrql;
-
-   DPRINT("Entering KeWaitForSingleObject(Object %x) "
-         "PsGetCurrentThread() %x\n",Object,PsGetCurrentThread());
-
-   CurrentThread = KeGetCurrentThread();
-   WaitIrql = KeGetCurrentIrql();
-
-   if (Timeout != NULL)
-     {
-       KeAddThreadTimeout(CurrentThread, Timeout);
-     }
-   
-   do
-     {
-       KeAcquireDispatcherDatabaseLock(FALSE);
-       
-       DPRINT("hdr->SignalState %d\n", hdr->SignalState);     
-       
-       if (Alertable && KiTestAlert())
-        {
-          KeReleaseDispatcherDatabaseLock(FALSE);
-          return(STATUS_USER_APC);
-        }      
-
-       if (KiIsObjectSignalled(hdr, CurrentThread))
-        {           
-          KeReleaseDispatcherDatabaseLock(FALSE);
-          if (Timeout != NULL)
-            {
-              KeCancelTimer(&KeGetCurrentThread()->Timer);
-            }
-          return(STATUS_WAIT_0);
-         }
-       
-       CurrentThread->WaitStatus = STATUS_UNSUCCESSFUL;
-       /* Append wait block to the KTHREAD wait block list */
-       CurrentThread->WaitBlockList = &CurrentThread->WaitBlock[0];    
-       CurrentThread->WaitBlock[0].Object = Object;
-       CurrentThread->WaitBlock[0].Thread = CurrentThread;
-       CurrentThread->WaitBlock[0].WaitKey = 0;
-       CurrentThread->WaitBlock[0].WaitType = WaitAny;
-       CurrentThread->WaitBlock[0].NextWaitBlock = NULL;
-       InsertTailList(&hdr->WaitListHead, 
-                     &CurrentThread->WaitBlock[0].WaitListEntry);
-       PsBlockThread(&Status, (UCHAR)Alertable, WaitMode, TRUE, WaitIrql);
-     } while (Status == STATUS_KERNEL_APC);
-   
-   if (Timeout != NULL)
-     {
-       KeCancelTimer(&KeGetCurrentThread()->Timer);
-     }
-   
-   DPRINT("Returning from KeWaitForSingleObject()\n");
-   return(Status);
-}
+    PKMUTANT CurrentObject;
+    PKWAIT_BLOCK WaitBlock;
+    PKWAIT_BLOCK TimerWaitBlock;
+    PKTIMER ThreadTimer;
+    PKTHREAD CurrentThread = KeGetCurrentThread();
+    NTSTATUS Status;
+    NTSTATUS WaitStatus;
+    DPRINT("Entering KeWaitForSingleObject\n");
+
+    /* Check if the lock is already held */
+    if (CurrentThread->WaitNext)
+    {
+        /* Lock is held, disable Wait Next */
+        DPRINT("Lock is held\n");
+        CurrentThread->WaitNext = FALSE;
+    }
+    else
+    {
+        /* Lock not held, acquire it */
+        DPRINT("Lock is not held, acquiring\n");
+        CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
+    }
+
+    /* Start the actual Loop */
+    do
+    {
+        /* Check if a kernel APC is pending and we were below APC_LEVEL */
+        if ((CurrentThread->ApcState.KernelApcPending) &&
+            (CurrentThread->WaitIrql < APC_LEVEL))
+        {
+            /* Unlock the dispatcher */
+            KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+            goto SkipWait;
+        }
+
+        /* Get the current Wait Status */
+        WaitStatus = CurrentThread->WaitStatus;
+
+        /* Append wait block to the KTHREAD wait block list */
+        CurrentThread->WaitBlockList = WaitBlock = &CurrentThread->WaitBlock[0];
+
+        /* Get the Current Object */
+        CurrentObject = (PKMUTANT)Object;
+
+        /* Check if it's a mutant */
+        if (CurrentObject->Header.Type == MutantObject)
+        {
+            /* Check its signal state or if we own it */
+            if ((CurrentObject->Header.SignalState > 0) ||
+                (CurrentThread == CurrentObject->OwnerThread))
+            {
+                /* Just unwait this guy and exit */
+                if (CurrentObject->Header.SignalState != (LONG)MINLONG)
+                {
+                    /* It has a normal signal state, so unwait it and return */
+                    KiSatisfyMutantWait(CurrentObject, CurrentThread);
+                    Status = STATUS_WAIT_0;
+                    goto DontWait;
+                }
+                else
+                {
+                    /* According to wasm.ru, we must raise this exception (tested and true) */
+                    KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+                    ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+                }
+            }
+        }
+        else if (CurrentObject->Header.SignalState > 0)
+        {
+            /* Another satisfied object */
+            KiSatisfyNonMutantWait(CurrentObject, CurrentThread);
+            Status = STATUS_WAIT_0;
+            goto DontWait;
+        }
+
+        /* 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)
+        {
+            /* Fail if the timeout interval is actually 0 */
+            if (!Timeout->QuadPart)
+            {
+                /* Return a timeout */
+                Status = STATUS_TIMEOUT;
+                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 = WaitBlock;
+
+            /* Link the timer to this Wait Block */
+            InitializeListHead(&ThreadTimer->Header.WaitListHead);
+            InsertTailList(&ThreadTimer->Header.WaitListHead,
+                           &TimerWaitBlock->WaitListEntry);
+
+            /* Insert the Timer into the Timer Lists and enable it */
+            if (!KiInsertTimer(ThreadTimer, *Timeout))
+            {
+                /* Return a timeout if we couldn't insert the timer */
+                Status = STATUS_TIMEOUT;
+                goto DontWait;
+            }
+        }
+
+        /* Link the Object to this Wait Block */
+        InsertTailList(&CurrentObject->Header.WaitListHead,
+                       &WaitBlock->WaitListEntry);
+
+        /* Handle Kernel Queues */
+        if (CurrentThread->Queue)
+        {
+            DPRINT("Waking Queue\n");
+            KiWakeQueue(CurrentThread->Queue);
+        }
+
+        /* Setup the wait information */
+        CurrentThread->Alertable = Alertable;
+        CurrentThread->WaitMode = WaitMode;
+        CurrentThread->WaitReason = WaitReason;
+        CurrentThread->WaitTime = 0;
+        CurrentThread->State = Waiting;
+
+        /* Find a new thread to run */
+        DPRINT("Swapping threads\n");
+        Status = KiSwapThread();
+
+        /* Check if we were executing an APC */
+        if (Status != STATUS_KERNEL_APC)
+        {
+            /* Return Status */
+            return Status;
+        }
 
+        /* Check if we had a timeout */
+        if (Timeout)
+        {
+             /* FIXME: Fixup interval */
+        }
+
+        /* Acquire again the lock */
+SkipWait:
+        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;
+
+DontWait:
+    /* Adjust the Quantum */
+    KiAdjustQuantumThread(CurrentThread);
+
+    /* Release & Return */
+    DPRINT("Quick-return from KeWaitForMultipleObjects(), %x. Status: %d\n.",
+            KeGetCurrentThread(), Status);
+    KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+    return Status;
+}
 
+/*
+ * @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)
+KeWaitForMultipleObjects(ULONG Count,
+                         PVOID Object[],
+                         WAIT_TYPE WaitType,
+                         KWAIT_REASON WaitReason,
+                         KPROCESSOR_MODE WaitMode,
+                         BOOLEAN Alertable,
+                         PLARGE_INTEGER Timeout,
+                         PKWAIT_BLOCK WaitBlockArray)
 {
-  DISPATCHER_HEADER* hdr;
-  PKWAIT_BLOCK blk;
-  PKTHREAD CurrentThread;
-  ULONG CountSignaled;
-  ULONG i;
-  NTSTATUS Status;
-  KIRQL WaitIrql;
-
-  DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
-        "PsGetCurrentThread() %x\n",Count,Object,PsGetCurrentThread());
-
-  CountSignaled = 0;
-  CurrentThread = KeGetCurrentThread();
-  WaitIrql = KeGetCurrentIrql();
-
-  if (WaitBlockArray == NULL)
+    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)
     {
-      if (Count > 4)
-        {
-         DbgPrint("(%s:%d) Too many objects!\n",
-                  __FILE__,__LINE__);
-         return STATUS_UNSUCCESSFUL;
-        }
-      blk = &CurrentThread->WaitBlock[0];
+        /* Lock is held, disable Wait Next */
+        DPRINT("Lock is held\n");
+        CurrentThread->WaitNext = FALSE;
     }
-  else
+    else
     {
-      if (Count > 64)
-        {
-         DbgPrint("(%s:%d) Too many objects!\n",
-                  __FILE__,__LINE__);
-         return STATUS_UNSUCCESSFUL;
-        }
-      blk = WaitBlockArray;
+        /* Lock not held, acquire it */
+        DPRINT("Lock is not held, acquiring\n");
+        CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
     }
-  if (Timeout != NULL)
+
+    /* Make sure the Wait Count is valid for the Thread and Maximum Wait Objects */
+    if (!WaitBlockArray)
+    {
+        /* Check in regards to the Thread Object Limit */
+        if (Count > THREAD_WAIT_OBJECTS) KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
+
+        /* Use the Thread's Wait Block */
+        WaitBlockArray = &CurrentThread->WaitBlock[0];
+    }
+    else
     {
-      KeAddThreadTimeout(CurrentThread,Timeout);
+        /* Using our own Block Array. Check in regards to System Object Limit */
+        if (Count > MAXIMUM_WAIT_OBJECTS) KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
     }
-  
-  do {
-    KeAcquireDispatcherDatabaseLock(FALSE);
-    
-    for (i = 0; i < Count; i++)
-      {
-       hdr = (DISPATCHER_HEADER *)Object[i];
-       
-       DPRINT("hdr->SignalState %d\n", hdr->SignalState);
-       
-       if (KiIsObjectSignalled(hdr, CurrentThread))
-         {
-           CountSignaled++;
-           
-           if (WaitType == WaitAny)
-             {
-                 KeReleaseDispatcherDatabaseLock(FALSE);
-                 DPRINT("One object is already signaled!\n");
-                 return(STATUS_WAIT_0 + i);
-             }
-         }
-      }
-    
-    if ((WaitType == WaitAll) && (CountSignaled == Count))
-      {
-       KeReleaseDispatcherDatabaseLock(FALSE);
-       DPRINT("All objects are already signaled!\n");
-       return(STATUS_WAIT_0);
-      }
-    
-    /* Append wait block to the KTHREAD wait block list */
-    CurrentThread->WaitBlockList = blk;
-    
-    for (i = 0; i < Count; i++)
-      {
-       hdr = (DISPATCHER_HEADER *)Object[i];
-       
-       DPRINT("hdr->SignalState %d\n", hdr->SignalState);
-       
-       blk->Object = Object[i];
-       blk->Thread = CurrentThread;
-       blk->WaitKey = i;
-       blk->WaitType = WaitType;
-       if (i == Count - 1)
-         blk->NextWaitBlock = NULL;
-       else
-         blk->NextWaitBlock = blk + 1;
-       
-       InsertTailList(&(hdr->WaitListHead),&(blk->WaitListEntry));
-       
-       blk = blk->NextWaitBlock;
-      }
-    
-    PsBlockThread(&Status, Alertable, WaitMode, TRUE, WaitIrql);
-  } while( Status == STATUS_KERNEL_APC );
-  if (Timeout != NULL)
-    KeCancelTimer(&KeGetCurrentThread()->Timer);
-  DPRINT("Returning from KeWaitForMultipleObjects()\n");
-  return(Status);
+
+    /* Start the actual Loop */
+    do
+    {
+        /* Check if a kernel APC is pending and we were below APC_LEVEL */
+        if ((CurrentThread->ApcState.KernelApcPending) &&
+            (CurrentThread->WaitIrql < APC_LEVEL))
+        {
+            /* Unlock the dispatcher */
+            KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+            goto SkipWait;
+        }
+
+        /* 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 = (PKMUTANT)Object[WaitIndex];
+
+            /* Check the type of wait */
+            if (WaitType == WaitAny)
+            {
+                /* Check if the Object is a mutant */
+                if (CurrentObject->Header.Type == MutantObject)
+                {
+                    /* Check if it's signaled */
+                    if ((CurrentObject->Header.SignalState > 0) ||
+                        (CurrentThread == CurrentObject->OwnerThread))
+                    {
+                        /* This is a Wait Any, so just unwait this and exit */
+                        if (CurrentObject->Header.SignalState != (LONG)MINLONG)
+                        {
+                            /* Normal signal state, so unwait it and return */
+                            KiSatisfyMutantWait(CurrentObject, CurrentThread);
+                            Status = STATUS_WAIT_0 | WaitIndex;
+                            goto DontWait;
+                        }
+                        else
+                        {
+                            /* According to wasm.ru, we must raise this exception (tested and true) */
+                            KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+                            ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+                        }
+                    }
+                }
+                else if (CurrentObject->Header.SignalState > 0)
+                {
+                    /* Another signaled object, unwait and return */
+                    KiSatisfyNonMutantWait(CurrentObject, CurrentThread);
+                    Status = WaitIndex;
+                    goto DontWait;
+                }
+            }
+            else
+            {
+                /* Check if we're dealing with a mutant again */
+                if (CurrentObject->Header.Type == MutantObject)
+                {
+                    /* Check if it has an invalid count */
+                    if ((CurrentThread == CurrentObject->OwnerThread) &&
+                        (CurrentObject->Header.SignalState == MINLONG))
+                    {
+                        /* Raise an exception */
+                        KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+                        ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+                    }
+                    else if ((CurrentObject->Header.SignalState <= 0) &&
+                             (CurrentThread != CurrentObject->OwnerThread))
+                    {
+                        /* We don't own it, can't satisfy the wait */
+                        AllObjectsSignaled = FALSE;
+                    }
+                }
+                else if (CurrentObject->Header.SignalState <= 0)
+                {
+                    /* Not signaled, can't satisfy */
+                    AllObjectsSignaled = FALSE;
+                }
+            }
+
+            /* Set up a Wait Block for this Object */
+            WaitBlock->Object = CurrentObject;
+            WaitBlock->Thread = CurrentThread;
+            WaitBlock->WaitKey = (USHORT)WaitIndex;
+            WaitBlock->WaitType = (USHORT)WaitType;
+            WaitBlock->NextWaitBlock = WaitBlock + 1;
+
+            /* Move to the next Wait Block */
+            WaitBlock = WaitBlock->NextWaitBlock;
+        }
+
+        /* 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)
+        {
+            /* Make sure the timeout interval isn't actually 0 */
+            if (!Timeout->QuadPart)
+            {
+                /* Return a timeout */
+                Status = STATUS_TIMEOUT;
+                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);
+
+            /* Insert the Timer into the Timer Lists and enable it */
+            if (!KiInsertTimer(ThreadTimer, *Timeout))
+            {
+                /* Return a timeout if we couldn't insert the timer */
+                Status = STATUS_TIMEOUT;
+                goto DontWait;
+            }
+        }
+
+        /* Insert into Object's Wait List*/
+        WaitBlock = CurrentThread->WaitBlockList;
+        do
+        {
+            /* Get the Current Object */
+            CurrentObject = WaitBlock->Object;
+
+            /* Link the Object to this Wait Block */
+            InsertTailList(&CurrentObject->Header.WaitListHead,
+                           &WaitBlock->WaitListEntry);
+
+            /* 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);
+        }
+
+        /* Setup the wait information */
+        CurrentThread->Alertable = Alertable;
+        CurrentThread->WaitMode = WaitMode;
+        CurrentThread->WaitReason = WaitReason;
+        CurrentThread->WaitTime = 0;
+        CurrentThread->State = Waiting;
+
+        /* Find a new thread to run */
+        DPRINT("Swapping threads\n");
+        Status = KiSwapThread();
+
+        /* Check if we were executing an APC */
+        DPRINT("Thread is back\n");
+        if (Status != STATUS_KERNEL_APC)
+        {
+            /* Return Status */
+            return Status;
+        }
+
+        /* Check if we had a timeout */
+        if (Timeout)
+        {
+             /* FIXME: Fixup interval */
+        }
+
+        /* Acquire again the lock */
+SkipWait:
+        DPRINT("Looping again\n");
+        CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
+    }
+    while (TRUE);
+
+    /* Release the Lock, we are done */
+    DPRINT("Returning, %x. Status: %d\n",  KeGetCurrentThread(), Status);
+    KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+    return Status;
+
+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 KeInitializeDispatcher(VOID)
+VOID
+FASTCALL
+KiWaitTest(PVOID ObjectPointer,
+           KPRIORITY Increment)
 {
-   KeInitializeSpinLock(&DispatcherDatabaseLock);
+    PLIST_ENTRY WaitEntry;
+    PLIST_ENTRY WaitList;
+    PKWAIT_BLOCK CurrentWaitBlock;
+    PKWAIT_BLOCK NextWaitBlock;
+    PKTHREAD WaitThread;
+    PKMUTANT FirstObject = ObjectPointer, Object;
+
+    /* Loop the Wait Entries */
+    DPRINT("KiWaitTest for Object: %x\n", FirstObject);
+    WaitList = &FirstObject->Header.WaitListHead;
+    WaitEntry = WaitList->Flink;
+    while ((FirstObject->Header.SignalState > 0) && (WaitEntry != WaitList))
+    {
+        /* Get the current wait block */
+        CurrentWaitBlock = CONTAINING_RECORD(WaitEntry,
+                                             KWAIT_BLOCK,
+                                             WaitListEntry);
+        WaitThread = CurrentWaitBlock->Thread;
+
+        /* Check the current Wait Mode */
+        if (CurrentWaitBlock->WaitType == WaitAny)
+        {
+            /* Easy case, satisfy only this wait */
+            DPRINT("Satisfiying a Wait any\n");
+            WaitEntry = WaitEntry->Blink;
+            KiSatisfyObjectWait(FirstObject, WaitThread);
+        }
+        else
+        {
+            /* Everything must be satisfied */
+            DPRINT("Checking for a Wait All\n");
+            NextWaitBlock = CurrentWaitBlock->NextWaitBlock;
+
+            /* Loop first to make sure they are valid */
+            while (NextWaitBlock != CurrentWaitBlock)
+            {
+                /* Check if the object is signaled */
+                Object = NextWaitBlock->Object;
+                DPRINT("Checking: %p %d\n",
+                        Object, Object->Header.SignalState);
+                if (NextWaitBlock->WaitKey != STATUS_TIMEOUT)
+                {
+                    /* Check if this is a mutant */
+                    if ((Object->Header.Type == MutantObject) &&
+                        (Object->Header.SignalState <= 0) &&
+                        (WaitThread == Object->OwnerThread))
+                    {
+                        /* It's a signaled mutant */
+                    }
+                    else if (Object->Header.SignalState <= 0)
+                    {
+                        /* Skip the unwaiting */
+                        goto SkipUnwait;
+                    }
+                }
+
+                /* Go to the next Wait block */
+                NextWaitBlock = NextWaitBlock->NextWaitBlock;
+            }
+
+            /* All the objects are signaled, we can satisfy */
+            DPRINT("Satisfiying a Wait All\n");
+            WaitEntry = WaitEntry->Blink;
+            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");
 }
 
-NTSTATUS STDCALL NtWaitForMultipleObjects(IN ULONG Count,
-                                         IN HANDLE Object [],
-                                         IN CINT WaitType,
-                                         IN BOOLEAN Alertable,
-                                         IN PLARGE_INTEGER Time)
+/* Must be called with the dispatcher lock held */
+VOID
+FASTCALL
+KiAbortWaitThread(PKTHREAD Thread,
+                  NTSTATUS WaitStatus,
+                  KPRIORITY Increment)
 {
-   KWAIT_BLOCK WaitBlockArray[EX_MAXIMUM_WAIT_OBJECTS]; 
-   PVOID ObjectPtrArray[EX_MAXIMUM_WAIT_OBJECTS];       
-   NTSTATUS Status;
-   ULONG i, j;
-
-   DPRINT("NtWaitForMultipleObjects(Count %lu Object[] %x, Alertable %d, "
-         "Time %x)\n", Count,Object,Alertable,Time);
-
-   if (Count > EX_MAXIMUM_WAIT_OBJECTS)  
-     return STATUS_UNSUCCESSFUL;
-
-   /* reference all objects */
-   for (i = 0; i < Count; i++)
-     {
-        Status = ObReferenceObjectByHandle(Object[i],
-                                           SYNCHRONIZE,
-                                           NULL,
-                                           UserMode,
-                                           &ObjectPtrArray[i],
-                                           NULL);
-        if (Status != STATUS_SUCCESS)
-          {
-             /* dereference all referenced objects */
-             for (j = 0; j < i; i++)
-               {
-                  ObDereferenceObject(ObjectPtrArray[j]);
-               }
-
-             return(Status);
-          }
-     }
-
-   Status = KeWaitForMultipleObjects(Count,
-                                     ObjectPtrArray,
-                                     WaitType,
-                                     UserRequest,
-                                     UserMode,
-                                     Alertable,
-                                     Time,
-                                     WaitBlockArray);
-
-   /* dereference all objects */
-   for (i = 0; i < Count; i++)
-     {
-        ObDereferenceObject(ObjectPtrArray[i]);
-     }
-
-   return(Status);
-}
+    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);
 
-NTSTATUS STDCALL NtWaitForSingleObject (IN     HANDLE          Object,
-                                       IN      BOOLEAN         Alertable,
-                                       IN      PLARGE_INTEGER  Time)
-{
-   PVOID ObjectPtr;
-   NTSTATUS Status;
-   
-   DPRINT("NtWaitForSingleObject(Object %x, Alertable %d, Time %x)\n",
-         Object,Alertable,Time);
-   
-   Status = ObReferenceObjectByHandle(Object,
-                                     SYNCHRONIZE,
-                                     NULL,
-                                     UserMode,
-                                     &ObjectPtr,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-   
-   Status = KeWaitForSingleObject(ObjectPtr,
-                                 UserMode,
-                                 UserMode,
-                                 Alertable,
-                                 Time);
-   
-   ObDereferenceObject(ObjectPtr);
-   
-   return(Status);
+    /* Remove the Wait Blocks from the list */
+    DPRINT("Removing waits\n");
+    WaitBlock = Thread->WaitBlockList;
+    do
+    {
+        /* Remove it */
+        DPRINT("Removing Waitblock: %x, %x\n",
+                WaitBlock, WaitBlock->NextWaitBlock);
+        RemoveEntryList(&WaitBlock->WaitListEntry);
+
+        /* Go to the next one */
+        WaitBlock = WaitBlock->NextWaitBlock;
+    } while (WaitBlock != Thread->WaitBlockList);
+
+    /* Check if there's a Thread Timer */
+    if (Thread->Timer.Header.Inserted)
+    {
+        /* Cancel the Thread Timer with the no-lock fastpath */
+        DPRINT("Removing the Thread's Timer\n");
+        Thread->Timer.Header.Inserted = FALSE;
+        RemoveEntryList(&Thread->Timer.TimerListEntry);
+    }
+
+    /* Increment the Queue's active threads */
+    if (Thread->Queue)
+    {
+        DPRINT("Incrementing Queue's active threads\n");
+        Thread->Queue->CurrentCount++;
+    }
+
+    /* Reschedule the Thread */
+    DPRINT("Unblocking the Thread\n");
+    KiUnblockThread(Thread, &WaitStatus, 0);
 }
 
+VOID
+FASTCALL
+KiAcquireFastMutex(IN PFAST_MUTEX FastMutex)
+{
+    /* Increase contention count */
+    FastMutex->Contention++;
+
+    /* Wait for the event */
+    KeWaitForSingleObject(&FastMutex->Gate,
+                          WrMutex,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+}
 
-NTSTATUS STDCALL
-NtSignalAndWaitForSingleObject(IN HANDLE SignalObject,
-                              IN HANDLE WaitObject,
-                              IN BOOLEAN Alertable,
-                              IN PLARGE_INTEGER Time)
+VOID
+FASTCALL
+KiExitDispatcher(KIRQL OldIrql)
 {
-   KPROCESSOR_MODE ProcessorMode;
-   DISPATCHER_HEADER* hdr;
-   PVOID SignalObj;
-   PVOID WaitObj;
-   NTSTATUS Status;
-
-   ProcessorMode = ExGetPreviousMode();
-   Status = ObReferenceObjectByHandle(SignalObject,
-                                     0,
-                                     NULL,
-                                     ProcessorMode,
-                                     &SignalObj,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       return Status;
-     }
-
-   Status = ObReferenceObjectByHandle(WaitObject,
-                                     SYNCHRONIZE,
-                                     NULL,
-                                     ProcessorMode,
-                                     &WaitObj,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       ObDereferenceObject(SignalObj);
-       return Status;
-     }
-
-   hdr = (DISPATCHER_HEADER *)SignalObj;
-   switch (hdr->Type)
-     {
-      case InternalNotificationEvent:
-      case InternalSynchronizationEvent:
-       KeSetEvent(SignalObj,
-                  EVENT_INCREMENT,
-                  TRUE);
-       break;
-
-      case InternalMutexType:
-       KeReleaseMutex(SignalObj,
-                      TRUE);
-       break;
-
-      case InternalSemaphoreType:
-       KeReleaseSemaphore(SignalObj,
-                          SEMAPHORE_INCREMENT,
-                          1,
-                          TRUE);
-       break;
-
-      default:
-       ObDereferenceObject(SignalObj);
-       ObDereferenceObject(WaitObj);
-       return STATUS_OBJECT_TYPE_MISMATCH;
-     }
-
-   Status = KeWaitForSingleObject(WaitObj,
-                                 UserRequest,
-                                 ProcessorMode,
-                                 Alertable,
-                                 Time);
-
-   ObDereferenceObject(SignalObj);
-   ObDereferenceObject(WaitObj);
-
-   return Status;
+    /* If it's the idle thread, dispatch */
+    if (!(KeIsExecutingDpc()) &&
+        (OldIrql < DISPATCH_LEVEL) &&
+        (KeGetCurrentThread()) &&
+        (KeGetCurrentThread() == KeGetCurrentPrcb()->IdleThread))
+    {
+        KiDispatchThreadNoLock(Ready);
+    }
+
+    /* Lower irql back */
+    KeLowerIrql(OldIrql);
 }
+
+/* EOF */