[ros-diffs] [ion] 25605: - Convert KxDelayThreadWait, KxSingleThreadWait, KxMultiThreadWait into macros. - Add KxQueueThreadWait macro based on previous ones. - Add KxSetTimerForThreadWait to initialize the timer during the macros above. Wait timer setup is now done in two phases, which will be required with the new timer code anyway. - Remove IRQL hack from idle loop when delivering DPCs. - Make the wait code use the new macros and make it scale better. - Add some missing definitions to asm.h

ion at svn.reactos.org ion at svn.reactos.org
Tue Jan 23 19:39:48 CET 2007


Author: ion
Date: Tue Jan 23 21:39:47 2007
New Revision: 25605

URL: http://svn.reactos.org/svn/reactos?rev=25605&view=rev
Log:
- Convert KxDelayThreadWait, KxSingleThreadWait, KxMultiThreadWait into macros.
- Add KxQueueThreadWait macro based on previous ones.
- Add KxSetTimerForThreadWait to initialize the timer during the macros above. Wait timer setup is now done in two phases, which will be required with the new timer code anyway.
- Remove IRQL hack from idle loop when delivering DPCs.
- Make the wait code use the new macros and make it scale better.
- Add some missing definitions to asm.h

Modified:
    trunk/reactos/include/ndk/asm.h
    trunk/reactos/ntoskrnl/include/internal/ke_x.h
    trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S
    trunk/reactos/ntoskrnl/ke/queue.c
    trunk/reactos/ntoskrnl/ke/wait.c

Modified: trunk/reactos/include/ndk/asm.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/include/ndk/asm.h?rev=25605&r1=25604&r2=25605&view=diff
==============================================================================
--- trunk/reactos/include/ndk/asm.h (original)
+++ trunk/reactos/include/ndk/asm.h Tue Jan 23 21:39:47 2007
@@ -19,6 +19,8 @@
 
 #ifndef _ASM_H
 #define _ASM_H
+
+//#define NEW_SCHEDULER
 
 //
 // PCR Access
@@ -138,6 +140,16 @@
 #define EPROCESS_VDM_OBJECTS                    0x144
 
 //
+// KTIMER_TABLE Offsets
+//
+#ifdef __ASM__
+#define KTIMER_TABLE_ENTRY                      0x00
+#define KTIMER_TABLE_TIME                       0x08
+#define TIMER_ENTRY_SIZE                        0x10
+#define TIMER_TABLE_SIZE                        0x200
+#endif
+
+//
 // KPRCB Offsets
 //
 #define KPRCB_DR0                               0x2F8
@@ -146,6 +158,8 @@
 #define KPRCB_DR3                               0x304
 #define KPRCB_DR6                               0x308
 #define KPRCB_DR7                               0x20C
+#define KPRCB_TIMER_HAND                        0x964
+#define KPRCB_TIMER_REQUEST                     0x968
 
 //
 // KPCR Offsets

Modified: trunk/reactos/ntoskrnl/include/internal/ke_x.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/ke_x.h?rev=25605&r1=25604&r2=25605&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/ke_x.h (original)
+++ trunk/reactos/ntoskrnl/include/internal/ke_x.h Tue Jan 23 21:39:47 2007
@@ -373,126 +373,220 @@
     return STATUS_WAIT_0;
 }
 
-FORCEINLINE
-BOOLEAN
-KxDelayThreadWait(IN PKTHREAD Thread,
-                   IN BOOLEAN Alertable,
-                   IN KPROCESSOR_MODE WaitMode)
-{
-    BOOLEAN Swappable;
-    PKWAIT_BLOCK TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
-
-    /* Setup the Wait Block */
-    Thread->WaitBlockList = TimerBlock;
-    TimerBlock->NextWaitBlock = TimerBlock;
-
-    /* Link the timer to this Wait Block */
-    Thread->Timer.Header.WaitListHead.Flink = &TimerBlock->WaitListEntry;
-    Thread->Timer.Header.WaitListHead.Blink = &TimerBlock->WaitListEntry;
-
-    /* Clear wait status */
-    Thread->WaitStatus = STATUS_WAIT_0;
-
-    /* Setup wait fields */
-    Thread->Alertable = Alertable;
-    Thread->WaitReason = DelayExecution;
-    Thread->WaitMode = WaitMode;
-
-    /* Check if we can swap the thread's stack */
-    Thread->WaitListEntry.Flink = NULL;
-    Swappable = KiCheckThreadStackSwap(Thread, WaitMode);
-
-    /* Set the wait time */
-    Thread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart;
-    return Swappable;
-}
-
-FORCEINLINE
-BOOLEAN
-KxMultiThreadWait(IN PKTHREAD Thread,
-                  IN PKWAIT_BLOCK WaitBlock,
-                  IN BOOLEAN Alertable,
-                  IN KWAIT_REASON WaitReason,
-                  IN KPROCESSOR_MODE WaitMode)
-{
-    BOOLEAN Swappable;
-    PKTIMER ThreadTimer = &Thread->Timer;
-
-    /* Set default wait status */
-    Thread->WaitStatus = STATUS_WAIT_0;
-
-    /* Link wait block array to the thread */
-    Thread->WaitBlockList = WaitBlock;
-
-    /* Initialize the timer list */
-    InitializeListHead(&ThreadTimer->Header.WaitListHead);
-
-    /* Set wait settings */
-    Thread->Alertable = Alertable;
-    Thread->WaitMode = WaitMode;
-    Thread->WaitReason = WaitReason;
-
-    /* Check if we can swap the thread's stack */
-    Thread->WaitListEntry.Flink = NULL;
-    Swappable = KiCheckThreadStackSwap(Thread, WaitMode);
-
-    /* Set the wait time */
-    Thread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart;
-    return Swappable;
-}
-
-FORCEINLINE
-BOOLEAN
-KxSingleThreadWait(IN PKTHREAD Thread,
-                   IN PKWAIT_BLOCK WaitBlock,
-                   IN PVOID Object,
-                   IN PLARGE_INTEGER Timeout,
-                   IN BOOLEAN Alertable,
-                   IN KWAIT_REASON WaitReason,
-                   IN KPROCESSOR_MODE WaitMode)
-{
-    BOOLEAN Swappable;
-    PKWAIT_BLOCK TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
-
-    /* Setup the Wait Block */
-    Thread->WaitBlockList = WaitBlock;
-    WaitBlock->WaitKey = STATUS_WAIT_0;
-    WaitBlock->Object = Object;
-    WaitBlock->WaitType = WaitAny;
-
-    /* Clear wait status */
-    Thread->WaitStatus = STATUS_WAIT_0;
-
-    /* Check if we have a timer */
-    if (Timeout)
-    {
-        /* Pointer to timer block */
-        WaitBlock->NextWaitBlock = TimerBlock;
-        TimerBlock->NextWaitBlock = WaitBlock;
-
-        /* Link the timer to this Wait Block */
-        Thread->Timer.Header.WaitListHead.Flink = &TimerBlock->WaitListEntry;
-        Thread->Timer.Header.WaitListHead.Blink = &TimerBlock->WaitListEntry;
-    }
-    else
-    {
-        /* No timer block, just ourselves */
-        WaitBlock->NextWaitBlock = WaitBlock;
-    }
-
-    /* Setup wait fields */
-    Thread->Alertable = Alertable;
-    Thread->WaitReason = WaitReason;
-    Thread->WaitMode = WaitMode;
-
-    /* Check if we can swap the thread's stack */
-    Thread->WaitListEntry.Flink = NULL;
-    Swappable = KiCheckThreadStackSwap(Thread, WaitMode);
-
-    /* Set the wait time */
-    Thread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart;
-    return Swappable;
-}
+VOID
+FORCEINLINE
+KxSetTimerForThreadWait(IN PKTIMER Timer,
+                        IN LARGE_INTEGER Interval)
+{
+    LARGE_INTEGER InterruptTime, SystemTime, TimeDifference;
+
+    /* Check the timer's interval to see if it's absolute */
+    Timer->Header.Absolute = FALSE;
+    if (!Timer->Period) Timer->Header.SignalState = FALSE;
+    if (Interval.HighPart >= 0)
+    {
+        /* Get the system time and calculate the relative time */
+        KeQuerySystemTime(&SystemTime);
+        TimeDifference.QuadPart = SystemTime.QuadPart - Interval.QuadPart;
+        Timer->Header.Absolute = TRUE;
+
+        /* Check if we've already expired */
+        if (TimeDifference.HighPart >= 0)
+        {
+            /* Reset everything */
+            Timer->DueTime.QuadPart = 0;
+            Timer->Header.SignalState = TRUE;
+            return;
+        }
+        else
+        {
+            /* Update the interval */
+            Interval = TimeDifference;
+        }
+    }
+
+    /* Calculate the due time */
+    InterruptTime.QuadPart = KeQueryInterruptTime();
+    Timer->DueTime.QuadPart = InterruptTime.QuadPart - Interval.QuadPart;
+}
+
+#define KxDelayThreadWait()                                                 \
+                                                                            \
+    /* Setup the Wait Block */                                              \
+    Thread->WaitBlockList = TimerBlock;                                     \
+                                                                            \
+    /* Setup the timer */                                                   \
+    KxSetTimerForThreadWait(Timer, *Interval);                              \
+                                                                            \
+    /* Save the due time for the caller */                                  \
+    DueTime.QuadPart = Timer->DueTime.QuadPart;                             \
+                                                                            \
+    /* Link the timer to this Wait Block */                                 \
+    TimerBlock->NextWaitBlock = TimerBlock;                                 \
+    Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry;          \
+    Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry;          \
+                                                                            \
+    /* Clear wait status */                                                 \
+    Thread->WaitStatus = STATUS_SUCCESS;                                    \
+                                                                            \
+    /* Setup wait fields */                                                 \
+    Thread->Alertable = Alertable;                                          \
+    Thread->WaitReason = DelayExecution;                                    \
+    Thread->WaitMode = WaitMode;                                            \
+                                                                            \
+    /* Check if we can swap the thread's stack */                           \
+    Thread->WaitListEntry.Flink = NULL;                                     \
+    Swappable = KiCheckThreadStackSwap(Thread, WaitMode);                   \
+                                                                            \
+    /* Set the wait time */                                                 \
+    Thread->WaitTime = KeTickCount.LowPart;
+
+#define KxMultiThreadWait()                                                 \
+    /* Link wait block array to the thread */                               \
+    Thread->WaitBlockList = WaitBlockArray;                                 \
+                                                                            \
+    /* Reset the index */                                                   \
+    Index = 0;                                                              \
+                                                                            \
+    /* Loop wait blocks */                                                  \
+    do                                                                      \
+    {                                                                       \
+        /* Fill out the wait block */                                       \
+        WaitBlock = &WaitBlockArray[Index];                                 \
+        WaitBlock->Object = Object[Index];                                  \
+        WaitBlock->WaitKey = Index;                                         \
+        WaitBlock->WaitType = WaitType;                                     \
+        WaitBlock->Thread = Thread;                                         \
+                                                                            \
+        /* Link to next block */                                            \
+        WaitBlock->NextWaitBlock = &WaitBlockArray[Index + 1];              \
+        Index++;                                                            \
+    } while (Index < Count);                                                \
+                                                                            \
+    /* Link the last block */                                               \
+    WaitBlock->NextWaitBlock = WaitBlockArray;                              \
+                                                                            \
+    /* Set default wait status */                                           \
+    Thread->WaitStatus = STATUS_WAIT_0;                                     \
+                                                                            \
+    /* Check if we have a timer */                                          \
+    if (Timeout)                                                            \
+    {                                                                       \
+        /* Link to the block */                                             \
+        TimerBlock->NextWaitBlock = WaitBlockArray;                         \
+                                                                            \
+        /* Setup the timer */                                               \
+        KxSetTimerForThreadWait(Timer, *Timeout);                           \
+                                                                            \
+        /* Save the due time for the caller */                              \
+        DueTime.QuadPart = Timer->DueTime.QuadPart;                         \
+                                                                            \
+        /* Initialize the list */                                           \
+        InitializeListHead(&Timer->Header.WaitListHead);                    \
+    }                                                                       \
+                                                                            \
+    /* Set wait settings */                                                 \
+    Thread->Alertable = Alertable;                                          \
+    Thread->WaitMode = WaitMode;                                            \
+    Thread->WaitReason = WaitReason;                                        \
+                                                                            \
+    /* Check if we can swap the thread's stack */                           \
+    Thread->WaitListEntry.Flink = NULL;                                     \
+    Swappable = KiCheckThreadStackSwap(Thread, WaitMode);                   \
+                                                                            \
+    /* Set the wait time */                                                 \
+    Thread->WaitTime = KeTickCount.LowPart;
+
+#define KxSingleThreadWait()                                                \
+    /* Setup the Wait Block */                                              \
+    Thread->WaitBlockList = WaitBlock;                                      \
+    WaitBlock->WaitKey = STATUS_SUCCESS;                                    \
+    WaitBlock->Object = Object;                                             \
+    WaitBlock->WaitType = WaitAny;                                          \
+                                                                            \
+    /* Clear wait status */                                                 \
+    Thread->WaitStatus = STATUS_SUCCESS;                                    \
+                                                                            \
+    /* Check if we have a timer */                                          \
+    if (Timeout)                                                            \
+    {                                                                       \
+        /* Setup the timer */                                               \
+        KxSetTimerForThreadWait(Timer, *Timeout);                           \
+                                                                            \
+        /* Save the due time for the caller */                              \
+        DueTime.QuadPart = Timer->DueTime.QuadPart;                         \
+                                                                            \
+        /* Pointer to timer block */                                        \
+        WaitBlock->NextWaitBlock = TimerBlock;                              \
+        TimerBlock->NextWaitBlock = WaitBlock;                              \
+                                                                            \
+        /* Link the timer to this Wait Block */                             \
+        Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry;      \
+        Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry;      \
+    }                                                                       \
+    else                                                                    \
+    {                                                                       \
+        /* No timer block, just ourselves */                                \
+        WaitBlock->NextWaitBlock = WaitBlock;                               \
+    }                                                                       \
+                                                                            \
+    /* Set wait settings */                                                 \
+    Thread->Alertable = Alertable;                                          \
+    Thread->WaitMode = WaitMode;                                            \
+    Thread->WaitReason = WaitReason;                                        \
+                                                                            \
+    /* Check if we can swap the thread's stack */                           \
+    Thread->WaitListEntry.Flink = NULL;                                     \
+    Swappable = KiCheckThreadStackSwap(Thread, WaitMode);                   \
+                                                                            \
+    /* Set the wait time */                                                 \
+    Thread->WaitTime = KeTickCount.LowPart;
+
+#define KxQueueThreadWait()                                                 \
+    /* Setup the Wait Block */                                              \
+    Thread->WaitBlockList = WaitBlock;                                      \
+    WaitBlock->WaitKey = STATUS_SUCCESS;                                    \
+    WaitBlock->Object = Queue;                                              \
+    WaitBlock->WaitType = WaitAny;                                          \
+    WaitBlock->Thread = Thread;                                             \
+                                                                            \
+    /* Clear wait status */                                                 \
+    Thread->WaitStatus = STATUS_SUCCESS;                                    \
+                                                                            \
+    /* Check if we have a timer */                                          \
+    if (Timeout)                                                            \
+    {                                                                       \
+        /* Setup the timer */                                               \
+        KxSetTimerForThreadWait(Timer, *Timeout);                           \
+                                                                            \
+        /* Save the due time for the caller */                              \
+        DueTime.QuadPart = Timer->DueTime.QuadPart;                         \
+                                                                            \
+        /* Pointer to timer block */                                        \
+        WaitBlock->NextWaitBlock = TimerBlock;                              \
+        TimerBlock->NextWaitBlock = WaitBlock;                              \
+                                                                            \
+        /* Link the timer to this Wait Block */                             \
+        Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry;      \
+        Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry;      \
+    }                                                                       \
+    else                                                                    \
+    {                                                                       \
+        /* No timer block, just ourselves */                                \
+        WaitBlock->NextWaitBlock = WaitBlock;                               \
+    }                                                                       \
+                                                                            \
+    /* Set wait settings */                                                 \
+    Thread->Alertable = FALSE;                                              \
+    Thread->WaitMode = WaitMode;                                            \
+    Thread->WaitReason = WrQueue;                                           \
+                                                                            \
+    /* Check if we can swap the thread's stack */                           \
+    Thread->WaitListEntry.Flink = NULL;                                     \
+    Swappable = KiCheckThreadStackSwap(Thread, WaitMode);                   \
+                                                                            \
+    /* Set the wait time */                                                 \
+    Thread->WaitTime = KeTickCount.LowPart;
 
 //
 // Unwaits a Thread
@@ -772,6 +866,27 @@
     /* We deliver instantly on UP */
     UNREFERENCED_PARAMETER(NeedApc);
     UNREFERENCED_PARAMETER(Processor);
+}
+
+FORCEINLINE
+PKSPIN_LOCK_QUEUE
+KiAcquireTimerLock(IN ULONG Hand)
+{
+    ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
+
+    /* Nothing to do on UP */
+    UNREFERENCED_PARAMETER(Hand);
+    return NULL;
+}
+
+FORCEINLINE
+VOID
+KiReleaseTimerLock(IN PKSPIN_LOCK_QUEUE LockQueue)
+{
+    ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
+
+    /* Nothing to do on UP */
+    UNREFERENCED_PARAMETER(LockQueue);
 }
 
 #else
@@ -1350,3 +1465,19 @@
     /* Return the current mode */
     return KeGetCurrentThread()->PreviousMode;
 }
+
+VOID
+FORCEINLINE
+KiInsertWaitTimer(IN PKTIMER Timer)
+{
+    /* Set default data */
+    Timer->Header.Inserted = TRUE;
+    if (!Timer->Period) Timer->Header.SignalState = FALSE;
+
+    /* Now insert it into the Timer List */
+    InsertAscendingList(&KiTimerListHead,
+                        Timer,
+                        KTIMER,
+                        TimerListEntry,
+                        DueTime.QuadPart);
+}

Modified: trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S?rev=25605&r1=25604&r2=25605&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S (original)
+++ trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S Tue Jan 23 21:39:47 2007
@@ -677,18 +677,9 @@
 #endif
     jz CheckSchedule
 
-    /* Raise to DISPATCH_LEVEL */
-    mov ecx, DISPATCH_LEVEL
-    call @KfRaiseIrql at 4
-    mov edi, eax
-
     /* Handle the above */
     lea ecx, [ebx+KPCR_PRCB_DATA]
     call @KiRetireDpcList at 4
-
-    /* Lower IRQL */
-    mov ecx, edi
-    call @KfLowerIrql at 4
 
 CheckSchedule:
 #ifndef NEW_SCHEDULER

Modified: trunk/reactos/ntoskrnl/ke/queue.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/queue.c?rev=25605&r1=25604&r2=25605&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/ke/queue.c (original)
+++ trunk/reactos/ntoskrnl/ke/queue.c Tue Jan 23 21:39:47 2007
@@ -244,13 +244,13 @@
     PLIST_ENTRY QueueEntry;
     NTSTATUS Status;
     PKTHREAD Thread = KeGetCurrentThread();
-    KIRQL OldIrql;
     PKQUEUE PreviousQueue;
-    PKWAIT_BLOCK WaitBlock;
-    PKTIMER Timer;
+    PKWAIT_BLOCK WaitBlock = &Thread->WaitBlock[0];
+    PKWAIT_BLOCK TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
+    PKTIMER Timer = &Thread->Timer;
     BOOLEAN Swappable;
     PLARGE_INTEGER OriginalDueTime = Timeout;
-    LARGE_INTEGER DueTime, NewDueTime;
+    LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
     ASSERT_QUEUE(Queue);
     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
 
@@ -259,12 +259,14 @@
     {
         /* It is, so next time don't do expect this */
         Thread->WaitNext = FALSE;
+        KxQueueThreadWait();
     }
     else
     {
-        /* Lock the Dispatcher Database */
-        OldIrql = KiAcquireDispatcherLock();
-        Thread->WaitIrql = OldIrql;
+        /* Raise IRQL to synch, prepare the wait, then lock the database */
+        Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
+        KxQueueThreadWait();
+        KiAcquireDispatcherLockAtDpcLevel();
     }
 
     /*
@@ -314,7 +316,13 @@
             /* Check if the entry is valid. If not, bugcheck */
             if (!(QueueEntry->Flink) || !(QueueEntry->Blink))
             {
-                KEBUGCHECK(INVALID_WORK_QUEUE_ITEM);
+                /* Invalid item */
+                KeBugCheckEx(INVALID_WORK_QUEUE_ITEM,
+                             (ULONG_PTR)QueueEntry,
+                             (ULONG_PTR)Queue,
+                             (ULONG_PTR)NULL,
+                             (ULONG_PTR)((PWORK_QUEUE_ITEM)QueueEntry)->
+                                         WorkerRoutine);
             }
 
             /* Remove the Entry */
@@ -326,16 +334,14 @@
         }
         else
         {
-            /* Use the Thread's Wait Block, it's big enough */
-            Thread->WaitBlockList = &Thread->WaitBlock[0];
-
             /* Check if a kernel APC is pending and we're below APC_LEVEL */
             if ((Thread->ApcState.KernelApcPending) &&
                 !(Thread->SpecialApcDisable) && (Thread->WaitIrql < APC_LEVEL))
             {
                 /* Increment the count and unlock the dispatcher */
                 Queue->CurrentCount++;
-                KiReleaseDispatcherLock(Thread->WaitIrql);
+                KiReleaseDispatcherLockFromDpcLevel();
+                KiExitDispatcher(Thread->WaitIrql);
             }
             else
             {
@@ -349,94 +355,57 @@
                     break;
                 }
 
-                /* Build the Wait Block */
-                WaitBlock = &Thread->WaitBlock[0];
-                WaitBlock->Object = (PVOID)Queue;
-                WaitBlock->WaitKey = STATUS_SUCCESS;
-                WaitBlock->WaitType = WaitAny;
-                WaitBlock->Thread = Thread;
-                Thread->WaitStatus = STATUS_WAIT_0;
-
-                /* Check if we can swap the thread's stack */
-                Thread->WaitListEntry.Flink = NULL;
-                Swappable = KiCheckThreadStackSwap(Thread, WaitMode);
-
-                /* We need to wait for the object... check for a timeout */
+                /* Enable the Timeout Timer if there was any specified */
                 if (Timeout)
                 {
-                    /* Check if it's zero */
-                    if (!Timeout->QuadPart)
+                    /* Check if the timer expired */
+                    InterruptTime.QuadPart = KeQueryInterruptTime();
+                    if (InterruptTime.QuadPart >= Timer->DueTime.QuadPart)
                     {
-                        /* Don't wait. Return and increase pending threads */
+                        /* It did, so we don't need to wait */
                         QueueEntry = (PLIST_ENTRY)STATUS_TIMEOUT;
                         Queue->CurrentCount++;
                         break;
                     }
 
-                    /*
-                     * Set up the Timer. We'll use the internal function so
-                     * that we can hold on to the dispatcher lock.
-                     */
-                    Timer = &Thread->Timer;
-                    WaitBlock->NextWaitBlock = &Thread->WaitBlock[1];
-                    WaitBlock = &Thread->WaitBlock[1];
-
-                    /* Set up the Timer Wait Block */
-                    WaitBlock->Object = (PVOID)Timer;
-                    WaitBlock->Thread = Thread;
-                    WaitBlock->WaitKey = STATUS_TIMEOUT;
-                    WaitBlock->WaitType = WaitAny;
-
-                    /* Link the timer to this Wait Block */
-                    Timer->Header.WaitListHead.Flink =
-                        &WaitBlock->WaitListEntry;
-                    Timer->Header.WaitListHead.Blink =
-                        &WaitBlock->WaitListEntry;
-                    WaitBlock->WaitListEntry.Flink =
-                        &Timer->Header.WaitListHead;
-                    WaitBlock->WaitListEntry.Blink =
-                        &Timer->Header.WaitListHead;
-
-                    /* Create Timer */
-                    if (!KiInsertTimer(Timer, *Timeout))
-                    {
-                        /* FIXME */
-                        DPRINT1("If you see this message contact Alex ASAP\n");
-                        KEBUGCHECK(0);
-                    }
-
-                    /* Set timer due time */
-                    DueTime.QuadPart = Timer->DueTime.QuadPart;
+                    /* It didn't, so activate it */
+                    Timer->Header.Inserted = TRUE;
                 }
 
-                /* Close the loop */
-                WaitBlock->NextWaitBlock = &Thread->WaitBlock[0];
-
-                /* Insert the wait block into the Queues's wait list */
-                WaitBlock = &Thread->WaitBlock[0];
+                /* Insert the wait block in the list */
                 InsertTailList(&Queue->Header.WaitListHead,
                                &WaitBlock->WaitListEntry);
 
                 /* Setup the wait information */
-                Thread->WaitMode = WaitMode;
-                Thread->WaitReason = WrQueue;
-                Thread->Alertable = FALSE;
-                Thread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart;
                 Thread->State = Waiting;
 
-                /* Find a new thread to run */
+                /* Add the thread to the wait list */
                 KiAddThreadToWaitList(Thread, Swappable);
+
+                /* Activate thread swap */
+                ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
+                KiSetThreadSwapBusy(Thread);
+
+                /* Check if we have a timer */
+                if (Timeout)
+                {
+                    /* Insert it */
+                    KiInsertWaitTimer(Timer);
+                }
+                else
+                {
+                    /* Otherwise, unlock the dispatcher */
+                    KiReleaseDispatcherLockFromDpcLevel();
+                }
+
+                /* Do the actual swap */
                 Status = KiSwapThread(Thread, KeGetCurrentPrcb());
 
                 /* Reset the wait reason */
                 Thread->WaitReason = 0;
 
                 /* Check if we were executing an APC */
-                if (Status != STATUS_KERNEL_APC)
-                {
-                    /* Done Waiting  */
-                    return (PLIST_ENTRY)Status;
-                }
+                if (Status != STATUS_KERNEL_APC) return (PLIST_ENTRY)Status;
 
                 /* Check if we had a timeout */
                 if (Timeout)
@@ -448,17 +417,17 @@
                 }
             }
 
-            /* Reacquire the lock */
-            OldIrql = KiAcquireDispatcherLock();
-
-            /* Save the new IRQL and decrease number of waiting threads */
-            Thread->WaitIrql = OldIrql;
+            /* Start another wait */
+            Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
+            KxQueueThreadWait();
+            KiAcquireDispatcherLockAtDpcLevel();
             Queue->CurrentCount--;
         }
     }
 
     /* Unlock Database and return */
-    KiReleaseDispatcherLock(Thread->WaitIrql);
+    KiReleaseDispatcherLockFromDpcLevel();
+    KiExitDispatcher(Thread->WaitIrql);
     return QueueEntry;
 }
 

Modified: trunk/reactos/ntoskrnl/ke/wait.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/wait.c?rev=25605&r1=25604&r2=25605&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/ke/wait.c (original)
+++ trunk/reactos/ntoskrnl/ke/wait.c Tue Jan 23 21:39:47 2007
@@ -15,6 +15,7 @@
 
 /* PRIVATE FUNCTIONS *********************************************************/
 
+#if 0
 VOID
 FASTCALL
 KiWaitSatisfyAll(PKWAIT_BLOCK FirstBlock)
@@ -36,6 +37,7 @@
         WaitBlock = WaitBlock->NextWaitBlock;
     } while (WaitBlock != FirstBlock);
 }
+#endif
 
 VOID
 FASTCALL
@@ -234,89 +236,122 @@
                        IN BOOLEAN Alertable,
                        IN PLARGE_INTEGER Interval OPTIONAL)
 {
-    PKTIMER ThreadTimer;
+    PKTIMER Timer;
+    PKWAIT_BLOCK TimerBlock;
     PKTHREAD Thread = KeGetCurrentThread();
     NTSTATUS WaitStatus;
     BOOLEAN Swappable;
-    PLARGE_INTEGER OriginalDueTime = Interval;
-    LARGE_INTEGER DueTime, NewDueTime;
+    PLARGE_INTEGER OriginalDueTime;
+    LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
+
+    /* If this is a user-mode wait of 0 seconds, yield execution */
+    if (!(Interval->QuadPart) && (WaitMode != KernelMode))
+    {
+        /* Make sure the wait isn't alertable or interrupting an APC */
+        if (!(Alertable) && !(Thread->ApcState.UserApcPending))
+        {
+            /* Yield execution */
+            NtYieldExecution();
+        }
+    }
+
+    /* Setup the original time and timer/wait blocks */
+    OriginalDueTime = Interval;
+    Timer = &Thread->Timer;
+    TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
 
     /* Check if the lock is already held */
-    if (Thread->WaitNext)
-    {
-        /* Lock is held, disable Wait Next */
-        Thread->WaitNext = FALSE;
-        Swappable = KxDelayThreadWait(Thread, Alertable, WaitMode);
-    }
-    else
-    {
-        /* Lock not held, acquire it */
+    if (!Thread->WaitNext) goto WaitStart;
+
+    /*  Otherwise, we already have the lock, so initialize the wait */
+    Thread->WaitNext = FALSE;
+    KxDelayThreadWait();
+
+    /* Start wait loop */
+    for (;;)
+    {
+        /* Disable pre-emption */
+        Thread->Preempted = FALSE;
+
+        /* Check if a kernel APC is pending and we're below APC_LEVEL */
+        if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
+            (Thread->WaitIrql < APC_LEVEL))
+        {
+            /* Unlock the dispatcher */
+            KiReleaseDispatcherLock(Thread->WaitIrql);
+        }
+        else
+        {
+            /* Check if we have to bail out due to an alerted state */
+            WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
+            if (WaitStatus != STATUS_WAIT_0) break;
+
+            /* Check if the timer expired */
+            InterruptTime.QuadPart = KeQueryInterruptTime();
+            if (InterruptTime.QuadPart >= Timer->DueTime.QuadPart)
+            {
+                /* It did, so we don't need to wait */
+                goto NoWait;
+            }
+
+            /* It didn't, so activate it */
+            Timer->Header.Inserted = TRUE;
+
+            /* Handle Kernel Queues */
+            if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
+
+            /* Setup the wait information */
+            Thread->State = Waiting;
+
+            /* Add the thread to the wait list */
+            KiAddThreadToWaitList(Thread, Swappable);
+
+            /* Insert the timer and swap the thread */
+            ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
+            KiSetThreadSwapBusy(Thread);
+            KiInsertWaitTimer(Timer);
+            WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
+
+            /* Check if were swapped ok */
+            if (WaitStatus != STATUS_KERNEL_APC)
+            {
+                /* This is a good thing */
+                if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS;
+
+                /* Return Status */
+                return WaitStatus;
+            }
+
+            /* Recalculate due times */
+            Interval = KiRecalculateDueTime(OriginalDueTime,
+                                            &DueTime,
+                                            &NewDueTime);
+        }
+
 WaitStart:
-        Thread->WaitIrql = KiAcquireDispatcherLock();
-        Swappable = KxDelayThreadWait(Thread, Alertable, WaitMode);
-    }
-
-    /* Check if a kernel APC is pending and we're below APC_LEVEL */
-    if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
-        (Thread->WaitIrql < APC_LEVEL))
-    {
-        /* Unlock the dispatcher */
+        /* Setup a new wait */
+        Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
+        KxDelayThreadWait();
+        KiAcquireDispatcherLockAtDpcLevel();
+    }
+
+    /* We're done! */
+    KiReleaseDispatcherLock(Thread->WaitIrql);
+    return WaitStatus;
+
+NoWait:
+    /* There was nothing to wait for. Did we have a wait interval? */
+    if (!Interval->QuadPart)
+    {
+        /* Unlock the dispatcher and do a yield */
         KiReleaseDispatcherLock(Thread->WaitIrql);
-        goto WaitStart;
-    }
-
-    /* Check if we have to bail out due to an alerted state */
-    WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
-    if (WaitStatus != STATUS_WAIT_0)
-    {
-        /* Unlock the dispatcher and return */
-        KiReleaseDispatcherLock(Thread->WaitIrql);
-        return WaitStatus;
-    }
-
-    /* Set Timer */
-    ThreadTimer = &Thread->Timer;
-
-    /* Insert the Timer into the Timer Lists and enable it */
-    if (!KiInsertTimer(ThreadTimer, *Interval))
-    {
-        /* FIXME: We should find a new ready thread */
-        KiReleaseDispatcherLock(Thread->WaitIrql);
-        return STATUS_WAIT_0;
-    }
-
-    /* Save due time */
-    DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
-
-    /* Handle Kernel Queues */
-    if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
-
-    /* Setup the wait information */
-    Thread->State = Waiting;
-
-    /* Add the thread to the wait list */
-    KiAddThreadToWaitList(Thread, Swappable);
-
-    /* Swap the thread */
-    ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
-    KiSetThreadSwapBusy(Thread);
-    WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
-
-    /* Check if we were executing an APC or if we timed out */
-    if (WaitStatus == STATUS_KERNEL_APC)
-    {
-        /* Recalculate due times */
-        Interval = KiRecalculateDueTime(OriginalDueTime,
-                                        &DueTime,
-                                        &NewDueTime);
-        goto WaitStart;
-    }
-
-    /* This is a good thing */
-    if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS;
-
-    /* Return Status */
-    return WaitStatus;
+        return NtYieldExecution();
+    }
+
+    /* Unlock the dispatcher and adjust the quantum for a no-wait */
+    KiReleaseDispatcherLockFromDpcLevel();
+    KiAdjustQuantumThread(Thread);
+    return STATUS_SUCCESS;
 }
 
 /*
@@ -330,157 +365,145 @@
                       IN BOOLEAN Alertable,
                       IN PLARGE_INTEGER Timeout OPTIONAL)
 {
-    PKMUTANT CurrentObject;
-    PKWAIT_BLOCK WaitBlock;
-    PKTIMER ThreadTimer;
     PKTHREAD Thread = KeGetCurrentThread();
+    PKMUTANT CurrentObject = (PKMUTANT)Object;
+    PKWAIT_BLOCK WaitBlock = &Thread->WaitBlock[0];
+    PKWAIT_BLOCK TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
+    PKTIMER Timer = &Thread->Timer;
     NTSTATUS WaitStatus;
     BOOLEAN Swappable;
-    LARGE_INTEGER DueTime, NewDueTime;
+    LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
     PLARGE_INTEGER OriginalDueTime = Timeout;
 
-    /* Get wait block */
-    WaitBlock = &Thread->WaitBlock[0];
-
     /* Check if the lock is already held */
-    if (Thread->WaitNext)
-    {
-        /* Lock is held, disable Wait Next */
-        Thread->WaitNext = FALSE;
-        Swappable = KxSingleThreadWait(Thread,
-                                       WaitBlock,
-                                       Object,
-                                       Timeout,
-                                       Alertable,
-                                       WaitReason,
-                                       WaitMode);
-    }
-    else
-    {
-StartWait:
-        /* Lock not held, acquire it */
-        Thread->WaitIrql = KiAcquireDispatcherLock();
-        Swappable = KxSingleThreadWait(Thread,
-                                       WaitBlock,
-                                       Object,
-                                       Timeout,
-                                       WaitReason,
-                                       WaitMode,
-                                       Alertable);
-    }
-
-    /* Check if a kernel APC is pending and we're below APC_LEVEL */
-    if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
-        (Thread->WaitIrql < APC_LEVEL))
-    {
-        /* Unlock the dispatcher and wait again */
-        KiReleaseDispatcherLock(Thread->WaitIrql);
-        goto StartWait;
-    }
-
-    /* Get the Current Object */
-    CurrentObject = (PKMUTANT)Object;
-    ASSERT(CurrentObject->Header.Type != QueueObject);
-
-    /* Check if it's a mutant */
-    if (CurrentObject->Header.Type == MutantObject)
-    {
-        /* Check its signal state or if we own it */
-        if ((CurrentObject->Header.SignalState > 0) ||
-            (Thread == CurrentObject->OwnerThread))
-        {
-            /* Just unwait this guy and exit */
-            if (CurrentObject->Header.SignalState != (LONG)MINLONG)
-            {
-                /* It has a normal signal state. Unwait and return */
-                KiSatisfyMutantWait(CurrentObject, Thread);
-                WaitStatus = Thread->WaitStatus;
+    if (!Thread->WaitNext) goto WaitStart;
+
+    /*  Otherwise, we already have the lock, so initialize the wait */
+    Thread->WaitNext = FALSE;
+    KxSingleThreadWait();
+
+    /* Start wait loop */
+    for (;;)
+    {
+        /* Disable pre-emption */
+        Thread->Preempted = FALSE;
+
+        /* Check if a kernel APC is pending and we're below APC_LEVEL */
+        if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
+            (Thread->WaitIrql < APC_LEVEL))
+        {
+            /* Unlock the dispatcher */
+            KiReleaseDispatcherLock(Thread->WaitIrql);
+        }
+        else
+        {
+            /* Sanity check */
+            ASSERT(CurrentObject->Header.Type != QueueObject);
+
+            /* Check if it's a mutant */
+            if (CurrentObject->Header.Type == MutantObject)
+            {
+                /* Check its signal state or if we own it */
+                if ((CurrentObject->Header.SignalState > 0) ||
+                    (Thread == CurrentObject->OwnerThread))
+                {
+                    /* Just unwait this guy and exit */
+                    if (CurrentObject->Header.SignalState != (LONG)MINLONG)
+                    {
+                        /* It has a normal signal state. Unwait and return */
+                        KiSatisfyMutantWait(CurrentObject, Thread);
+                        WaitStatus = Thread->WaitStatus;
+                        goto DontWait;
+                    }
+                    else
+                    {
+                        /* Raise an exception */
+                        KiReleaseDispatcherLock(Thread->WaitIrql);
+                        ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+                   }
+                }
+            }
+            else if (CurrentObject->Header.SignalState > 0)
+            {
+                /* Another satisfied object */
+                KiSatisfyNonMutantWait(CurrentObject, Thread);
+                WaitStatus = STATUS_WAIT_0;
                 goto DontWait;
             }
+
+            /* Make sure we can satisfy the Alertable request */
+            WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
+            if (WaitStatus != STATUS_WAIT_0) break;
+
+            /* Enable the Timeout Timer if there was any specified */
+            if (Timeout)
+            {
+                /* Check if the timer expired */
+                InterruptTime.QuadPart = KeQueryInterruptTime();
+                if (InterruptTime.QuadPart >= Timer->DueTime.QuadPart)
+                {
+                    /* It did, so we don't need to wait */
+                    WaitStatus = STATUS_TIMEOUT;
+                    goto DontWait;
+                }
+
+                /* It didn't, so activate it */
+                Timer->Header.Inserted = TRUE;
+            }
+
+            /* Link the Object to this Wait Block */
+            InsertTailList(&CurrentObject->Header.WaitListHead,
+                           &WaitBlock->WaitListEntry);
+
+            /* Handle Kernel Queues */
+            if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
+
+            /* Setup the wait information */
+            Thread->State = Waiting;
+
+            /* Add the thread to the wait list */
+            KiAddThreadToWaitList(Thread, Swappable);
+
+            /* Activate thread swap */
+            ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
+            KiSetThreadSwapBusy(Thread);
+
+            /* Check if we have a timer */
+            if (Timeout)
+            {
+                /* Insert it */
+                KiInsertWaitTimer(Timer);
+            }
             else
             {
-                /* Raise an exception */
-                KiReleaseDispatcherLock(Thread->WaitIrql);
-                ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
-           }
-        }
-    }
-    else if (CurrentObject->Header.SignalState > 0)
-    {
-        /* Another satisfied object */
-        KiSatisfyNonMutantWait(CurrentObject, Thread);
-        WaitStatus = STATUS_WAIT_0;
-        goto DontWait;
-    }
-
-    /* Make sure we can satisfy the Alertable request */
-    WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
-    if (WaitStatus != STATUS_WAIT_0)
-    {
-        /* Unlock the dispatcher and return */
-        KiReleaseDispatcherLock(Thread->WaitIrql);
-        return WaitStatus;
-    }
-
-    /* Enable the Timeout Timer if there was any specified */
-    if (Timeout)
-    {
-        /* Fail if the timeout interval is actually 0 */
-        if (!Timeout->QuadPart)
-        {
-            /* Return a timeout */
-            WaitStatus = STATUS_TIMEOUT;
-            goto DontWait;
-        }
-
-        /* Insert the Timer into the Timer Lists and enable it */
-        ThreadTimer = &Thread->Timer;
-        if (!KiInsertTimer(ThreadTimer, *Timeout))
-        {
-            /* Return a timeout if we couldn't insert the timer */
-            WaitStatus = STATUS_TIMEOUT;
-            goto DontWait;
-        }
-
-        /* Set the current due time */
-        DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
-    }
-
-    /* Link the Object to this Wait Block */
-    InsertTailList(&CurrentObject->Header.WaitListHead,
-                   &WaitBlock->WaitListEntry);
-
-    /* Handle Kernel Queues */
-    if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
-
-    /* Setup the wait information */
-    Thread->State = Waiting;
-
-    /* Add the thread to the wait list */
-    KiAddThreadToWaitList(Thread, Swappable);
-
-    /* Swap the thread */
-    ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
-    KiSetThreadSwapBusy(Thread);
-    WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
-
-    /* Check if we were executing an APC */
-    if (WaitStatus == STATUS_KERNEL_APC)
-    {
-        /* Check if we had a timeout */
-        if (Timeout)
-        {
-            /* Recalculate due times */
-            Timeout = KiRecalculateDueTime(OriginalDueTime,
-                                           &DueTime,
-                                           &NewDueTime);
-        }
-
-        /* Wait again */
-        goto StartWait;
+                /* Otherwise, unlock the dispatcher */
+                KiReleaseDispatcherLockFromDpcLevel();
+            }
+
+            /* Do the actual swap */
+            WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
+
+            /* Check if we were executing an APC */
+            if (WaitStatus != STATUS_KERNEL_APC) return WaitStatus;
+
+            /* Check if we had a timeout */
+            if (Timeout)
+            {
+                /* Recalculate due times */
+                Timeout = KiRecalculateDueTime(OriginalDueTime,
+                                               &DueTime,
+                                               &NewDueTime);
+            }
+        }
+WaitStart:
+        /* Setup a new wait */
+        Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
+        KxSingleThreadWait();
+        KiAcquireDispatcherLockAtDpcLevel();
     }
 
     /* Wait complete */
+    KiReleaseDispatcherLock(Thread->WaitIrql);
     return WaitStatus;
 
 DontWait:
@@ -508,15 +531,14 @@
 {
     PKMUTANT CurrentObject;
     PKWAIT_BLOCK WaitBlock;
-    PKWAIT_BLOCK TimerWaitBlock;
-    PKTIMER ThreadTimer;
     PKTHREAD Thread = KeGetCurrentThread();
-    ULONG AllObjectsSignaled;
-    ULONG WaitIndex;
+    PKWAIT_BLOCK TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
+    PKTIMER Timer = &Thread->Timer;
     NTSTATUS WaitStatus = STATUS_SUCCESS;
     BOOLEAN Swappable;
     PLARGE_INTEGER OriginalDueTime = Timeout;
-    LARGE_INTEGER DueTime, NewDueTime;
+    LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
+    ULONG Index;
 
     /* Make sure the Wait Count is valid */
     if (!WaitBlockArray)
@@ -545,219 +567,220 @@
     ASSERT(Count != 0);
 
     /* Check if the lock is already held */
-    if (Thread->WaitNext)
-    {
-        /* Lock is held, disable Wait Next */
-        Thread->WaitNext = FALSE;
-    }
-    else
-    {
-        /* Lock not held, acquire it */
-StartWait:
-        Thread->WaitIrql = KiAcquireDispatcherLock();
-    }
-
-    /* Prepare for the wait */
-    Swappable = KxMultiThreadWait(Thread,
-                                  WaitBlockArray,
-                                  Alertable,
-                                  WaitReason,
-                                  WaitMode);
-
-    /* Check if a kernel APC is pending and we're below APC_LEVEL */
-    if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
-        (Thread->WaitIrql < APC_LEVEL))
-    {
-        /* Unlock the dispatcher */
-        KiReleaseDispatcherLock(Thread->WaitIrql);
-        goto StartWait;
-    }
-
-    /* Append wait block to the KTHREAD wait block list */
-    WaitBlock = WaitBlockArray;
-
-    /* Check if the wait is (already) satisfied */
-    AllObjectsSignaled = TRUE;
-
-    /* First, we'll try to satisfy the wait directly */
-    for (WaitIndex = 0; WaitIndex < Count; WaitIndex++)
-    {
-        /* Get the Current Object */
-        CurrentObject = (PKMUTANT)Object[WaitIndex];
-        ASSERT(CurrentObject->Header.Type != QueueObject);
-
-        /* Check the type of wait */
-        if (WaitType == WaitAny)
-        {
-            /* Check if the Object is a mutant */
-            if (CurrentObject->Header.Type == MutantObject)
-            {
-                /* Check if it's signaled */
-                if ((CurrentObject->Header.SignalState > 0) ||
-                    (Thread == CurrentObject->OwnerThread))
+    if (!Thread->WaitNext) goto WaitStart;
+
+    /*  Otherwise, we already have the lock, so initialize the wait */
+    Thread->WaitNext = FALSE;
+    KxMultiThreadWait();
+
+    /* Start wait loop */
+    for (;;)
+    {
+        /* Disable pre-emption */
+        Thread->Preempted = FALSE;
+
+        /* Check if a kernel APC is pending and we're below APC_LEVEL */
+        if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
+            (Thread->WaitIrql < APC_LEVEL))
+        {
+            /* Unlock the dispatcher */
+            KiReleaseDispatcherLock(Thread->WaitIrql);
+        }
+        else
+        {
+            /* Check what kind of wait this is */
+            Index = 0;
+            if (WaitType == WaitAny)
+            {
+                /* Loop blocks */
+                do
                 {
-                    /* This is a Wait Any, so unwait this and exit */
-                    if (CurrentObject->Header.SignalState !=
-                        (LONG)MINLONG)
+                    /* Get the Current Object */
+                    CurrentObject = (PKMUTANT)Object[Index];
+                    ASSERT(CurrentObject->Header.Type != QueueObject);
+
+                    /* Check if the Object is a mutant */
+                    if (CurrentObject->Header.Type == MutantObject)
                     {
-                        /* Normal signal state, unwait it and return */
-                        KiSatisfyMutantWait(CurrentObject, Thread);
-                        WaitStatus = Thread->WaitStatus | WaitIndex;
+                        /* Check if it's signaled */
+                        if ((CurrentObject->Header.SignalState > 0) ||
+                            (Thread == CurrentObject->OwnerThread))
+                        {
+                            /* This is a Wait Any, so unwait this and exit */
+                            if (CurrentObject->Header.SignalState !=
+                                (LONG)MINLONG)
+                            {
+                                /* Normal signal state, unwait it and return */
+                                KiSatisfyMutantWait(CurrentObject, Thread);
+                                WaitStatus = Thread->WaitStatus | Index;
+                                goto DontWait;
+                            }
+                            else
+                            {
+                                /* Raise an exception (see wasm.ru) */
+                                KiReleaseDispatcherLock(Thread->WaitIrql);
+                                ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+                            }
+                        }
+                    }
+                    else if (CurrentObject->Header.SignalState > 0)
+                    {
+                        /* Another signaled object, unwait and return */
+                        KiSatisfyNonMutantWait(CurrentObject, Thread);
+                        WaitStatus = Index;
                         goto DontWait;
                     }
-                    else
+
+                    /* Go to the next block */
+                    Index++;
+                } while (Index < Count);
+            }
+            else
+            {
+                /* Loop blocks */
+                do
+                {
+                    /* Get the Current Object */
+                    CurrentObject = (PKMUTANT)Object[Index];
+                    ASSERT(CurrentObject->Header.Type != QueueObject);
+
+                    /* Check if we're dealing with a mutant again */
+                    if (CurrentObject->Header.Type == MutantObject)
                     {
-                        /* Raise an exception (see wasm.ru) */
-                        KiReleaseDispatcherLock(Thread->WaitIrql);
-                        ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+                        /* Check if it has an invalid count */
+                        if ((Thread == CurrentObject->OwnerThread) &&
+                            (CurrentObject->Header.SignalState == MINLONG))
+                        {
+                            /* Raise an exception */
+                            KiReleaseDispatcherLock(Thread->WaitIrql);
+                            ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+                        }
+                        else if ((CurrentObject->Header.SignalState <= 0) &&
+                                 (Thread != CurrentObject->OwnerThread))
+                        {
+                            /* We don't own it, can't satisfy the wait */
+                            break;
+                        }
                     }
+                    else if (CurrentObject->Header.SignalState <= 0)
+                    {
+                        /* Not signaled, can't satisfy */
+                        break;
+                    }
+
+                    /* Go to the next block */
+                    Index++;
+                } while (Index < Count);
+
+                /* Check if we've went through all the objects */
+                if (Index == Count)
+                {
+                    /* Loop wait blocks */
+                    WaitBlock = WaitBlockArray;
+                    do
+                    {
+                        /* Get the object and satisfy it */
+                        CurrentObject = (PKMUTANT)WaitBlock->Object;
+                        KiSatisfyObjectWait(CurrentObject, Thread);
+
+                        /* Go to the next block */
+                        WaitBlock = WaitBlock->NextWaitBlock;
+                    } while(WaitBlock != WaitBlockArray);
+
+                    /* Set the wait status and get out */
+                    WaitStatus = Thread->WaitStatus;
+                    goto DontWait;
                 }
             }
-            else if (CurrentObject->Header.SignalState > 0)
-            {
-                /* Another signaled object, unwait and return */
-                KiSatisfyNonMutantWait(CurrentObject, Thread);
-                WaitStatus = WaitIndex;
-                goto DontWait;
-            }
-        }
-        else
-        {
-            /* Check if we're dealing with a mutant again */
-            if (CurrentObject->Header.Type == MutantObject)
-            {
-                /* Check if it has an invalid count */
-                if ((Thread == CurrentObject->OwnerThread) &&
-                    (CurrentObject->Header.SignalState == MINLONG))
+
+            /* Make sure we can satisfy the Alertable request */
+            WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
+            if (WaitStatus != STATUS_WAIT_0) break;
+
+            /* Enable the Timeout Timer if there was any specified */
+            if (Timeout)
+            {
+                /* Check if the timer expired */
+                InterruptTime.QuadPart = KeQueryInterruptTime();
+                if (InterruptTime.QuadPart >= Timer->DueTime.QuadPart)
                 {
-                    /* Raise an exception */
-                    KiReleaseDispatcherLock(Thread->WaitIrql);
-                    ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+                    /* It did, so we don't need to wait */
+                    WaitStatus = STATUS_TIMEOUT;
+                    goto DontWait;
                 }
-                else if ((CurrentObject->Header.SignalState <= 0) &&
-                         (Thread != CurrentObject->OwnerThread))
-                {
-                    /* We don't own it, can't satisfy the wait */
-                    AllObjectsSignaled = FALSE;
-                }
-            }
-            else if (CurrentObject->Header.SignalState <= 0)
-            {
-                /* Not signaled, can't satisfy */
-                AllObjectsSignaled = FALSE;
-            }
-        }
-
-        /* Set up a Wait Block for this Object */
-        WaitBlock = &WaitBlockArray[WaitIndex];
-        WaitBlock->Object = CurrentObject;
-        WaitBlock->Thread = Thread;
-        WaitBlock->WaitKey = (USHORT)WaitIndex;
-        WaitBlock->WaitType = (UCHAR)WaitType;
-        WaitBlock->NextWaitBlock = &WaitBlockArray[WaitIndex + 1];
-    }
-
-    /* Check if this is a Wait All and all the objects are signaled */
-    if ((WaitType == WaitAll) && (AllObjectsSignaled))
-    {
-        /* Return to the Root Wait Block */
-        WaitBlock->NextWaitBlock = &WaitBlockArray[0];
-
-        /* Satisfy their Waits and return to the caller */
-        KiWaitSatisfyAll(WaitBlock);
-        WaitStatus = Thread->WaitStatus;
-        goto DontWait;
-    }
-
-    /* Make sure we can satisfy the Alertable request */
-    WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
-    if (WaitStatus != STATUS_WAIT_0)
-    {
-        /* Unlock the dispatcher and return */
-        KiReleaseDispatcherLock(Thread->WaitIrql);
-        return WaitStatus;
-    }
-
-    /* Enable the Timeout Timer if there was any specified */
-    if (Timeout)
-    {
-        /* Make sure the timeout interval isn't actually 0 */
-        if (!Timeout->QuadPart)
-        {
-            /* Return a timeout */
-            WaitStatus = STATUS_TIMEOUT;
-            goto DontWait;
-        }
-
-        /* Link timer wait block */
-        TimerWaitBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
-        WaitBlock->NextWaitBlock = TimerWaitBlock;
-
-        /* Use this the timer block for linking below */
-        WaitBlock = TimerWaitBlock;
-
-        /* Insert the Timer into the Timer Lists and enable it */
-        ThreadTimer = &Thread->Timer;
-        if (!KiInsertTimer(ThreadTimer, *Timeout))
-        {
-            /* Return a timeout if we couldn't insert the timer */
-            WaitStatus = STATUS_TIMEOUT;
-            goto DontWait;
-        }
-
-        /* Set the current due time */
-        DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
-    }
-
-    /* Link to the Root Wait Block */
-    WaitBlock->NextWaitBlock = &WaitBlockArray[0];
-
-    /* Insert into Object's Wait List*/
-    WaitBlock = &WaitBlockArray[0];
-    do
-    {
-        /* Get the Current Object */
-        CurrentObject = WaitBlock->Object;
-
-        /* Link the Object to this Wait Block */
-        InsertTailList(&CurrentObject->Header.WaitListHead,
-                       &WaitBlock->WaitListEntry);
-
-        /* Move to the next Wait Block */
-        WaitBlock = WaitBlock->NextWaitBlock;
-    } while (WaitBlock != WaitBlockArray);
-
-    /* Handle Kernel Queues */
-    if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
-
-    /* Setup the wait information */
-    Thread->State = Waiting;
-
-    /* Add the thread to the wait list */
-    KiAddThreadToWaitList(Thread, Swappable);
-
-    /* Swap the thread */
-    ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
-    KiSetThreadSwapBusy(Thread);
-    WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
-
-    /* Check if we were executing an APC */
-    if (WaitStatus == STATUS_KERNEL_APC)
-    {
-        /* Check if we had a timeout */
-        if (Timeout)
-        {
-            /* Recalculate due times */
-            Timeout = KiRecalculateDueTime(OriginalDueTime,
-                                           &DueTime,
-                                           &NewDueTime);
-        }
-
-        /* Wait again */
-        goto StartWait;
+
+                /* It didn't, so activate it */
+                Timer->Header.Inserted = TRUE;
+
+                /* Link the wait blocks */
+                WaitBlock->NextWaitBlock = TimerBlock;
+            }
+
+            /* Insert into Object's Wait List*/
+            WaitBlock = WaitBlockArray;
+            do
+            {
+                /* Get the Current Object */
+                CurrentObject = WaitBlock->Object;
+
+                /* Link the Object to this Wait Block */
+                InsertTailList(&CurrentObject->Header.WaitListHead,
+                               &WaitBlock->WaitListEntry);
+
+                /* Move to the next Wait Block */
+                WaitBlock = WaitBlock->NextWaitBlock;
+            } while (WaitBlock != WaitBlockArray);
+
+            /* Handle Kernel Queues */
+            if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
+
+            /* Setup the wait information */
+            Thread->State = Waiting;
+
+            /* Add the thread to the wait list */
+            KiAddThreadToWaitList(Thread, Swappable);
+
+            /* Activate thread swap */
+            ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
+            KiSetThreadSwapBusy(Thread);
+
+            /* Check if we have a timer */
+            if (Timeout)
+            {
+                /* Insert it */
+                KiInsertWaitTimer(Timer);
+            }
+            else
+            {
+                /* Otherwise, unlock the dispatcher */
+                KiReleaseDispatcherLockFromDpcLevel();
+            }
+
+            /* Swap the thread */
+            WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
+
+            /* Check if we were executing an APC */
+            if (WaitStatus != STATUS_KERNEL_APC) return WaitStatus;
+
+            /* Check if we had a timeout */
+            if (Timeout)
+            {
+                /* Recalculate due times */
+                Timeout = KiRecalculateDueTime(OriginalDueTime,
+                                               &DueTime,
+                                               &NewDueTime);
+            }
+        }
+
+WaitStart:
+        /* Setup a new wait */
+        Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
+        KxMultiThreadWait();
+        KiAcquireDispatcherLockAtDpcLevel();
     }
 
     /* We are done */
+    KiReleaseDispatcherLock(Thread->WaitIrql);
     return WaitStatus;
 
 DontWait:




More information about the Ros-diffs mailing list