Dispatching & Queue Rewrite II:
authorAlex Ionescu <aionescu@gmail.com>
Mon, 14 Mar 2005 05:54:32 +0000 (05:54 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Mon, 14 Mar 2005 05:54:32 +0000 (05:54 +0000)
    - Rewrote wait code. It is now cleaner, more optimized and faster. All waiting
      functions are now clearly differentiated instead of sharing code. These functions
      are called up to a dozen times a second, so having dedicated code for each of
      them is a real boost in speed.
    - Fixed several queue issues, made a dedicated queue wait/wake function (you are not
      supposed to use KeWaitFor on a queue, and this is also a speed boost), and make it
      compatible with new wait code.
    - Optimized Work Queue code to be much smaller and better organized, by using an
      array instead of hard-coded multiple static variables. Also, add support for the
      real NT structures and implementation, paving the road for Dynamic Work Items, which
      also have timeouts, and deadlock dection + debug info.
    - Simplified PsBlockThread and made it compatible with wait code.
    - Added support for priority boosting when unwaiting a thread; will use later, as well
      as put proper boosting for dispatch objects.
    - Inlined all dispatcher lock functions and header initialization for speed.
    - Moved executive wait code into ob.

svn path=/trunk/; revision=14047

19 files changed:
reactos/config
reactos/include/ddk/extypes.h
reactos/ntoskrnl/Makefile
reactos/ntoskrnl/ex/init.c
reactos/ntoskrnl/ex/work.c
reactos/ntoskrnl/include/internal/ex.h
reactos/ntoskrnl/include/internal/ke.h
reactos/ntoskrnl/include/internal/ps.h
reactos/ntoskrnl/ke/event.c
reactos/ntoskrnl/ke/i386/tskswitch.S
reactos/ntoskrnl/ke/kthread.c
reactos/ntoskrnl/ke/mutex.c
reactos/ntoskrnl/ke/queue.c
reactos/ntoskrnl/ke/sem.c
reactos/ntoskrnl/ke/timer.c
reactos/ntoskrnl/ke/wait.c
reactos/ntoskrnl/ntoskrnl.def
reactos/ntoskrnl/ps/kill.c
reactos/ntoskrnl/ps/thread.c

index 3f4ba86..4045d73 100644 (file)
@@ -5,7 +5,6 @@
 # Possible values in the future: alpha,i386,m68k,mips,powerpc
 ARCH := i386
 
-
 #
 # Which cpu should reactos optimize for
 # example : i486, i586, pentium, pentium2, pentium3, pentium4
@@ -32,11 +31,6 @@ DBG := 0
 #
 CONFIG_SMP := 0
 
-#
-# whether to use a 3GB User, 1GB Kernel memory map
-#
-3GB := 0
-
 #
 # Which version of NDIS do we support up to?
 #
index 4db6f6d..29cfd89 100644 (file)
@@ -30,6 +30,22 @@ typedef enum _WORK_QUEUE_TYPE {
     MaximumWorkQueue
 } WORK_QUEUE_TYPE;
 
+typedef struct _EX_QUEUE_WORKER_INFO {
+    UCHAR QueueDisabled:1;
+    UCHAR MakeThreadsAsNecessary:1;
+    UCHAR WaitMode:1;
+    ULONG WorkerCount:29;
+} EX_QUEUE_WORKER_INFO, *PEX_QUEUE_WORKER_INFO;
+
+typedef struct _EX_WORK_QUEUE {
+    KQUEUE WorkerQueue;
+    ULONG DynamicThreadCount;
+    ULONG WorkItemsProcessed;
+    ULONG WorkItemsProcessedLastPass;
+    ULONG QueueDepthLastPass;
+    EX_QUEUE_WORKER_INFO Info;    
+} EX_WORK_QUEUE, *PEX_WORK_QUEUE;
+
 typedef ULONG_PTR ERESOURCE_THREAD, *PERESOURCE_THREAD;
 
 typedef struct _OWNER_ENTRY
index ac8c798..96e3f2a 100644 (file)
@@ -212,7 +212,8 @@ OBJECTS_OB = \
        ob/object.o \
        ob/sdcache.o \
        ob/security.o \
-       ob/symlink.o
+       ob/symlink.o \
+       ob/wait.o
 
 # Process Manager (Ps)
 OBJECTS_PS = \
index 6737db0..a5982fe 100644 (file)
@@ -27,11 +27,9 @@ extern ULONG_PTR LastKrnlPhysAddr;
 extern ULONG_PTR LastKernelAddress;
 extern LOADER_MODULE KeLoaderModules[64];
 extern PRTL_MESSAGE_RESOURCE_DATA KiBugCodeMessages;
-#if 0
 extern LIST_ENTRY KiProfileListHead;
 extern LIST_ENTRY KiProfileSourceListHead;
 extern KSPIN_LOCK KiProfileLock;
-#endif
 
 VOID PspPostInitSystemProcess(VOID);
 
@@ -427,12 +425,10 @@ ExpInitializeExecutive(VOID)
     /* Bring back the IRQL to Passive */
     KeLowerIrql(PASSIVE_LEVEL);
     
-#if 0
     /* Initialize Profiling */
     InitializeListHead(&KiProfileListHead);
     InitializeListHead(&KiProfileSourceListHead);
     KeInitializeSpinLock(&KiProfileLock);
-#endif
     
     /* Load basic Security for other Managers */
     if (!SeInit1()) KEBUGCHECK(SECURITY_INITIALIZATION_FAILED);
@@ -488,7 +484,7 @@ ExpInitializeExecutive(VOID)
     PspPostInitSystemProcess();
 
     /* initialize the worker threads */
-    ExInitializeWorkerThreads();
+    ExpInitializeWorkerThreads();
     
     /* initialize callbacks */
     ExpInitializeCallbacks();
index ff1f747..0a5f82f 100644 (file)
@@ -1,11 +1,11 @@
-/* $Id$
- *
+/*
  * COPYRIGHT:          See COPYING in the top level directory
  * PROJECT:            ReactOS kernel
  * FILE:               ntoskrnl/ex/work.c
  * PURPOSE:            Manage system work queues
  * 
- * PROGRAMMERS:        David Welch (welch@mcmail.com)
+ * PROGRAMMERS:        Alex Ionescu - Used correct work queue array and added some fixes and checks.
+ *                     Gunnar Dalsnes - Implemented
  */
 
 /* INCLUDES ******************************************************************/
 /*
  * PURPOSE: Queue of items waiting to be processed at normal priority
  */
-KQUEUE EiNormalWorkQueue;
-
-KQUEUE EiCriticalWorkQueue;
-
-KQUEUE EiHyperCriticalWorkQueue;
+EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue];
 
 /* FUNCTIONS ****************************************************************/
 
-//static NTSTATUS STDCALL
-static VOID STDCALL
-ExWorkerThreadEntryPoint(IN PVOID context)
 /*
  * FUNCTION: Entry point for a worker thread
  * ARGUMENTS:
@@ -44,161 +37,138 @@ ExWorkerThreadEntryPoint(IN PVOID context)
  * NOTE: To kill a worker thread you must queue an item whose callback
  * calls PsTerminateSystemThread
  */
+static
+VOID 
+STDCALL
+ExpWorkerThreadEntryPoint(IN PVOID Context)
 {
-
-   PWORK_QUEUE_ITEM item;
-   PLIST_ENTRY current;
+    PWORK_QUEUE_ITEM WorkItem;
+    PLIST_ENTRY QueueEntry;
+    WORK_QUEUE_TYPE WorkQueueType;
+    PEX_WORK_QUEUE WorkQueue;
    
-   while (TRUE) 
-   {
-      current = KeRemoveQueue( (PKQUEUE)context, KernelMode, NULL );
-      
-      /* can't happend since we do a KernelMode wait (and we're a system thread) */
-      ASSERT((NTSTATUS)current != STATUS_USER_APC);
-      
-      /* this should never happend either, since we wait with NULL timeout,
-       * but there's a slight possibility that STATUS_TIMEOUT is returned
-       * at queue rundown in NT (unlikely) -Gunnar
-       */
-      ASSERT((NTSTATUS)current != STATUS_TIMEOUT);
-      
-      /* based on INVALID_WORK_QUEUE_ITEM bugcheck desc. */
-      if (current->Flink == NULL || current->Blink == NULL)
-      {
-         KeBugCheck(INVALID_WORK_QUEUE_ITEM);
-      }
+    /* Get Queue Type and Worker Queue */
+    WorkQueueType = (WORK_QUEUE_TYPE)Context;
+    WorkQueue = &ExWorkerQueue[WorkQueueType];
+    
+    /* Loop forever */
+    while (TRUE) {
+        
+        /* Wait for Something to Happen on the Queue */
+        QueueEntry = KeRemoveQueue(&WorkQueue->WorkerQueue, KernelMode, NULL);
       
-      /* "reinitialize" item (same as done in ExInitializeWorkItem) */
-      current->Flink = NULL;
+        /* Can't happen since we do a KernelMode wait (and we're a system thread) */
+        ASSERT((NTSTATUS)QueueEntry != STATUS_USER_APC);
       
-      item = CONTAINING_RECORD( current, WORK_QUEUE_ITEM, List);
-      item->WorkerRoutine(item->Parameter);
-      
-      if (KeGetCurrentIrql() != PASSIVE_LEVEL)
-      {
-         KeBugCheck(IRQL_NOT_LESS_OR_EQUAL);
-      }
-   }
-   
+        /* this should never happen either, since we wait with NULL timeout,
+         * but there's a slight possibility that STATUS_TIMEOUT is returned
+         * at queue rundown in NT (unlikely) -Gunnar
+         */
+        ASSERT((NTSTATUS)QueueEntry != STATUS_TIMEOUT);
+    
+        /* Increment Processed Work Items */
+        InterlockedIncrement(&WorkQueue->WorkItemsProcessed);
+
+        /* Get the Work Item */
+        WorkItem = CONTAINING_RECORD(QueueEntry, WORK_QUEUE_ITEM, List);
+        
+        /* Call the Worker Routine */
+        WorkItem->WorkerRoutine(WorkItem->Parameter);
+    
+        /* Make sure it returned at right IRQL */
+        if (KeGetCurrentIrql() != PASSIVE_LEVEL) {
+        
+            /* FIXME: Make this an Ex */
+            KEBUGCHECK(WORKER_THREAD_RETURNED_AT_BAD_IRQL);
+        }
+    
+        /* Make sure it returned with Impersionation Disabled */
+        if (PsGetCurrentThread()->ActiveImpersonationInfo) {
+            
+            /* FIXME: Make this an Ex */
+            KEBUGCHECK(IMPERSONATING_WORKER_THREAD);
+        }
+    }
 }
 
-static VOID ExInitializeWorkQueue(PKQUEUE WorkQueue,
-                                 KPRIORITY Priority)
+static 
+VOID 
+STDCALL
+ExpInitializeWorkQueue(WORK_QUEUE_TYPE WorkQueueType,
+                       KPRIORITY Priority)
 {
     ULONG i;
     PETHREAD Thread;
     HANDLE hThread;
-    NTSTATUS Status;
-
-    PAGED_CODE();
-
+   
     /* Loop through how many threads we need to create */
     for (i = 0; i < NUMBER_OF_WORKER_THREADS; i++) {
-
+        
         /* Create the System Thread */
-        Status = PsCreateSystemThread(&hThread,
-                                      THREAD_ALL_ACCESS,
-                                      NULL,
-                                      NULL,
-                                      NULL,
-                                      ExWorkerThreadEntryPoint,
-                                      (PVOID)WorkQueue);
-        if(NT_SUCCESS(Status))
-        {
-          /* Get the Thread */
-          Status = ObReferenceObjectByHandle(hThread,
-                                             THREAD_SET_INFORMATION,
-                                             PsThreadType,
-                                             KernelMode,
-                                             (PVOID*)&Thread,
-                                             NULL);
-
-          if(NT_SUCCESS(Status))
-          {
-            /* Set the Priority */
-            KeSetPriorityThread(&Thread->Tcb, Priority);
-
-            /* Dereference and close handle */
-            ObDereferenceObject(Thread);
-            ZwClose(hThread);
-          }
-          else
-          {
-            DPRINT1("Unable to reference worker thread handle 0x%x, Status: 0x%x!\n", hThread, Status);
-            KEBUGCHECK(0);
-          }
-        }
-        else
-        {
-          DPRINT1("Unable to create worker thread, Status: 0x%x!\n", Status);
-          KEBUGCHECK(0);
-        }
+        PsCreateSystemThread(&hThread,
+                             THREAD_ALL_ACCESS,
+                             NULL,
+                             NULL,
+                             NULL,
+                             ExpWorkerThreadEntryPoint,
+                             (PVOID)WorkQueueType);
+        
+        /* Get the Thread */
+        ObReferenceObjectByHandle(hThread,
+                                  THREAD_SET_INFORMATION,
+                                  PsThreadType,
+                                  KernelMode,
+                                  (PVOID*)&Thread,
+                                  NULL);
+        
+        /* Set the Priority */
+        KeSetPriorityThread(&Thread->Tcb, Priority);
+        
+        /* Dereference and close handle */
+        ObDereferenceObject(Thread);
+        ZwClose(hThread);
     }
 }
 
-VOID INIT_FUNCTION
-ExInitializeWorkerThreads(VOID)
+VOID 
+INIT_FUNCTION
+ExpInitializeWorkerThreads(VOID)
 {
-   KeInitializeQueue( &EiNormalWorkQueue, NUMBER_OF_WORKER_THREADS );
-   KeInitializeQueue( &EiCriticalWorkQueue , NUMBER_OF_WORKER_THREADS );
-   KeInitializeQueue( &EiHyperCriticalWorkQueue , NUMBER_OF_WORKER_THREADS );
-
-   ExInitializeWorkQueue(&EiNormalWorkQueue,
-                        LOW_PRIORITY);
-   ExInitializeWorkQueue(&EiCriticalWorkQueue,
-                        LOW_REALTIME_PRIORITY);
-   ExInitializeWorkQueue(&EiHyperCriticalWorkQueue,
-                        HIGH_PRIORITY);
+    ULONG WorkQueueType;
+    
+    /* Initialize the Array */
+    for (WorkQueueType = 0; WorkQueueType < MaximumWorkQueue; WorkQueueType++) {
+    
+        RtlZeroMemory(&ExWorkerQueue[WorkQueueType], sizeof(EX_WORK_QUEUE));
+        KeInitializeQueue(&ExWorkerQueue[WorkQueueType].WorkerQueue, 0);
+    }
+    
+    /* Create the built-in worker threads for each work queue */
+    ExpInitializeWorkQueue(CriticalWorkQueue, LOW_REALTIME_PRIORITY);
+    ExpInitializeWorkQueue(DelayedWorkQueue, LOW_PRIORITY);
+    ExpInitializeWorkQueue(HyperCriticalWorkQueue, HIGH_PRIORITY);
 }
 
 /*
  * @implemented
- */
-VOID STDCALL
-ExQueueWorkItem (PWORK_QUEUE_ITEM      WorkItem,
-                WORK_QUEUE_TYPE                QueueType)
-/*
+ *
  * FUNCTION: Inserts a work item in a queue for one of the system worker
  * threads to process
  * ARGUMENTS:
  *        WorkItem = Item to insert
  *        QueueType = Queue to insert it in
  */
+VOID 
+STDCALL
+ExQueueWorkItem(PWORK_QUEUE_ITEM WorkItem,
+                WORK_QUEUE_TYPE QueueType)
 {
     ASSERT(WorkItem!=NULL);
     ASSERT_IRQL(DISPATCH_LEVEL);
     ASSERT(WorkItem->List.Flink == NULL);
-   /*
-    * Insert the item in the appropiate queue and wake up any thread
-    * waiting for something to do
-    */
-    switch(QueueType)
-    {
-    case DelayedWorkQueue:
-      KeInsertQueue (
-          &EiNormalWorkQueue,
-          &WorkItem->List
-            );
-       break;
-       
-    case CriticalWorkQueue:
-            KeInsertQueue (
-              &EiCriticalWorkQueue,
-              &WorkItem->List
-              );
-           break;
-
-    case HyperCriticalWorkQueue:
-            KeInsertQueue (
-             &EiHyperCriticalWorkQueue,
-             &WorkItem->List
-             );
-               break;
-     
-    default:
-        break;
-
-    }
+    
+    /* Insert the Queue */
+    KeInsertQueue(&ExWorkerQueue[QueueType].WorkerQueue, &WorkItem->List);
 }
 
 /* EOF */
index 521aa96..c2d17e9 100644 (file)
@@ -86,7 +86,9 @@ extern LARGE_INTEGER ExpTimeZoneBias;
 extern ULONG ExpTimeZoneId;
 
 extern POBJECT_TYPE ExEventPairObjectType;
-
+extern POBJECT_TYPE EXPORTED ExMutantObjectType;
+extern POBJECT_TYPE EXPORTED ExSemaphoreObjectType;
+extern POBJECT_TYPE EXPORTED ExTimerType;
 
 /* INITIALIZATION FUNCTIONS *************************************************/
 
@@ -100,7 +102,7 @@ ExInit3(VOID);
 VOID
 ExpInitTimeZoneInfo(VOID);
 VOID
-ExInitializeWorkerThreads(VOID);
+ExpInitializeWorkerThreads(VOID);
 VOID
 ExpInitLookasideLists(VOID);
 VOID
index 9bfc388..eaff778 100644 (file)
@@ -139,33 +139,38 @@ KeProfileInterruptWithSource(
        IN KPROFILE_SOURCE              Source
 );
 
-VOID KiInsertProfileIntoProcess(PLIST_ENTRY ListHead, PKPROFILE Profile);
-VOID KiInsertProfile(PKPROFILE Profile);
-VOID KiRemoveProfile(PKPROFILE Profile);
-VOID STDCALL KiDeleteProfile(PVOID ObjectBody);
-
 
 VOID STDCALL KeUpdateSystemTime(PKTRAP_FRAME TrapFrame, KIRQL Irql);
 VOID STDCALL KeUpdateRunTime(PKTRAP_FRAME TrapFrame, KIRQL Irql);
 
 VOID STDCALL KiExpireTimers(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2);
 
-KIRQL KeAcquireDispatcherDatabaseLock(VOID);
-VOID KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID);
-VOID KeReleaseDispatcherDatabaseLock(KIRQL Irql);
-VOID KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID);
+KIRQL inline FASTCALL KeAcquireDispatcherDatabaseLock(VOID);
+VOID inline FASTCALL KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID);
+VOID inline FASTCALL KeReleaseDispatcherDatabaseLock(KIRQL Irql);
+VOID inline FASTCALL KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID);
 
 BOOLEAN KiDispatcherObjectWake(DISPATCHER_HEADER* hdr, KPRIORITY increment);
 VOID STDCALL KeExpireTimers(PKDPC Apc,
                            PVOID Arg1,
                            PVOID Arg2,
                            PVOID Arg3);
-VOID KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header, ULONG Type,
-                                 ULONG Size, ULONG SignalState);
+VOID inline FASTCALL KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header, ULONG Type,
+                                 ULONG Size, ULONG SignalState);
 VOID KeDumpStackFrames(PULONG Frame);
 BOOLEAN KiTestAlert(VOID);
 
-BOOLEAN KiAbortWaitThread(struct _KTHREAD* Thread, NTSTATUS WaitStatus);
+VOID FASTCALL KiAbortWaitThread(struct _KTHREAD* Thread, NTSTATUS WaitStatus);
+BOOLEAN STDCALL KiInsertTimer(PKTIMER Timer, LARGE_INTEGER DueTime);
+
+VOID inline FASTCALL KiSatisfyObjectWait(PDISPATCHER_HEADER Object, PKTHREAD Thread);
+
+BOOLEAN inline FASTCALL KiIsObjectSignaled(PDISPATCHER_HEADER Object, PKTHREAD Thread);
+
+VOID inline FASTCALL KiSatisifyMultipleObjectWaits(PKWAIT_BLOCK WaitBlock);
+
+VOID FASTCALL KiWaitTest(PDISPATCHER_HEADER Object, KPRIORITY Increment);
 
 PULONG KeGetStackTopThread(struct _ETHREAD* Thread);
 VOID KeContextToTrapFrame(PCONTEXT Context, PKTRAP_FRAME TrapFrame);
@@ -191,6 +196,7 @@ STDCALL
 KeTestAlertThread(IN KPROCESSOR_MODE AlertMode);
 
 BOOLEAN STDCALL KeRemoveQueueApc (PKAPC Apc);
+VOID FASTCALL KiWakeQueue(IN PKQUEUE Queue);
 PLIST_ENTRY STDCALL KeRundownQueue(IN PKQUEUE Queue);
 
 extern LARGE_INTEGER SystemBootTime;
@@ -202,7 +208,7 @@ VOID KeInitInterrupts(VOID);
 VOID KeInitTimer(VOID);
 VOID KeInitDpc(struct _KPRCB* Prcb);
 VOID KeInitDispatcher(VOID);
-VOID KeInitializeDispatcher(VOID);
+VOID inline FASTCALL KeInitializeDispatcher(VOID);
 VOID KiInitializeSystemClock(VOID);
 VOID KiInitializeBugCheck(VOID);
 VOID Phase1Initialization(PVOID Context);
index 46d5453..307a0a8 100644 (file)
@@ -525,8 +525,11 @@ VOID PsUnfreezeProcessThreads(PEPROCESS Process);
 ULONG PsEnumThreadsByProcess(PEPROCESS Process);
 PEPROCESS PsGetNextProcess(PEPROCESS OldProcess);
 VOID
-PsBlockThread(PNTSTATUS Status, UCHAR Alertable, ULONG WaitMode, 
-             BOOLEAN DispatcherLock, KIRQL WaitIrql, UCHAR WaitReason);
+STDCALL
+PsBlockThread(PNTSTATUS Status, 
+              UCHAR Alertable, 
+              ULONG WaitMode,
+              UCHAR WaitReason);
 VOID
 PsUnblockThread(PETHREAD Thread, PNTSTATUS WaitStatus, KPRIORITY Increment);
 VOID
index c4ab1aa..7683afa 100644 (file)
@@ -91,7 +91,7 @@ KePulseEvent(IN PKEVENT Event,
         Event->Header.SignalState = 1;
     
         /* Wake the Event */
-        KiDispatcherObjectWake(&Event->Header, Increment);
+        KiWaitTest(&Event->Header, Increment);
     }
     
     /* Unsignal it */
@@ -196,7 +196,7 @@ KeSetEvent(PKEVENT Event,
                 /* We must do a full wait satisfaction */
                 DPRINT("Notification Event or WaitAll, Wait on the Event and Signal\n");
                 Event->Header.SignalState = 1;
-                KiDispatcherObjectWake(&Event->Header, Increment);
+                KiWaitTest(&Event->Header, Increment);
             }
                 
         } else {
index 4555f23..9e3bf2b 100644 (file)
@@ -204,7 +204,7 @@ SaveTrapFrameForKDB_Return:
         */
        sti
 
-       call    _KeReleaseDispatcherDatabaseLockFromDpcLevel
+       call    @KeReleaseDispatcherDatabaseLockFromDpcLevel@0
 
        cmpl    $0, _PiNrThreadsAwaitingReaping
        je      5f
index 040eb28..bf66f41 100644 (file)
@@ -56,7 +56,7 @@ KeAlertResumeThread(IN PKTHREAD Thread)
             
             /* Signal and satisfy */
             Thread->SuspendSemaphore.Header.SignalState++;
-            KiDispatcherObjectWake(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
+            KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
         }
     }
 
index de7f785..ff4b97e 100644 (file)
@@ -177,7 +177,7 @@ KeReleaseMutant(IN PKMUTANT Mutant,
             
             /* Wake the Mutant */
             DPRINT("Waking the Mutant\n");
-            KiDispatcherObjectWake(&Mutant->Header, Increment);
+            KiWaitTest(&Mutant->Header, Increment);
         }
     }
 
index 5cd85f9..6a1c654 100644 (file)
 
 /* FUNCTIONS *****************************************************************/
 
-
+LONG STDCALL KiInsertQueue(IN PKQUEUE Queue, IN PLIST_ENTRY Entry, BOOLEAN Head);
+              
 /*
  * @implemented
  */
-VOID STDCALL
+VOID 
+STDCALL
 KeInitializeQueue(IN PKQUEUE Queue,
-                 IN ULONG Count OPTIONAL)
+                  IN ULONG Count OPTIONAL)
 {
-  KeInitializeDispatcherHeader(&Queue->Header,
-                              QueueObject,
-                              sizeof(KQUEUE)/sizeof(ULONG),
-                              0);
-  InitializeListHead(&Queue->EntryListHead);
-  InitializeListHead(&Queue->ThreadListHead);
-  Queue->CurrentCount = 0;
-  Queue->MaximumCount = (Count == 0) ? (ULONG) KeNumberProcessors : Count;
+    DPRINT("KeInitializeQueue %x\n", Queue);
+    
+    /* Initialize the Header */
+    KeInitializeDispatcherHeader(&Queue->Header,
+                                 QueueObject,
+                                 sizeof(KQUEUE)/sizeof(ULONG),
+                                 0);
+    
+    /* Initialize the Lists */
+    InitializeListHead(&Queue->EntryListHead);
+    InitializeListHead(&Queue->ThreadListHead);
+    
+    /* Set the Current and Maximum Count */
+    Queue->CurrentCount = 0;
+    Queue->MaximumCount = (Count == 0) ? (ULONG) KeNumberProcessors : Count;
 }
 
-
 /*
  * @implemented
- *
- * Returns number of entries in the queue
- */
-LONG STDCALL
-KeReadStateQueue(IN PKQUEUE Queue)
-{
-  return(Queue->Header.SignalState);
-}
-
-/*
- * Returns the previous number of entries in the queue
  */
-LONG STDCALL
-KiInsertQueue(
-   IN PKQUEUE Queue,
-   IN PLIST_ENTRY Entry,
-   BOOLEAN Head
-   )
+LONG
+STDCALL
+KeInsertHeadQueue(IN PKQUEUE Queue,
+                  IN PLIST_ENTRY Entry)
 {
-   ULONG InitialState;
-  
-   DPRINT("KiInsertQueue(Queue %x, Entry %x)\n", Queue, Entry);
+    LONG PreviousState;
+    KIRQL OldIrql;
+    
+    DPRINT("KeInsertHeadQueue %x\n", Queue);
+    
+    /* Lock the Dispatcher Database */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+    
+    /* Insert the Queue */
+    PreviousState = KiInsertQueue(Queue, Entry, TRUE);
+    
+    /* Release the Dispatcher Lock */
+    KeReleaseDispatcherDatabaseLock(OldIrql);
    
-   InitialState = Queue->Header.SignalState;
-
-   if (Head)
-   {
-      InsertHeadList(&Queue->EntryListHead, Entry);
-   }
-   else
-   {
-      InsertTailList(&Queue->EntryListHead, Entry);
-   }
-   
-   //inc. num entries in queue
-   Queue->Header.SignalState++;
-   
-   /* Why the KeGetCurrentThread()->Queue != Queue?
-    * KiInsertQueue might be called from an APC for the current thread. 
-    * -Gunnar
-    */
-   if (Queue->CurrentCount < Queue->MaximumCount &&
-       !IsListEmpty(&Queue->Header.WaitListHead) &&
-       KeGetCurrentThread()->Queue != Queue)
-   {
-      KiDispatcherObjectWake(&Queue->Header, IO_NO_INCREMENT);
-   }
-
-   return InitialState;
+    /* Return previous State */
+    return PreviousState;
 }
 
-
-
 /*
  * @implemented
  */
 LONG STDCALL
-KeInsertHeadQueue(IN PKQUEUE Queue,
-                 IN PLIST_ENTRY Entry)
+KeInsertQueue(IN PKQUEUE Queue,
+              IN PLIST_ENTRY Entry)
 {
-   LONG Result;
-   KIRQL OldIrql;
-   
-   OldIrql = KeAcquireDispatcherDatabaseLock();
-   Result = KiInsertQueue(Queue,Entry,TRUE);
-   KeReleaseDispatcherDatabaseLock(OldIrql);
+    LONG PreviousState;
+    KIRQL OldIrql;
+    
+    DPRINT("KeInsertQueue %x\n", Queue);
+    
+    /* Lock the Dispatcher Database */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+    
+    /* Insert the Queue */
+    PreviousState = KiInsertQueue(Queue, Entry, FALSE);
+    
+    /* Release the Dispatcher Lock */
+    KeReleaseDispatcherDatabaseLock(OldIrql);
    
-   return Result;
+    /* Return previous State */
+    return PreviousState;
 }
 
-
 /*
  * @implemented
+ *
+ * Returns number of entries in the queue
  */
-LONG STDCALL
-KeInsertQueue(IN PKQUEUE Queue,
-             IN PLIST_ENTRY Entry)
+LONG
+STDCALL
+KeReadStateQueue(IN PKQUEUE Queue)
 {
-   LONG Result;
-   KIRQL OldIrql;
-   
-   OldIrql = KeAcquireDispatcherDatabaseLock();
-   Result = KiInsertQueue(Queue,Entry,FALSE);
-   KeReleaseDispatcherDatabaseLock(OldIrql);
-   
-   return Result;
+    /* Returns the Signal State */
+    return(Queue->Header.SignalState);
 }
 
-
 /*
  * @implemented
  */
-PLIST_ENTRY STDCALL
+PLIST_ENTRY 
+STDCALL
 KeRemoveQueue(IN PKQUEUE Queue,
-             IN KPROCESSOR_MODE WaitMode,
-             IN PLARGE_INTEGER Timeout OPTIONAL)
+              IN KPROCESSOR_MODE WaitMode,
+              IN PLARGE_INTEGER Timeout OPTIONAL)
 {
    
-   PLIST_ENTRY ListEntry;
-   NTSTATUS Status;
-   PKTHREAD Thread = KeGetCurrentThread();
-   KIRQL OldIrql;
-
-   OldIrql = KeAcquireDispatcherDatabaseLock ();
-
-   if (Thread->Queue != Queue)
-   {
-      /*
-       * INVESTIGATE: What is the Thread->QueueListEntry used for? It's linked it into the
-       * Queue->ThreadListHead when the thread registers with the queue and unlinked when
-       * the thread registers with a new queue. The Thread->Queue already tells us what
-       * queue the thread is registered with.
-       * -Gunnar
-       */
-
-      //unregister thread from previous queue (if any)
-      if (Thread->Queue)
-      {
-         RemoveEntryList(&Thread->QueueListEntry);
-         Thread->Queue->CurrentCount--;
-         
-         if (Thread->Queue->CurrentCount < Thread->Queue->MaximumCount && 
-             !IsListEmpty(&Thread->Queue->EntryListHead))
-         {
-            KiDispatcherObjectWake(&Thread->Queue->Header, 0);
-         }
+    PLIST_ENTRY ListEntry;
+    NTSTATUS Status;
+    PKTHREAD Thread = KeGetCurrentThread();
+    KIRQL OldIrql;
+    PKQUEUE PreviousQueue;
+    PKWAIT_BLOCK WaitBlock;
+    PKWAIT_BLOCK TimerWaitBlock;
+    PKTIMER Timer;
+
+    DPRINT("KeRemoveQueue %x\n", Queue);
+    
+    /* Check if the Lock is already held */
+    if (Thread->WaitNext) {
+    
+        DPRINT("Lock is already held\n");
+    
+    } else {
+        
+        /* Lock the Dispatcher Database */
+        DPRINT("Lock not held, acquiring\n");
+        OldIrql = KeAcquireDispatcherDatabaseLock();
+        Thread->WaitIrql = OldIrql;
+    }
+
+    /* This is needed so that we can set the new queue right here, before additional processing */
+    PreviousQueue = Thread->Queue;
+    Thread->Queue = Queue;
+
+    /* Check if this is a different queue */    
+    if (Queue != PreviousQueue) {
+        
+        /*
+         * INVESTIGATE: What is the Thread->QueueListEntry used for? It's linked it into the
+         * Queue->ThreadListHead when the thread registers with the queue and unlinked when
+         * the thread registers with a new queue. The Thread->Queue already tells us what
+         * queue the thread is registered with.
+         * -Gunnar
+         */
+        DPRINT("Different Queue\n");
+        if (PreviousQueue)  {
+          
+            /* Remove from this list */
+            DPRINT("Removing Old Queue\n");
+            RemoveEntryList(&Thread->QueueListEntry);
+            
+            /* Wake the queue */
+            DPRINT("Activating new thread\n");
+            KiWakeQueue(PreviousQueue);
       }
 
-      // register thread with this queue
-      InsertTailList(&Queue->ThreadListHead, &Thread->QueueListEntry);
-      Thread->Queue = Queue;
-   }
-   else /* if (Thread->Queue == Queue) */
-   {
-      //dec. num running threads
-      Queue->CurrentCount--;
-   }
-   
-   
-   
+        /* Insert in this new Queue */
+        DPRINT("Inserting new Queue!\n");
+        InsertTailList(&Queue->ThreadListHead, &Thread->QueueListEntry);
    
-   while (TRUE)
-   {
-      if (Queue->CurrentCount < Queue->MaximumCount && !IsListEmpty(&Queue->EntryListHead))
-      {
-         ListEntry = RemoveHeadList(&Queue->EntryListHead);
-         //dec. num entries in queue
-         Queue->Header.SignalState--;
-         //inc. num running threads
-         Queue->CurrentCount++;
-         
-         KeReleaseDispatcherDatabaseLock(OldIrql);
-         return ListEntry;
-      }
-      else
-      {
-         //inform KeWaitXxx that we are holding disp. lock
-         Thread->WaitNext = TRUE;
-         Thread->WaitIrql = OldIrql;
-
-         Status = KeWaitForSingleObject(Queue,
-                                        WrQueue,
-                                        WaitMode,
-                                        TRUE, //bAlertable
-                                        Timeout);
-
-         if (Status == STATUS_TIMEOUT || Status == STATUS_USER_APC)
-         {
-            return (PVOID)Status;
-         }
-         
-         OldIrql = KeAcquireDispatcherDatabaseLock ();
-      }
-   }
+    } else {
+      
+        /* Same queue, decrement waiting threads */
+        DPRINT("Same Queue!\n");
+        Queue->CurrentCount--;
+    }
+    
+    /* Loop until the queue is processed */
+    while (TRUE) {
+      
+        /* Get the Entry */
+        ListEntry = Queue->EntryListHead.Flink;
+        
+        /* Check if the counts are valid and if there is still a queued entry */
+        if ((Queue->CurrentCount < Queue->MaximumCount) && 
+             (ListEntry != &Queue->EntryListHead)) {
+          
+            /* Remove the Entry and Save it */
+            DPRINT("Removing Queue Entry. CurrentCount: %d, Maximum Count: %d\n", 
+                    Queue->CurrentCount, Queue->MaximumCount);
+            ListEntry = RemoveHeadList(&Queue->EntryListHead);
+            
+            /* Decrease the number of entries */
+            Queue->Header.SignalState--;
+            
+            /* Increase numbef of running threads */
+            Queue->CurrentCount++;
+            
+            /* Check if the entry is valid. If not, bugcheck */
+            if (!ListEntry->Flink || !ListEntry->Blink) {
+            
+                KEBUGCHECK(INVALID_WORK_QUEUE_ITEM);
+            }
+            
+            /* Remove the Entry */
+            RemoveEntryList(ListEntry);
+            ListEntry->Flink = NULL;
+            
+            /* Nothing to wait on */
+            break;
+            
+        } else {
+                       
+            /* Do the wait */
+            DPRINT("Waiting on Queue Entry. CurrentCount: %d, Maximum Count: %d\n", 
+                    Queue->CurrentCount, Queue->MaximumCount);
+            
+            /* Use the Thread's Wait Block, it's big enough */
+            Thread->WaitBlockList = &Thread->WaitBlock[0];
+            
+            /* Fail if there's an APC Pending */
+            if (WaitMode == UserMode && Thread->ApcState.UserApcPending) {
+            
+                /* Return the status and increase the pending threads */
+                ListEntry = (PLIST_ENTRY)STATUS_USER_APC;
+                Queue->CurrentCount++;
+                
+                /* Nothing to wait on */
+                break;
+            }
+            
+            /* Build the Wait Block */
+            WaitBlock = &Thread->WaitBlock[0];
+            WaitBlock->Object = (PVOID)Queue;
+            WaitBlock->WaitKey = STATUS_SUCCESS;
+            WaitBlock->WaitType = WaitAny;
+            WaitBlock->Thread = Thread;
+            WaitBlock->NextWaitBlock = NULL;
+            
+            Thread->WaitStatus = STATUS_SUCCESS;
+            
+            /* We need to wait for the object... check if we have a timeout */
+            if (Timeout) {
+        
+                /* If it's zero, then don't do any waiting */
+                if (!Timeout->QuadPart) {
+            
+                    /* Instant Timeout, return the status and increase the pending threads */
+                    DPRINT("Queue Wait has timed out\n");
+                    ListEntry = (PLIST_ENTRY)STATUS_TIMEOUT;
+                    Queue->CurrentCount++;
+                    
+                    /* Nothing to wait on */
+                    break;
+                }
+                
+                /* 
+                 * Set up the Timer. We'll use the internal function so that we can
+                 * hold on to the dispatcher lock.
+                 */
+                Timer = &Thread->Timer;
+                TimerWaitBlock = &Thread->WaitBlock[1];
+
+                /* Set up the Timer Wait Block */
+                TimerWaitBlock->Object = (PVOID)Timer;
+                TimerWaitBlock->Thread = Thread;
+                TimerWaitBlock->WaitKey = STATUS_TIMEOUT;
+                TimerWaitBlock->WaitType = WaitAny;
+                TimerWaitBlock->NextWaitBlock = NULL;
+            
+                /* Link the timer to this Wait Block */
+                InitializeListHead(&Timer->Header.WaitListHead);
+                InsertTailList(&Timer->Header.WaitListHead, &TimerWaitBlock->WaitListEntry);
+            
+                /* Create Timer */
+                DPRINT("Creating Timer with timeout %I64d\n", *Timeout);
+                KiInsertTimer(Timer, *Timeout);
+            }
+                            
+            /* Insert the wait block into the Queues's wait list */
+            WaitBlock = Thread->WaitBlockList;
+            InsertTailList(&Queue->Header.WaitListHead, &WaitBlock->WaitListEntry);
+            
+            /* Block the Thread */
+            DPRINT("Blocking the Thread: %x %x!\n", KeGetCurrentThread(), Thread);
+            PsBlockThread(&Status, 
+                          FALSE, 
+                          WaitMode,
+                          WrQueue);
+    
+            /* Reset the wait reason */
+            Thread->WaitReason = 0;
+            
+            /* Check if we were executing an APC */
+            if (Status != STATUS_KERNEL_APC) {
+             
+                /* Done Waiting  */
+                DPRINT("Done waking queue. Thread: %x %x!\n", KeGetCurrentThread(), Thread);
+                return (PLIST_ENTRY)Status;
+            }
+        
+            /* Acquire again the lock */
+            DPRINT("Looping again\n");
+            OldIrql = KeAcquireDispatcherDatabaseLock();
+            
+            /* Save the new IRQL and decrease number of waiting threads */
+            Thread->WaitIrql = OldIrql;
+            Queue->CurrentCount--;
+        }
+    }
+    
+    /* Unlock Database and return */
+    KeReleaseDispatcherDatabaseLock(Thread->WaitIrql);
+    DPRINT("Returning. CurrentCount: %d, Maximum Count: %d\n", 
+            Queue->CurrentCount, Queue->MaximumCount);
+    return ListEntry;
 }
 
-
 /*
  * @implemented
  */
-PLIST_ENTRY STDCALL
+PLIST_ENTRY 
+STDCALL
 KeRundownQueue(IN PKQUEUE Queue)
 {
-   PLIST_ENTRY EnumEntry;
-   PKTHREAD Thread;
-   KIRQL OldIrql;
-
-   DPRINT("KeRundownQueue(Queue %x)\n", Queue);
-
-   /* I'm just guessing how this should work:-/
-    * -Gunnar 
-    */
-     
-   OldIrql = KeAcquireDispatcherDatabaseLock ();
-
-   //no thread must wait on queue at rundown
-   ASSERT(IsListEmpty(&Queue->Header.WaitListHead));
+    PLIST_ENTRY EnumEntry;
+    PLIST_ENTRY FirstEntry;
+    PKTHREAD Thread;
+    KIRQL OldIrql;
+
+    DPRINT("KeRundownQueue(Queue %x)\n", Queue);
+
+    /* Get the Dispatcher Lock */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+
+    /* Get the First Empty Entry */
+    FirstEntry = Queue->EntryListHead.Flink;
+            
+    /* Make sure the list is not empty */
+    if (FirstEntry == &Queue->EntryListHead) {
+    
+        /* It is, so don't return anything */
+        EnumEntry = NULL;
    
-   // unlink threads and clear their Thread->Queue
-   while (!IsListEmpty(&Queue->ThreadListHead))
-   {
-      EnumEntry = RemoveHeadList(&Queue->ThreadListHead);
-      Thread = CONTAINING_RECORD(EnumEntry, KTHREAD, QueueListEntry);
-      Thread->Queue = NULL;
-   }
-
-   if (IsListEmpty(&Queue->EntryListHead))
-   {
-      EnumEntry = NULL;
-   }
-   else
-   {
-      EnumEntry = Queue->EntryListHead.Flink;
-   }
+    } else {
+       
+        /* Remove it */
+        RemoveEntryList(&Queue->EntryListHead);
+    }
+    
+    /* Unlink threads and clear their Thread->Queue */
+    while (!IsListEmpty(&Queue->ThreadListHead)) {
+        
+        /* Get the Entry and Remove it */
+        EnumEntry = RemoveHeadList(&Queue->ThreadListHead);
+        
+        /* Get the Entry's Thread */
+        Thread = CONTAINING_RECORD(EnumEntry, KTHREAD, QueueListEntry);
+        
+        /* Kill its Queue */
+        Thread->Queue = NULL;
+    }
+
+    /* Release the lock and return */
+    KeReleaseDispatcherDatabaseLock(OldIrql);
+    return FirstEntry;
+}
 
-   KeReleaseDispatcherDatabaseLock (OldIrql);
+/*
+ * Called when a thread which has a queue entry is entering a wait state
+ */
+VOID
+FASTCALL
+KiWakeQueue(IN PKQUEUE Queue)
+{
+    PLIST_ENTRY QueueEntry;
+    PLIST_ENTRY WaitEntry;
+    PKWAIT_BLOCK WaitBlock;
+    
+    /* Decrement the number of active threads */
+    DPRINT("KiWakeQueue: %x. Thread: %x\n", Queue, KeGetCurrentThread());
+    Queue->CurrentCount--;
+    
+    /* Make sure the counts are OK */
+    if (Queue->CurrentCount < Queue->MaximumCount) {
+    
+        /* Get the Queue Entry */
+        QueueEntry = Queue->EntryListHead.Flink;
+        
+        /* Get the Wait Entry */
+        WaitEntry = Queue->Header.WaitListHead.Blink;
+        DPRINT("Queue Count is ok, Queue entries: %x, %x\n", QueueEntry, WaitEntry);
+        
+        /* Make sure that the Queue List isn't empty and that this entry is valid */
+        if (!IsListEmpty(&Queue->Header.WaitListHead) && 
+            (QueueEntry != &Queue->EntryListHead)) {
+            
+            /* Remove this entry */
+            DPRINT("Queue in List, removing it\n");
+            RemoveEntryList(QueueEntry);
+            QueueEntry->Flink = NULL;
+            
+            /* Decrease the Signal State */
+            Queue->Header.SignalState--;
+            
+            /* Unwait the Thread */
+            DPRINT("Unwaiting Thread\n");
+            WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry);
+            KiAbortWaitThread(WaitBlock->Thread, (NTSTATUS)QueueEntry);
+        }
+    }    
+}
 
-   return EnumEntry;
+/*
+ * Returns the previous number of entries in the queue
+ */
+LONG 
+STDCALL
+KiInsertQueue(IN PKQUEUE Queue,
+              IN PLIST_ENTRY Entry,
+              BOOLEAN Head)
+{
+    ULONG InitialState;
+    PKTHREAD Thread = KeGetCurrentThread();
+    PKWAIT_BLOCK WaitBlock;
+    PLIST_ENTRY WaitEntry;
+  
+    DPRINT("KiInsertQueue(Queue %x, Entry %x)\n", Queue, Entry);
+   
+    /* Save the old state */
+    InitialState = Queue->Header.SignalState;
+     
+    /* Get the Entry */
+    WaitEntry = Queue->Header.WaitListHead.Blink;
+    DPRINT("Initial State, WaitEntry: %d, %x\n", InitialState, WaitEntry);
+    
+    /*
+     * Why the KeGetCurrentThread()->Queue != Queue?
+     * KiInsertQueue might be called from an APC for the current thread. 
+     * -Gunnar
+     */
+    if ((Queue->CurrentCount < Queue->MaximumCount) && 
+        (WaitEntry != &Queue->Header.WaitListHead) &&
+        ((Thread->Queue != Queue) || (Thread->WaitReason != WrQueue))) {
+       
+        /* Remove the wait entry */
+        DPRINT("Removing Entry\n");
+        RemoveEntryList(WaitEntry);
+        
+        /* Get the Wait Block and Thread */
+        WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry);
+        DPRINT("Got wait block: %x\n", WaitBlock);
+        Thread = WaitBlock->Thread;
+        
+        /* Reset the wait reason */
+        Thread->WaitReason = 0;
+        
+        /* Increase the waiting threads */
+        Queue->CurrentCount++;
+        
+        /* 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);
+        }
+        
+        /* Reschedule the Thread */
+        DPRINT("Unblocking the Thread\n");
+        PsUnblockThread((PETHREAD)Thread, (PNTSTATUS)&Entry, 0);
+    
+    } else {
+    
+        /* Increase the Entries */
+        DPRINT("Adding new Queue Entry: %d %d\n", Head, Queue->Header.SignalState);
+        Queue->Header.SignalState++;
+        
+        if (Head) {
+        
+            InsertHeadList(&Queue->EntryListHead, Entry);
+        
+        } else {
+        
+            InsertTailList(&Queue->EntryListHead, Entry);
+        }
+    }
+
+    /* Return the previous state */
+    DPRINT("Returning\n");
+    return InitialState;
 }
 
 /* EOF */
index d90a7fd..f949905 100644 (file)
@@ -111,7 +111,7 @@ KeReleaseSemaphore(PKSEMAPHORE Semaphore,
     if (InitialState == 0 && !IsListEmpty(&Semaphore->Header.WaitListHead)) {
         
         /* Wake the Semaphore */
-        KiDispatcherObjectWake(&Semaphore->Header, SEMAPHORE_INCREMENT);
+        KiWaitTest(&Semaphore->Header, SEMAPHORE_INCREMENT);
     }
 
     /* If the Wait is true, then return with a Wait and don't unlock the Dispatcher Database */
index e2dba44..226a4d2 100644 (file)
@@ -291,7 +291,7 @@ KiHandleExpiredTimer(PKTIMER Timer)
     /* Set it as Signaled */
     DPRINT("Setting Timer as Signaled\n");
     Timer->Header.SignalState = TRUE;
-    KiDispatcherObjectWake(&Timer->Header, 0);   
+    KiWaitTest(&Timer->Header, 0);   
 
     /* If the Timer is periodic, reinsert the timer with the new due time */
     if (Timer->Period) {
index b1f630f..0da88c8 100644 (file)
@@ -1,16 +1,11 @@
-/* $Id$
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS project
  * FILE:            ntoskrnl/ke/wait.c
  * PURPOSE:         Manages non-busy waiting
  * 
- * PROGRAMMERS:     David Welch (welch@mcmail.com)
- *                  Phillip Susi
- */
-
-/* NOTES ********************************************************************
- *
+ * PROGRAMMERS:     Alex Ionescu - Fixes and optimization.
+ *                  Gunnar Dalsnes - Implementation
  */
 
 /* INCLUDES ******************************************************************/
 
 static KSPIN_LOCK DispatcherDatabaseLock;
 
-#define KeDispatcherObjectWakeOne(hdr, increment) KeDispatcherObjectWakeOneOrAll(hdr, increment, FALSE)
-#define KeDispatcherObjectWakeAll(hdr, increment) KeDispatcherObjectWakeOneOrAll(hdr, increment, TRUE)
+/* Tells us if the Timer or Event is a Syncronization or Notification Object */
+#define TIMER_OR_EVENT_TYPE 0x7L
 
-extern POBJECT_TYPE EXPORTED ExMutantObjectType;
-extern POBJECT_TYPE EXPORTED ExSemaphoreObjectType;
-extern POBJECT_TYPE EXPORTED ExTimerType;
+/* One of the Reserved Wait Blocks, this one is for the Thread's Timer */
+#define TIMER_WAIT_BLOCK 0x3L
 
 /* FUNCTIONS *****************************************************************/
 
-VOID 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
-KeAcquireDispatcherDatabaseLock(VOID)
-/*
- * PURPOSE: Acquires the dispatcher database lock for the caller
- */
-{
-   KIRQL OldIrql;
-
-   DPRINT("KeAcquireDispatcherDatabaseLock()\n");
-
-   KeAcquireSpinLock (&DispatcherDatabaseLock, &OldIrql);
-   return OldIrql;
-}
-
-
 VOID
-KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID)
-/*
- * PURPOSE: Acquires the dispatcher database lock for the caller
- */
-{
-   DPRINT("KeAcquireDispatcherDatabaseLockAtDpcLevel()\n");
-
-   KeAcquireSpinLockAtDpcLevel (&DispatcherDatabaseLock);
-}
-
-
-VOID
-KeReleaseDispatcherDatabaseLock(KIRQL OldIrql)
-{
-  DPRINT("KeReleaseDispatcherDatabaseLock(OldIrql %x)\n",OldIrql);
-  if (!KeIsExecutingDpc() && 
-      OldIrql < DISPATCH_LEVEL && 
-      KeGetCurrentThread() != NULL && 
-      KeGetCurrentThread() == KeGetCurrentPrcb()->IdleThread)
-  {
-    PsDispatchThreadNoLock(THREAD_STATE_READY);
-    KeLowerIrql(OldIrql);
-  }
-  else
-  {
-    KeReleaseSpinLock(&DispatcherDatabaseLock, OldIrql);
-  }
-}
-
-
-VOID
-KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID)
-{
-  DPRINT("KeReleaseDispatcherDatabaseLock()\n");
-
-  KeReleaseSpinLockFromDpcLevel(&DispatcherDatabaseLock);
-}
-
-
-static BOOLEAN
-KiSideEffectsBeforeWake(DISPATCHER_HEADER * hdr,
-                        PKTHREAD Thread)
-/*
- * FUNCTION: Perform side effects on object before a wait for a thread is
- *           satisfied
- */
-{
-   BOOLEAN Abandoned = FALSE;
-
-   switch (hdr->Type)
-   {
-      case EventSynchronizationObject:
-         hdr->SignalState = 0;
-         break;
-      
-      case QueueObject:
-         break;
-         
-      case SemaphoreObject:
-         hdr->SignalState--;
-         break;
-
-      case ProcessObject:
-         break;
-
-      case ThreadObject:
-         break;
-
-      case EventNotificationObject:
-         break;
-
-      case TimerSynchronizationObject:
-         hdr->SignalState = FALSE;
-         break;
-
-      case TimerNotificationObject:
-         break;
-
-      case MutantObject:
-      {
-         PKMUTEX Mutex;
-
-         Mutex = CONTAINING_RECORD(hdr, KMUTEX, Header);
-         hdr->SignalState--;
-         ASSERT(hdr->SignalState <= 1);
-         if (hdr->SignalState == 0)
-         {
-            if (Thread == NULL)
-            {
-               DPRINT("Thread == NULL!\n");
-               KEBUGCHECK(0);
-            }
-            Abandoned = Mutex->Abandoned;
-            if (Thread != NULL)
-               InsertTailList(&Thread->MutantListHead, &Mutex->MutantListEntry);
-            Mutex->OwnerThread = Thread;
-            Mutex->Abandoned = FALSE;
-         }
-      }
-         break;
-
-      default:
-         DbgPrint("(%s:%d) Dispatcher object %x has unknown type\n", __FILE__, __LINE__, hdr);
-         KEBUGCHECK(0);
-   }
-
-   return Abandoned;
-}
-
-static BOOLEAN
-KiIsObjectSignalled(DISPATCHER_HEADER * hdr,
-                    PKTHREAD Thread)
-{
-   if (hdr->Type == MutantObject)
-   {
-      PKMUTEX Mutex;
-
-      Mutex = CONTAINING_RECORD(hdr, KMUTEX, Header);
-
-      ASSERT(hdr->SignalState <= 1);
-
-      if ((hdr->SignalState < 1 && Mutex->OwnerThread == Thread) || hdr->SignalState == 1)
-      {
-         return (TRUE);
-      }
-      else
-      {
-         return (FALSE);
-      }
-   }
-
-   if (hdr->SignalState <= 0)
-   {
-      return (FALSE);
-   }
-   else
-   {
-      return (TRUE);
-   }
-}
-
-/* Must be called with the dispatcher lock held */
-BOOLEAN KiAbortWaitThread(PKTHREAD Thread, NTSTATUS WaitStatus)
-{
-   PKWAIT_BLOCK WaitBlock;
-   BOOLEAN WasWaiting;
-
-   /* if we are blocked, we must be waiting on something also */
-   ASSERT((Thread->State == THREAD_STATE_BLOCKED) == (Thread->WaitBlockList != NULL));
-
-   WaitBlock = (PKWAIT_BLOCK)Thread->WaitBlockList;
-   WasWaiting = (WaitBlock != NULL);
-   
-   while (WaitBlock)
-   {
-      RemoveEntryList(&WaitBlock->WaitListEntry);
-      WaitBlock = WaitBlock->NextWaitBlock;
-   }
-   
-   Thread->WaitBlockList = NULL;
-
-   if (WasWaiting)
-   {
-          PsUnblockThread((PETHREAD)Thread, &WaitStatus, 0);
-   }
-   return WasWaiting;
-}
-
-static BOOLEAN
-KeDispatcherObjectWakeOneOrAll(DISPATCHER_HEADER * hdr,
-                               KPRIORITY increment,
-                               BOOLEAN WakeAll)
-{
-   PKWAIT_BLOCK Waiter;
-   PKWAIT_BLOCK WaiterHead;
-   PLIST_ENTRY EnumEntry;
-   NTSTATUS Status;
-   BOOLEAN Abandoned;
-   BOOLEAN AllSignaled;
-   BOOLEAN WakedAny = FALSE;
-
-   DPRINT("KeDispatcherObjectWakeOnOrAll(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);
-   }
-
-   //enum waiters for this dispatcher object
-   EnumEntry = hdr->WaitListHead.Flink;
-   while (EnumEntry != &hdr->WaitListHead && (WakeAll || !WakedAny))
-   {
-      WaiterHead = CONTAINING_RECORD(EnumEntry, KWAIT_BLOCK, WaitListEntry);
-      DPRINT("current_entry %x current %x\n", EnumEntry, WaiterHead);
-      EnumEntry = EnumEntry->Flink;
-      ASSERT(WaiterHead->Thread != NULL);
-      ASSERT(WaiterHead->Thread->WaitBlockList != NULL);
-
-      Abandoned = FALSE;
-
-      if (WaiterHead->WaitType == WaitAny)
-      {
-         DPRINT("WaitAny: Remove all wait blocks.\n");
-         for (Waiter = WaiterHead->Thread->WaitBlockList; Waiter; Waiter = Waiter->NextWaitBlock)
-         {
-            RemoveEntryList(&Waiter->WaitListEntry);
-         }
-
-         WaiterHead->Thread->WaitBlockList = NULL;
-
-         /*
-          * If a WakeAll KiSideEffectsBeforeWake(hdr,.. will be called several times,
-          * but thats ok since WakeAll objects has no sideeffects.
-          */
-         Abandoned |= KiSideEffectsBeforeWake(hdr, WaiterHead->Thread);
-      }
-      else
-      {
-         DPRINT("WaitAll: All WaitAll objects must be signaled.\n");
-
-         AllSignaled = TRUE;
-
-         //all WaitAll obj. for thread need to be signaled to satisfy a wake
-         for (Waiter = WaiterHead->Thread->WaitBlockList; Waiter; Waiter = Waiter->NextWaitBlock)
-         {
-            //no need to check hdr since it has to be signaled
-            if (Waiter->WaitType == WaitAll && Waiter->Object != hdr)
-            {
-               if (!KiIsObjectSignalled(Waiter->Object, Waiter->Thread))
-               {
-                  AllSignaled = FALSE;
-                  break;
-               }
-            }
-         }
-
-         if (AllSignaled)
-         {
-            for (Waiter = WaiterHead->Thread->WaitBlockList; Waiter; Waiter = Waiter->NextWaitBlock)
-            {
-               RemoveEntryList(&Waiter->WaitListEntry);
-         
-               if (Waiter->WaitType == WaitAll)
-               {
-                  Abandoned |= KiSideEffectsBeforeWake(Waiter->Object, Waiter->Thread);
-               }
-
-               //no WaitAny objects can possibly be signaled since we are here
-               ASSERT(!(Waiter->WaitType == WaitAny
-                                         && KiIsObjectSignalled(Waiter->Object, Waiter->Thread)));
-            }
-
-            WaiterHead->Thread->WaitBlockList = NULL;
-         }
-      }
-
-      if (WaiterHead->Thread->WaitBlockList == NULL)
-      {
-         Status = WaiterHead->WaitKey;
-         if (Abandoned)
-         {
-            DPRINT("Abandoned mutex among objects");
-            Status += STATUS_ABANDONED_WAIT_0;
-         }
-
-         WakedAny = TRUE;
-         DPRINT("Waking %x status = %x\n", WaiterHead->Thread, Status);
-         PsUnblockThread(CONTAINING_RECORD(WaiterHead->Thread, ETHREAD, Tcb),
-                         &Status, increment);
-      }
-   }
-
-   return WakedAny;
-}
-
-
-BOOLEAN KiDispatcherObjectWake(DISPATCHER_HEADER* hdr, KPRIORITY increment)
-/*
- * FUNCTION: Wake threads waiting on a dispatcher object
- * NOTE: The exact semantics of waking are dependant on the type of object
- */
+inline
+FASTCALL
+KiCheckAlertability(BOOLEAN Alertable,
+                    PKTHREAD CurrentThread,
+                    KPROCESSOR_MODE WaitMode,
+                    PNTSTATUS Status)
 {
-   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 EventNotificationObject:
-       return(KeDispatcherObjectWakeAll(hdr, increment));
-
-      case TimerNotificationObject:
-       return(KeDispatcherObjectWakeAll(hdr, increment));
-
-      case EventSynchronizationObject:
-       return(KeDispatcherObjectWakeOne(hdr, increment));
-
-      case TimerSynchronizationObject:
-       return(KeDispatcherObjectWakeOne(hdr, increment));
-
-      case QueueObject:
-       return(KeDispatcherObjectWakeOne(hdr, increment));
-      
-      case SemaphoreObject:
-       DPRINT("hdr->SignalState %d\n", hdr->SignalState);
-       if(hdr->SignalState>0)
-         {
-           do
-             {
-               DPRINT("Waking one semaphore waiter\n");
-               Ret = KeDispatcherObjectWakeOne(hdr, increment);
-             } while(hdr->SignalState > 0 &&  Ret) ;
-           return(Ret);
-         }
-       else return FALSE;
-
-     case ProcessObject:
-       return(KeDispatcherObjectWakeAll(hdr, increment));
-
-     case ThreadObject:
-       return(KeDispatcherObjectWakeAll(hdr, increment));
-
-     case MutantObject:
-       return(KeDispatcherObjectWakeOne(hdr, increment));
-     }
-   DbgPrint("Dispatcher object %x has unknown type %d\n", hdr, hdr->Type);
-   KEBUGCHECK(0);
-   return(FALSE);
+    /* At this point, we have to do a wait, so make sure we can make the thread Alertable if requested */
+    if (Alertable) {
+    
+        /* If the Thread is Alerted, set the Wait Status accordingly */    
+        if (CurrentThread->Alerted[(int)WaitMode]) {
+            
+            CurrentThread->Alerted[(int)WaitMode] = FALSE;
+            DPRINT("Thread was Alerted\n");
+            *Status = STATUS_ALERTED;
+            
+        /* If there are User APCs Pending, then we can't really be alertable */
+        } else if ((!IsListEmpty(&CurrentThread->ApcState.ApcListHead[UserMode])) && 
+                    (WaitMode == UserMode)) {
+            
+            DPRINT("APCs are Pending\n");
+            CurrentThread->ApcState.UserApcPending = TRUE;
+            *Status = STATUS_USER_APC;
+        }
+    
+    /* If there are User APCs Pending and we are waiting in usermode, then we must notify the caller */
+    } else if ((CurrentThread->ApcState.UserApcPending) && (WaitMode == UserMode)) {
+            DPRINT("APCs are Pending\n");
+            *Status = STATUS_USER_APC;
+    }
 }
 
 /*
  * @implemented
- */
-NTSTATUS STDCALL
-KeDelayExecutionThread (KPROCESSOR_MODE        WaitMode,
-                       BOOLEAN         Alertable,
-                       PLARGE_INTEGER  Interval)
-/*
+ *
  * FUNCTION: Puts the current thread into an alertable or nonalertable 
  * wait state for a given internal
  * ARGUMENTS:
@@ -413,27 +72,102 @@ KeDelayExecutionThread (KPROCESSOR_MODE   WaitMode,
  *          Interval = Specifies the interval to wait
  * RETURNS: Status
  */
+NTSTATUS 
+STDCALL
+KeDelayExecutionThread(KPROCESSOR_MODE WaitMode,
+                       BOOLEAN Alertable,
+                       PLARGE_INTEGER Interval)
 {
-   PKTHREAD Thread = KeGetCurrentThread();
+    PKWAIT_BLOCK TimerWaitBlock;
+    PKTIMER ThreadTimer;
+    PKTHREAD CurrentThread = KeGetCurrentThread();
+    NTSTATUS Status;
 
-   KeSetTimer(&Thread->Timer, *Interval, NULL);
-   return (KeWaitForSingleObject(&Thread->Timer,
-                                (WaitMode == KernelMode) ? Executive : UserRequest, /* TMN: Was unconditionally Executive */
-                                WaitMode, /* TMN: Was UserMode */
-                                Alertable,
-                                NULL));
+    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];
+    
+    /* Start Wait Loop */
+    do {
+    
+        /* We are going to wait no matter what (that's the point), so test Alertability */
+        KiCheckAlertability(Alertable, CurrentThread, KernelMode, &Status);
+        
+        /* 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 = NULL;
+    
+        /* 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: Unhandled case...what should we do? */
+            DPRINT1("Could not create timer for KeDelayExecutionThread\n");
+        }    
+        
+        /* Handle Kernel Queues */
+        if (CurrentThread->Queue) {
+                 
+            DPRINT("Waking Queue\n");
+            KiWakeQueue(CurrentThread->Queue);
+        }
+
+        /* Block the Thread */
+        DPRINT("Blocking the Thread: %d, %d, %x\n", Alertable, WaitMode, KeGetCurrentThread());
+        PsBlockThread(&Status, 
+                      Alertable, 
+                      WaitMode, 
+                      DelayExecution);
+    
+        /* 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;
+        }
+        
+        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;   
 }
 
 /*
  * @implemented
- */
-NTSTATUS STDCALL
-KeWaitForSingleObject(PVOID Object,
-                      KWAIT_REASON WaitReason,
-                      KPROCESSOR_MODE WaitMode,
-                      BOOLEAN Alertable,
-                      PLARGE_INTEGER Timeout)
-/*
+ *
  * FUNCTION: Puts the current thread into a wait state until the
  * given dispatcher object is set to signalled
  * ARGUMENTS:
@@ -446,52 +180,174 @@ 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)
 {
-   return KeWaitForMultipleObjects(1,
-                                   &Object,
-                                   WaitAny,
-                                   WaitReason,
-                                   WaitMode,
-                                   Alertable,
-                                   Timeout,
-                                   NULL);
-}
+    PDISPATCHER_HEADER 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 {
+        
+        /* 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 = (PDISPATCHER_HEADER)Object;
+            
+        /* FIXME: 
+         * Temporary hack until my Object Manager re-write. Basically some objects, like
+         * the File Object, but also LPCs and others, are actually waitable on their event.
+         * The Object Manager sets this up in The ObjectTypeInformation->DefaultObject member,
+         * by using pretty much the same kind of hack as us. Normal objects point to themselves
+         * in that pointer. Then, NtWaitForXXX will populate the WaitList that gets sent to us by
+         * using ->DefaultObject, so the proper actual objects will be sent to us. Until then however,
+         * I will keep this hack here, since there's no need to make an interim hack until the rewrite
+         * -- Alex Ionescu 24/02/05
+         */
+        if (CurrentObject->Type == IO_TYPE_FILE) {
+                   
+            DPRINT1("Hack used: %x\n", &((PFILE_OBJECT)CurrentObject)->Event);
+            CurrentObject = (PDISPATCHER_HEADER)(&((PFILE_OBJECT)CurrentObject)->Event);
+        }
 
-inline
-PVOID
-KiGetWaitableObjectFromObject(PVOID Object)
-{
-   //special case when waiting on file objects
-   if ( ((PDISPATCHER_HEADER)Object)->Type == IO_TYPE_FILE)
-   {
-      return &((PFILE_OBJECT)Object)->Event;
-   }
+        /* Check if the Object is Signaled */
+        if (KiIsObjectSignaled(CurrentObject, CurrentThread)) {
+                    
+            /* Just unwait this guy and exit */
+            if (CurrentObject->SignalState != MINLONG) {
+                    
+                /* It has a normal signal state, so unwait it and return */
+                KiSatisfyObjectWait(CurrentObject, CurrentThread);
+                Status = STATUS_WAIT_0;
+                goto WaitDone;
+                    
+            } else {
+                    
+                /* Is this a Mutant? */
+                if (CurrentObject->Type == MutantObject) {
+                        
+                    /* According to wasm.ru, we must raise this exception (tested and true) */
+                    KeReleaseDispatcherDatabaseLock(CurrentThread->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 = NULL;
+                      
+        /* Make sure we can satisfy the Alertable request */
+        KiCheckAlertability(Alertable, CurrentThread, WaitMode, &Status);
+    
+        /* 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 WaitDone;
+            }
+                       
+            /* Point to Timer Wait Block and Thread Timer */
+            TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK];
+            ThreadTimer = &CurrentThread->Timer;
 
-   return Object;
-}
+            /* 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 = NULL;
+            
+            /* 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)) {    
 
-inline BOOL
-KiIsObjectWaitable(PVOID Object)
-{
-    POBJECT_HEADER Header;
-    Header = BODY_TO_HEADER(Object);
-    if (Header->ObjectType == ExEventObjectType ||
-       Header->ObjectType == ExIoCompletionType ||
-       Header->ObjectType == ExMutantObjectType ||
-       Header->ObjectType == ExSemaphoreObjectType ||
-       Header->ObjectType == ExTimerType ||
-       Header->ObjectType == PsProcessType ||
-       Header->ObjectType == PsThreadType ||
-       Header->ObjectType == IoFileObjectType)
-    {
-       return TRUE;
-    }
-    else
-    {
-       return FALSE;
-    }
+                /* Return a timeout if we couldn't insert the timer for some reason */
+                Status = STATUS_TIMEOUT;
+                goto WaitDone;
+            }    
+        }
+
+        /* Link the Object to this Wait Block */
+        InsertTailList(&CurrentObject->WaitListHead, &WaitBlock->WaitListEntry);            
+        
+        /* 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());
+        PsBlockThread(&Status, 
+                      Alertable, 
+                      WaitMode, 
+                      (UCHAR)WaitReason);
+    
+        /* Check if we were executing an APC */
+        if (Status != STATUS_KERNEL_APC) {
+           
+            /* Return Status */
+            return Status;
+        }
+        
+        DPRINT("Looping Again\n");
+        CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
+    
+    } while (TRUE);
+    
+WaitDone:
+    /* Release the Lock, we are done */
+    DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n", KeGetCurrentThread(), Status);
+    KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+    return Status;       
 }
 
 /*
@@ -507,558 +363,542 @@ KeWaitForMultipleObjects(ULONG Count,
                          PLARGE_INTEGER Timeout,
                          PKWAIT_BLOCK WaitBlockArray)
 {
-   DISPATCHER_HEADER *hdr;
-   PKWAIT_BLOCK blk;
-   PKTHREAD CurrentThread;
-   ULONG CountSignaled;
-   ULONG i;
-   NTSTATUS Status;
-   KIRQL OldIrql;
-   BOOLEAN Abandoned;
-   NTSTATUS WaitStatus;
-
-   DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
-          "PsGetCurrentThread() %x\n", Count, Object, PsGetCurrentThread());
-
-   ASSERT(0 < Count && Count <= MAXIMUM_WAIT_OBJECTS);
-
-   CurrentThread = KeGetCurrentThread();
-
-   /*
-    * Work out where we are going to put the wait blocks
-    */
-   if (WaitBlockArray == NULL)
-   {
-      if (Count > THREAD_WAIT_OBJECTS)
-      {
-         DPRINT("(%s:%d) Too many objects!\n", __FILE__, __LINE__);
-         return (STATUS_UNSUCCESSFUL);
-      }
-      WaitBlockArray = &CurrentThread->WaitBlock[0];
-   }
-   else
-   {
-      if (Count > MAXIMUM_WAIT_OBJECTS)
-      {
-         DPRINT("(%s:%d) Too many objects!\n", __FILE__, __LINE__);
-         return (STATUS_UNSUCCESSFUL);
-      }
-   }
-
-
-
-   /*
-    * Set up the timeout if required
-    */
-   if (Timeout != NULL && Timeout->QuadPart != 0)
-   {
-      KeSetTimer(&CurrentThread->Timer, *Timeout, NULL);
-   }
-
-   do
-   {
-      if (CurrentThread->WaitNext)
-      {
-         CurrentThread->WaitNext = FALSE;
-         OldIrql = CurrentThread->WaitIrql;
-      }
-      else
-      {
-         OldIrql = KeAcquireDispatcherDatabaseLock ();
-      }
-
-    /* Get the current Wait Status */
-    WaitStatus = CurrentThread->WaitStatus;
-   
-    if (Alertable) {
+    PDISPATCHER_HEADER 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();
     
-        /* If the Thread is Alerted, set the Wait Status accordingly */    
-        if (CurrentThread->Alerted[(int)WaitMode]) {
-            
-            CurrentThread->Alerted[(int)WaitMode] = FALSE;
-            DPRINT("Thread was Alerted\n");
-            WaitStatus = STATUS_ALERTED;
-            
-        /* If there are User APCs Pending, then we can't really be alertable */
-        } else if ((!IsListEmpty(&CurrentThread->ApcState.ApcListHead[UserMode])) && 
-                   (WaitMode == UserMode)) {
+    /* 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) {
+       
+        /* Check in regards to the Thread Object Limit */
+        if (Count > THREAD_WAIT_OBJECTS) {
             
-            DPRINT1("APCs are Pending\n");
-            CurrentThread->ApcState.UserApcPending = TRUE;
-            WaitStatus = STATUS_USER_APC;
+            DPRINT1("(%s:%d) Too many objects!\n", __FILE__, __LINE__);
+            KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
         }
         
-    /* If there are User APCs Pending and we are waiting in usermode, then we must notify the caller */
-    } else if ((CurrentThread->ApcState.UserApcPending) && (WaitMode == UserMode)) {
-            DPRINT1("APCs are Pending\n");
-            WaitStatus = STATUS_USER_APC;
+        /* 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) {
+            
+            DPRINT1("(%s:%d) Too many objects!\n", __FILE__, __LINE__);
+            KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
+        }
     }
-
-      /*
-       * Check if the wait is (already) satisfied
-       */
-      CountSignaled = 0;
-      Abandoned = FALSE;
-      for (i = 0; i < Count; i++)
-      {
-         hdr = (DISPATCHER_HEADER *) KiGetWaitableObjectFromObject(Object[i]);
-
-         if (KiIsObjectSignalled(hdr, CurrentThread))
-         {
-            CountSignaled++;
-
-            if (WaitType == WaitAny)
-            {
-               Abandoned = KiSideEffectsBeforeWake(hdr, CurrentThread) ? TRUE : Abandoned;
-
-               KeReleaseDispatcherDatabaseLock(OldIrql);               
-               
-               if (Timeout != NULL && Timeout->QuadPart != 0)
-               {
-                  KeCancelTimer(&CurrentThread->Timer);
-               }
-
-               DPRINT("One object is (already) signaled!\n");
-               if (Abandoned == TRUE)
-               {
-                  return (STATUS_ABANDONED_WAIT_0 + i);
-               }
-
-               return (STATUS_WAIT_0 + i);
+    
+    /* 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];
+            
+            /* FIXME: 
+             * Temporary hack until my Object Manager re-write. Basically some objects, like
+             * the File Object, but also LPCs and others, are actually waitable on their event.
+             * The Object Manager sets this up in The ObjectTypeInformation->DefaultObject member,
+             * by using pretty much the same kind of hack as us. Normal objects point to themselves
+             * in that pointer. Then, NtWaitForXXX will populate the WaitList that gets sent to us by
+             * using ->DefaultObject, so the proper actual objects will be sent to us. Until then however,
+             * I will keep this hack here, since there's no need to make an interim hack until the rewrite
+             * -- Alex Ionescu 24/02/05
+             */
+            if (CurrentObject->Type == IO_TYPE_FILE) {
+                   
+                DPRINT1("Hack used: %x\n", &((PFILE_OBJECT)CurrentObject)->Event);
+                CurrentObject = (PDISPATCHER_HEADER)(&((PFILE_OBJECT)CurrentObject)->Event);
             }
-         }
-      }
-
-      Abandoned = FALSE;
-      if ((WaitType == WaitAll) && (CountSignaled == Count))
-      {
-         for (i = 0; i < Count; i++)
-         {
-            hdr = (DISPATCHER_HEADER *) KiGetWaitableObjectFromObject(Object[i]);
-            Abandoned = KiSideEffectsBeforeWake(hdr, CurrentThread) ? TRUE : Abandoned;
-         }
 
-         KeReleaseDispatcherDatabaseLock(OldIrql);
-         
-         if (Timeout != NULL && Timeout->QuadPart != 0)
-         {
-            KeCancelTimer(&CurrentThread->Timer);
-         }
-
-         DPRINT("All objects are (already) signaled!\n");
-
-         if (Abandoned == TRUE)
-         {
-            return (STATUS_ABANDONED_WAIT_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 != MINLONG) {
+                        
+                        /* It has a normal signal state, so unwait it and return */
+                        KiSatisfyObjectWait(CurrentObject, CurrentThread);
+                        Status = STATUS_WAIT_0 | WaitIndex;
+                        goto WaitDone;
+                        
+                    } else {
+                        
+                        /* Is this a Mutant? */
+                        if (CurrentObject->Type == MutantObject) {
+                            
+                            /* According to wasm.ru, we must raise this exception (tested and true) */
+                            KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+                            ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);                    
+                        } 
+                    }
+                }
+                
+            } else {
+                    
+                /* One of the objects isn't signaled... if this is a WaitAll, we will fail later */
+                AllObjectsSignaled = FALSE;
+            }
 
-         return (STATUS_WAIT_0);
-      }
+            /* 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 = NULL;
+            
+        /* 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 WaitDone;
+        }
+   
+        /* Make sure we can satisfy the Alertable request */
+        KiCheckAlertability(Alertable, CurrentThread, WaitMode, &Status);
+    
+        /* 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 WaitDone;
+            }
+            
+            /* Point to Timer Wait Block and Thread Timer */
+            TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK];
+            ThreadTimer = &CurrentThread->Timer;
 
-      //zero timeout is used for testing if the object(s) can be immediately acquired
-      if (Timeout != NULL && Timeout->QuadPart == 0)
-      {
-         KeReleaseDispatcherDatabaseLock(OldIrql);
-         return STATUS_TIMEOUT;
-      }
+            /* 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 = NULL;
+            
+            /* Link the timer to this Wait Block */
+            InitializeListHead(&ThreadTimer->Header.WaitListHead);
 
-      /*
-       * Check if we have already timed out
-       */
-      if (Timeout != NULL && KiIsObjectSignalled(&CurrentThread->Timer.Header, CurrentThread))
-      {
-         KiSideEffectsBeforeWake(&CurrentThread->Timer.Header, CurrentThread);
-         KeReleaseDispatcherDatabaseLock(OldIrql);
-         KeCancelTimer(&CurrentThread->Timer);
-         return (STATUS_TIMEOUT);
-      }
+            /* Insert the Timer into the Timer Lists and enable it */
+            if (!KiInsertTimer(ThreadTimer, *Timeout)) {    
 
-      /* Append wait block to the KTHREAD wait block list */
-      CurrentThread->WaitBlockList = blk = WaitBlockArray;
+                /* Return a timeout if we couldn't insert the timer for some reason */
+                Status = STATUS_TIMEOUT;
+                goto WaitDone;
+            }
+        }
 
-      /*
-       * Set up the wait
-       */
-      CurrentThread->WaitStatus = WaitStatus;;
+        /* Insert into Object's Wait List*/
+        WaitBlock = CurrentThread->WaitBlockList;
+        while (WaitBlock) {
+            
+            /* 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;
+        }
+        
+        /* Handle Kernel Queues */
+        if (CurrentThread->Queue) {
+                 
+            DPRINT("Waking Queue\n");
+            KiWakeQueue(CurrentThread->Queue);
+        }
 
-      for (i = 0; i < Count; i++)
-      {
-         hdr = (DISPATCHER_HEADER *) KiGetWaitableObjectFromObject(Object[i]);
+        /* Block the Thread */
+        DPRINT("Blocking the Thread: %d, %d, %d, %x\n", Alertable, WaitMode, WaitReason, KeGetCurrentThread());
+        PsBlockThread(&Status, 
+                      Alertable, 
+                      WaitMode,
+                      (UCHAR)WaitReason);
+    
+        /* Check if we were executing an APC */
+        if (Status != STATUS_KERNEL_APC) {
+           
+            /* Return Status */
+            return Status;
+        }
+        
+        DPRINT("Looping Again\n");
+        CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
+    
+    } while (TRUE);
+    
+WaitDone:
+    /* Release the Lock, we are done */
+    DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n", KeGetCurrentThread(), Status);
+    KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+    return Status;
+}
 
-         blk->Object = KiGetWaitableObjectFromObject(Object[i]);
-         blk->Thread = CurrentThread;
-         blk->WaitKey = (USHORT)(STATUS_WAIT_0 + i);
-         blk->WaitType = (USHORT)WaitType;
+VOID
+FASTCALL
+KiSatisfyObjectWait(PDISPATCHER_HEADER Object,
+                    PKTHREAD Thread)
 
-         if (i == (Count - 1))
-         {
-            if (Timeout != NULL)
-            {
-               blk->NextWaitBlock = &CurrentThread->WaitBlock[3];
-            }
-            else
-            {
-               blk->NextWaitBlock = NULL;
+{
+    /* 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) {
+        
+            /* Set the Owner Thread */
+            ((PKMUTANT)Object)->OwnerThread = Thread;
+            
+            /* Disable APCs if needed */
+            Thread->KernelApcDisable -= ((PKMUTANT)Object)->ApcDisable;
+            
+            /* Check if it's abandoned */
+            if (((PKMUTANT)Object)->Abandoned) {
+            
+                /* Unabandon it */
+                ((PKMUTANT)Object)->Abandoned = FALSE;
+                
+                /* Return Status */
+                Thread->WaitStatus = STATUS_ABANDONED;
             }
-         }
-         else
-         {
-            blk->NextWaitBlock = blk + 1;
-         }
-
-         /*
-          * add wait block to disp. obj. wait list
-          * Use FIFO for all waits except for queues which use LIFO
-          */
-         if (WaitReason == WrQueue)
-         {
-            InsertHeadList(&hdr->WaitListHead, &blk->WaitListEntry);
-         }
-         else
-         {
-            InsertTailList(&hdr->WaitListHead, &blk->WaitListEntry);
-         }
-
-         blk = blk->NextWaitBlock;
-      }
+            
+            /* 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) {
 
-      if (Timeout != NULL)
-      {
-         CurrentThread->WaitBlock[3].Object = (PVOID) & CurrentThread->Timer;
-         CurrentThread->WaitBlock[3].Thread = CurrentThread;
-         CurrentThread->WaitBlock[3].WaitKey = STATUS_TIMEOUT;
-         CurrentThread->WaitBlock[3].WaitType = WaitAny;
-         CurrentThread->WaitBlock[3].NextWaitBlock = NULL;
+        /* These ones can have multiple signalings, so we only decrease it */
+        Object->SignalState--;
+    } 
+}
 
-         InsertTailList(&CurrentThread->Timer.Header.WaitListHead,
-                        &CurrentThread->WaitBlock[3].WaitListEntry);
-      }
+VOID
+FASTCALL
+KiWaitTest(PDISPATCHER_HEADER Object,
+           KPRIORITY Increment)
+{
+    PLIST_ENTRY WaitEntry;
+    PLIST_ENTRY WaitList;
+    PKWAIT_BLOCK CurrentWaitBlock;
+    PKWAIT_BLOCK NextWaitBlock;
+    
+    /* 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);
+        
+        /* 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, CurrentWaitBlock->Thread);
+        
+        } 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) {
+            
+                /* Check if the object is signaled */
+                if (!KiIsObjectSignaled(Object, CurrentWaitBlock->Thread)) {
+                
+                    /* It's not, move to the next one */
+                    DPRINT1("One of the object is non-signaled, sorry.\n");
+                    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(CurrentWaitBlock->Thread, CurrentWaitBlock->WaitKey);
 
-      //kernel queues
-      if (CurrentThread->Queue && WaitReason != WrQueue)
-      {
-         DPRINT("queue: sleep on something else\n");
-         CurrentThread->Queue->CurrentCount--;  
-         
-         //wake another thread
-         if (CurrentThread->Queue->CurrentCount < CurrentThread->Queue->MaximumCount &&
-             !IsListEmpty(&CurrentThread->Queue->EntryListHead))
-         {
-            KiDispatcherObjectWake(&CurrentThread->Queue->Header, IO_NO_INCREMENT);
-         }
-      }
+SkipUnwait:
+        /* Next entry */
+        WaitEntry = WaitEntry->Flink;
+    }
+    
+    DPRINT("Done\n");
+}               
 
-      PsBlockThread(&Status, Alertable, WaitMode, TRUE, OldIrql, (UCHAR)WaitReason);
+/* Must be called with the dispatcher lock held */
+VOID
+FASTCALL 
+KiAbortWaitThread(PKTHREAD Thread, 
+                  NTSTATUS WaitStatus)
+{
+    PKWAIT_BLOCK WaitBlock;
 
-      //kernel queues
-      OldIrql = KeAcquireDispatcherDatabaseLock ();
-      if (CurrentThread->Queue && WaitReason != WrQueue)
-      {
-         DPRINT("queue: wake from something else\n");
-         CurrentThread->Queue->CurrentCount++;
-      }
-      if (Status == STATUS_KERNEL_APC)
-      {
-         CurrentThread->WaitNext = TRUE;
-         CurrentThread->WaitIrql = OldIrql;
-      }
-      else
-      {
-         KeReleaseDispatcherDatabaseLock(OldIrql);
-      }
-      
-   } while (Status == STATUS_KERNEL_APC);
-   
+    /* 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 == THREAD_STATE_BLOCKED) == (Thread->WaitBlockList != NULL));
 
-   if (Timeout != NULL)
-   {
-      KeCancelTimer(&CurrentThread->Timer);
-   }
+    /* Remove the Wait Blocks from the list */
+    DPRINT("Removing waits\n");
+    WaitBlock = Thread->WaitBlockList;
+    while (WaitBlock) {
+        
+        /* Remove it */
+        DPRINT("Removing Waitblock: %x, %x\n", WaitBlock, WaitBlock->NextWaitBlock);
+        RemoveEntryList(&WaitBlock->WaitListEntry);
+        
+        /* Go to the next one */
+        WaitBlock = WaitBlock->NextWaitBlock;
+    };
+    
+    /* 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++;
+    }
 
-   DPRINT("Returning from KeWaitForMultipleObjects()\n");
-   return (Status);
+    /* Reschedule the Thread */
+    DPRINT("Unblocking the Thread\n");
+    PsUnblockThread((PETHREAD)Thread, &WaitStatus, 0);
 }
 
-VOID KeInitializeDispatcher(VOID)
+BOOLEAN
+inline
+FASTCALL
+KiIsObjectSignaled(PDISPATCHER_HEADER Object,
+                   PKTHREAD Thread)
 {
-   KeInitializeSpinLock(&DispatcherDatabaseLock);
+    /* 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 {
+            
+            /* Unsignaled Mutant */
+            return (FALSE);
+        }
+    }
+    
+    /* Any other object is not a mutated freak, so let's use logic */
+   return (!Object->SignalState <= 0);
 }
 
-NTSTATUS STDCALL
-NtWaitForMultipleObjects(IN ULONG ObjectCount,
-                        IN PHANDLE ObjectsArray,
-                        IN WAIT_TYPE WaitType,
-                        IN BOOLEAN Alertable,
-                        IN PLARGE_INTEGER TimeOut  OPTIONAL)
+BOOL
+inline
+FASTCALL
+KiIsObjectWaitable(PVOID Object)
 {
-   KWAIT_BLOCK WaitBlockArray[MAXIMUM_WAIT_OBJECTS];
-   HANDLE SafeObjectsArray[MAXIMUM_WAIT_OBJECTS];
-   PVOID ObjectPtrArray[MAXIMUM_WAIT_OBJECTS];
-   ULONG i, j;
-   KPROCESSOR_MODE PreviousMode;
-   LARGE_INTEGER SafeTimeOut;
-   NTSTATUS Status = STATUS_SUCCESS;
-
-   DPRINT("NtWaitForMultipleObjects(ObjectCount %lu ObjectsArray[] %x, Alertable %d, "
-         "TimeOut %x)\n", ObjectCount,ObjectsArray,Alertable,TimeOut);
-
-   PreviousMode = ExGetPreviousMode();
-
-   if (ObjectCount > MAXIMUM_WAIT_OBJECTS)
-     return STATUS_UNSUCCESSFUL;
-   if (0 == ObjectCount)
-     return STATUS_INVALID_PARAMETER;
-
-   if(PreviousMode != KernelMode)
-   {
-     _SEH_TRY
-     {
-       ProbeForRead(ObjectsArray,
-                    ObjectCount * sizeof(ObjectsArray[0]),
-                    sizeof(ULONG));
-       /* make a copy so we don't have to guard with SEH later and keep track of
-          what objects we referenced in case dereferencing pointers suddenly fails */
-       RtlCopyMemory(SafeObjectsArray, ObjectsArray, ObjectCount * sizeof(ObjectsArray[0]));
-       ObjectsArray = SafeObjectsArray;
-       
-       if(TimeOut != NULL)
-       {
-         ProbeForRead(TimeOut,
-                      sizeof(LARGE_INTEGER),
-                      sizeof(ULONG));
-         /* make a local copy of the timeout on the stack */
-         SafeTimeOut = *TimeOut;
-         TimeOut = &SafeTimeOut;
-       }
-     }
-     _SEH_HANDLE
-     {
-       Status = _SEH_GetExceptionCode();
-     }
-     _SEH_END;
-     
-     if(!NT_SUCCESS(Status))
-     {
-       return Status;
-     }
-   }
-
-   /* reference all objects */
-   for (i = 0; i < ObjectCount; i++)
-     {
-        Status = ObReferenceObjectByHandle(ObjectsArray[i],
-                                           SYNCHRONIZE,
-                                           NULL,
-                                           PreviousMode,
-                                           &ObjectPtrArray[i],
-                                           NULL);
-        if (!NT_SUCCESS(Status) || !KiIsObjectWaitable(ObjectPtrArray[i]))
-          {
-             if (NT_SUCCESS(Status))
-              {
-                DPRINT1("Waiting for object type '%wZ' is not supported\n", 
-                        &BODY_TO_HEADER(ObjectPtrArray[i])->ObjectType->TypeName);
-                Status = STATUS_HANDLE_NOT_WAITABLE;
-                i++;
-              }
-             /* dereference all referenced objects */
-             for (j = 0; j < i; j++)
-               {
-                  ObDereferenceObject(ObjectPtrArray[j]);
-               }
-
-             return(Status);
-          }
-     }
-
-   Status = KeWaitForMultipleObjects(ObjectCount,
-                                     ObjectPtrArray,
-                                     WaitType,
-                                     UserRequest,
-                                     PreviousMode,
-                                     Alertable,
-                                    TimeOut,
-                                     WaitBlockArray);
-
-   /* dereference all objects */
-   for (i = 0; i < ObjectCount; i++)
-     {
-        ObDereferenceObject(ObjectPtrArray[i]);
-     }
-
-   return(Status);
+    POBJECT_HEADER Header;
+    Header = BODY_TO_HEADER(Object);
+    
+    if (Header->ObjectType == ExEventObjectType ||
+        Header->ObjectType == ExIoCompletionType ||
+        Header->ObjectType == ExMutantObjectType ||
+        Header->ObjectType == ExSemaphoreObjectType ||
+        Header->ObjectType == ExTimerType ||
+        Header->ObjectType == PsProcessType ||
+        Header->ObjectType == PsThreadType ||
+        Header->ObjectType == IoFileObjectType) {
+        
+        return TRUE;
+    
+    } else {
+        
+        return FALSE;
+    }
 }
 
-
-/*
- * @implemented
- */
-NTSTATUS STDCALL
-NtWaitForSingleObject(IN HANDLE ObjectHandle,
-                     IN BOOLEAN Alertable,
-                     IN PLARGE_INTEGER TimeOut  OPTIONAL)
+VOID
+inline
+FASTCALL
+KiSatisifyMultipleObjectWaits(PKWAIT_BLOCK WaitBlock)
 {
-   PVOID ObjectPtr;
-   KPROCESSOR_MODE PreviousMode;
-   LARGE_INTEGER SafeTimeOut;
-   NTSTATUS Status = STATUS_SUCCESS;
-
-   DPRINT("NtWaitForSingleObject(ObjectHandle %x, Alertable %d, TimeOut %x)\n",
-         ObjectHandle,Alertable,TimeOut);
-
-   PreviousMode = ExGetPreviousMode();
-   
-   if(TimeOut != NULL && PreviousMode != KernelMode)
-   {
-     _SEH_TRY
-     {
-       ProbeForRead(TimeOut,
-                    sizeof(LARGE_INTEGER),
-                    sizeof(ULONG));
-       /* make a copy on the stack */
-       SafeTimeOut = *TimeOut;
-       TimeOut = &SafeTimeOut;
-     }
-     _SEH_HANDLE
-     {
-       Status = _SEH_GetExceptionCode();
-     }
-     _SEH_END;
-     
-     if(!NT_SUCCESS(Status))
-     {
-       return Status;
-     }
-   }
-
-   Status = ObReferenceObjectByHandle(ObjectHandle,
-                                     SYNCHRONIZE,
-                                     NULL,
-                                     PreviousMode,
-                                     &ObjectPtr,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-   if (!KiIsObjectWaitable(ObjectPtr))
-     {
-       DPRINT1("Waiting for object type '%wZ' is not supported\n", 
-              &BODY_TO_HEADER(ObjectPtr)->ObjectType->TypeName);
-       Status = STATUS_HANDLE_NOT_WAITABLE;
-     }
-   else
-     {
-       Status = KeWaitForSingleObject(ObjectPtr,
-                                     UserRequest,
-                                     PreviousMode,
-                                     Alertable,
-                                     TimeOut);
-     }
-
-   ObDereferenceObject(ObjectPtr);
-
-   return(Status);
+    PKTHREAD WaitThread = WaitBlock->Thread;
+    
+    /* Loop through all the Wait Blocks, and wake each Object */
+    while (WaitBlock) {
+         
+        /* Wake the Object */
+        KiSatisfyObjectWait(WaitBlock->Object, WaitThread);
+        WaitBlock = WaitBlock->NextWaitBlock;
+    }      
 }
 
-
-NTSTATUS STDCALL
-NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal,
-                              IN HANDLE WaitableObjectHandle,
-                              IN BOOLEAN Alertable,
-                              IN PLARGE_INTEGER TimeOut  OPTIONAL)
+VOID
+inline
+FASTCALL
+KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header,
+                             ULONG Type,
+                             ULONG Size,
+                             ULONG SignalState)
 {
-   KPROCESSOR_MODE PreviousMode;
-   DISPATCHER_HEADER* hdr;
-   PVOID SignalObj;
-   PVOID WaitObj;
-   LARGE_INTEGER SafeTimeOut;
-   NTSTATUS Status = STATUS_SUCCESS;
-
-   PreviousMode = ExGetPreviousMode();
-   
-   if(TimeOut != NULL && PreviousMode != KernelMode)
-   {
-     _SEH_TRY
-     {
-       ProbeForRead(TimeOut,
-                    sizeof(LARGE_INTEGER),
-                    sizeof(ULONG));
-       /* make a copy on the stack */
-       SafeTimeOut = *TimeOut;
-       TimeOut = &SafeTimeOut;
-     }
-     _SEH_HANDLE
-     {
-       Status = _SEH_GetExceptionCode();
-     }
-     _SEH_END;
-     
-     if(!NT_SUCCESS(Status))
-     {
-       return Status;
-     }
-   }
-   
-   Status = ObReferenceObjectByHandle(ObjectHandleToSignal,
-                                     0,
-                                     NULL,
-                                     PreviousMode,
-                                     &SignalObj,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       return Status;
-     }
-
-   Status = ObReferenceObjectByHandle(WaitableObjectHandle,
-                                     SYNCHRONIZE,
-                                     NULL,
-                                     PreviousMode,
-                                     &WaitObj,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       ObDereferenceObject(SignalObj);
-       return Status;
-     }
-
-   hdr = (DISPATCHER_HEADER *)SignalObj;
-   switch (hdr->Type)
-     {
-      case EventNotificationObject:
-      case EventSynchronizationObject:
-       KeSetEvent(SignalObj,
-                  EVENT_INCREMENT,
-                  TRUE);
-       break;
+    Header->Type = (UCHAR)Type;
+    Header->Absolute = 0;
+    Header->Inserted = 0;
+    Header->Size = (UCHAR)Size;
+    Header->SignalState = SignalState;
+    InitializeListHead(&(Header->WaitListHead));
+}
 
-      case MutantObject:
-       KeReleaseMutex(SignalObj,
-                      TRUE);
-       break;
+KIRQL
+inline
+FASTCALL
+KeAcquireDispatcherDatabaseLock(VOID)
+{
+    KIRQL OldIrql;
 
-      case SemaphoreObject:
-       KeReleaseSemaphore(SignalObj,
-                          SEMAPHORE_INCREMENT,
-                          1,
-                          TRUE);
-       break;
+    KeAcquireSpinLock (&DispatcherDatabaseLock, &OldIrql);
+    return OldIrql;
+}
 
-      default:
-       ObDereferenceObject(SignalObj);
-       ObDereferenceObject(WaitObj);
-       return STATUS_OBJECT_TYPE_MISMATCH;
-     }
+VOID
+inline
+FASTCALL
+KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID)
+{
+    KeAcquireSpinLockAtDpcLevel (&DispatcherDatabaseLock);
+}
 
-   Status = KeWaitForSingleObject(WaitObj,
-                                 UserRequest,
-                                 PreviousMode,
-                                 Alertable,
-                                 TimeOut);
+VOID 
+inline
+FASTCALL
+KeInitializeDispatcher(VOID)
+{
+    /* Initialize the Dispatcher Lock */
+    KeInitializeSpinLock(&DispatcherDatabaseLock);
+}
 
-   ObDereferenceObject(SignalObj);
-   ObDereferenceObject(WaitObj);
+VOID
+inline
+FASTCALL
+KeReleaseDispatcherDatabaseLock(KIRQL OldIrql)
+{
+    /* If it's the idle thread, dispatch */
+    if (!KeIsExecutingDpc() && OldIrql < DISPATCH_LEVEL && KeGetCurrentThread() != NULL && 
+        KeGetCurrentThread() == KeGetCurrentPrcb()->IdleThread) {
+        
+        PsDispatchThreadNoLock(THREAD_STATE_READY);
+        KeLowerIrql(OldIrql);
+        
+    } else {
+        
+        /* Just release the spin lock */
+        KeReleaseSpinLock(&DispatcherDatabaseLock, OldIrql);
+    }
+}
 
-   return Status;
+VOID
+inline
+FASTCALL
+KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID)
+{
+    KeReleaseSpinLockFromDpcLevel(&DispatcherDatabaseLock);
 }
+
+/* EOF */
index 956d20c..48dccb9 100644 (file)
@@ -511,7 +511,7 @@ Ke386IoSetAccessProcess@8
 Ke386QueryIoAccessMap@8
 Ke386SetIoAccessMap@8
 KeAcquireSpinLockAtDpcLevel@4
-KeAcquireDispatcherDatabaseLockAtDpcLevel
+@KeAcquireDispatcherDatabaseLockAtDpcLevel@0
 @KeAcquireInStackQueuedSpinLockAtDpcLevel@8
 KeAcquireInterruptSpinLock@4
 KeAddSystemServiceTable@20
@@ -592,7 +592,7 @@ KeReadStateSemaphore@4
 KeReadStateTimer@4
 KeRegisterBugCheckCallback@20
 KeRegisterBugCheckReasonCallback@16
-KeReleaseDispatcherDatabaseLockFromDpcLevel
+@KeReleaseDispatcherDatabaseLockFromDpcLevel@0
 @KeReleaseInStackQueuedSpinLockFromDpcLevel@4
 KeReleaseInterruptSpinLock@8
 KeReleaseMutant@16
index 73c8d44..350a533 100644 (file)
@@ -207,7 +207,7 @@ PsTerminateCurrentThread(NTSTATUS ExitStatus)
 
    oldIrql = KeAcquireDispatcherDatabaseLock();
    CurrentThread->Tcb.DispatcherHeader.SignalState = TRUE;
-   KiDispatcherObjectWake(&CurrentThread->Tcb.DispatcherHeader, IO_NO_INCREMENT);
+   KiWaitTest(&CurrentThread->Tcb.DispatcherHeader, IO_NO_INCREMENT);
    KeReleaseDispatcherDatabaseLock (oldIrql);
 
    /* The last thread shall close the door on exit */
@@ -227,9 +227,7 @@ PsTerminateCurrentThread(NTSTATUS ExitStatus)
 #ifdef _ENABLE_THRDEVTPAIR
    ExpSwapThreadEventPair(CurrentThread, NULL); /* Release the associated eventpair object, if there was one */
 #endif /* _ENABLE_THRDEVTPAIR */
-
-   ASSERT(CurrentThread->Tcb.WaitBlockList == NULL);
-   
    PsDispatchThreadNoLock(THREAD_STATE_TERMINATED_1);
    DPRINT1("Unexpected return, CurrentThread %x PsGetCurrentThread() %x\n", CurrentThread, PsGetCurrentThread());
    KEBUGCHECK(0);
@@ -342,7 +340,7 @@ PiTerminateProcess(PEPROCESS Process,
    }
    OldIrql = KeAcquireDispatcherDatabaseLock ();
    Process->Pcb.DispatcherHeader.SignalState = TRUE;
-   KiDispatcherObjectWake(&Process->Pcb.DispatcherHeader, IO_NO_INCREMENT);
+   KiWaitTest(&Process->Pcb.DispatcherHeader, IO_NO_INCREMENT);
    KeReleaseDispatcherDatabaseLock (OldIrql);
    ObDereferenceObject(Process);
    return(STATUS_SUCCESS);
index 41fbd07..c8f8063 100644 (file)
@@ -545,49 +545,46 @@ PsUnblockThread(PETHREAD Thread, PNTSTATUS WaitStatus, KPRIORITY Increment)
 }
 
 VOID
-PsBlockThread(PNTSTATUS Status, UCHAR Alertable, ULONG WaitMode,
-             BOOLEAN DispatcherLock, KIRQL WaitIrql, UCHAR WaitReason)
+STDCALL
+PsBlockThread(PNTSTATUS Status, 
+              UCHAR Alertable, 
+              ULONG WaitMode,
+              UCHAR WaitReason)
 {
-  KIRQL oldIrql;
-  PKTHREAD KThread;
-  PETHREAD Thread;
-  PKWAIT_BLOCK WaitBlock;
-
-  if (!DispatcherLock)
-    {
-      oldIrql = KeAcquireDispatcherDatabaseLock();
-    }
-
-  KThread = KeGetCurrentThread();
-  Thread = CONTAINING_RECORD (KThread, ETHREAD, Tcb);
-  if (KThread->ApcState.KernelApcPending)
-  {
-    WaitBlock = (PKWAIT_BLOCK)Thread->Tcb.WaitBlockList;
-    while (WaitBlock)
-      {
-       RemoveEntryList (&WaitBlock->WaitListEntry);
-       WaitBlock = WaitBlock->NextWaitBlock;
-      }
-    Thread->Tcb.WaitBlockList = NULL;
-    PsDispatchThreadNoLock (THREAD_STATE_READY);
-    if (Status != NULL)
-      {
-       *Status = STATUS_KERNEL_APC;
-      }
-  }
-  else
-    {
-      Thread->Tcb.Alertable = Alertable;
-      Thread->Tcb.WaitMode = (UCHAR)WaitMode;
-      Thread->Tcb.WaitReason = WaitReason;
-      PsDispatchThreadNoLock(THREAD_STATE_BLOCKED);
-
-      if (Status != NULL)
-       {
-         *Status = Thread->Tcb.WaitStatus;
-       }
+    PKTHREAD Thread = KeGetCurrentThread();
+    PKWAIT_BLOCK WaitBlock;
+
+    if (Thread->ApcState.KernelApcPending) {
+    
+        DPRINT("Dispatching Thread as ready (APC!)\n");
+        
+        /* Remove Waits */
+        WaitBlock = Thread->WaitBlockList;
+        while (WaitBlock) {
+            RemoveEntryList (&WaitBlock->WaitListEntry);
+            WaitBlock = WaitBlock->NextWaitBlock;
+        }
+        Thread->WaitBlockList = NULL;
+        
+        /* Dispatch it and return status */
+        PsDispatchThreadNoLock (THREAD_STATE_READY);
+        if (Status != NULL) *Status = STATUS_KERNEL_APC;
+
+    } else {
+
+        /* Set the Thread Data as Requested */
+        DPRINT("Dispatching Thread as blocked\n");
+        Thread->Alertable = Alertable;
+        Thread->WaitMode = (UCHAR)WaitMode;
+        Thread->WaitReason = WaitReason;
+        
+        /* Dispatch it and return status */
+        PsDispatchThreadNoLock(THREAD_STATE_BLOCKED);
+        if (Status != NULL) *Status = Thread->WaitStatus;
     }
-  KeLowerIrql(WaitIrql);
+    
+    DPRINT("Releasing Dispatcher Lock\n");
+    KfLowerIrql(Thread->WaitIrql);
 }
 
 VOID