[HEADERS]
[reactos.git] / reactos / ntoskrnl / ke / wait.c
index 52eef58..a4737b0 100644 (file)
 
 #include <ntoskrnl.h>
 #define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
 
 /* PRIVATE FUNCTIONS *********************************************************/
 
-#if 0
-VOID
-FASTCALL
-KiWaitSatisfyAll(PKWAIT_BLOCK FirstBlock)
-{
-    PKWAIT_BLOCK WaitBlock = FirstBlock;
-    PKTHREAD WaitThread = WaitBlock->Thread;
-
-    /* Loop through all the Wait Blocks, and wake each Object */
-    do
-    {
-        /* Make sure it hasn't timed out */
-        if (WaitBlock->WaitKey != STATUS_TIMEOUT)
-        {
-            /* Wake the Object */
-            KiSatisfyObjectWait((PKMUTANT)WaitBlock->Object, WaitThread);
-        }
-
-        /* Move to the next block */
-        WaitBlock = WaitBlock->NextWaitBlock;
-    } while (WaitBlock != FirstBlock);
-}
-#endif
-
 VOID
 FASTCALL
 KiWaitTest(IN PVOID ObjectPointer,
@@ -101,13 +77,7 @@ KiUnlinkThread(IN PKTHREAD Thread,
 
     /* Check if there's a Thread Timer */
     Timer = &Thread->Timer;
-    if (Timer->Header.Inserted)
-    {
-        /* Remove the timer */
-        Timer->Header.Inserted = FALSE;
-        RemoveEntryList(&Timer->TimerListEntry);
-        //KiRemoveTimer(Timer);
-    }
+    if (Timer->Header.Inserted) KxRemoveTreeTimer(Timer);
 
     /* Increment the Queue's active threads */
     if (Thread->Queue) Thread->Queue->CurrentCount++;
@@ -117,7 +87,7 @@ KiUnlinkThread(IN PKTHREAD Thread,
 VOID
 FASTCALL
 KiUnwaitThread(IN PKTHREAD Thread,
-               IN NTSTATUS WaitStatus,
+               IN LONG_PTR WaitStatus,
                IN KPRIORITY Increment)
 {
     /* Unlink the thread */
@@ -140,13 +110,83 @@ KiAcquireFastMutex(IN PFAST_MUTEX FastMutex)
     FastMutex->Contention++;
 
     /* Wait for the event */
-    KeWaitForSingleObject(&FastMutex->Gate,
+    KeWaitForSingleObject(&FastMutex->Event,
                           WrMutex,
                           KernelMode,
                           FALSE,
                           NULL);
 }
 
+VOID
+FASTCALL
+KiAcquireGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
+{
+    ULONG BitsToRemove, BitsToAdd;
+    LONG OldValue, NewValue;
+
+    /* We depend on these bits being just right */
+    C_ASSERT((GM_LOCK_WAITER_WOKEN * 2) == GM_LOCK_WAITER_INC);
+    
+    /* Increase the contention count */
+    GuardedMutex->Contention++;
+    
+    /* Start by unlocking the Guarded Mutex */
+    BitsToRemove = GM_LOCK_BIT;
+    BitsToAdd = GM_LOCK_WAITER_INC;
+    
+    /* Start change loop */
+    for (;;)
+    {
+        /* Loop sanity checks */
+        ASSERT((BitsToRemove == GM_LOCK_BIT) ||
+               (BitsToRemove == (GM_LOCK_BIT | GM_LOCK_WAITER_WOKEN)));
+        ASSERT((BitsToAdd == GM_LOCK_WAITER_INC) ||
+               (BitsToAdd == GM_LOCK_WAITER_WOKEN));
+        
+        /* Get the Count Bits */
+        OldValue = GuardedMutex->Count;
+        
+        /* Start internal bit change loop */
+        for (;;)
+        {
+            /* Check if the Guarded Mutex is locked */
+            if (OldValue & GM_LOCK_BIT)
+            {
+                /* Sanity check */
+                ASSERT((BitsToRemove == GM_LOCK_BIT) ||
+                       ((OldValue & GM_LOCK_WAITER_WOKEN) != 0));
+                
+                /* Unlock it by removing the Lock Bit */
+                NewValue = OldValue ^ BitsToRemove;
+                NewValue = InterlockedCompareExchange(&GuardedMutex->Count,
+                                                      NewValue,
+                                                      OldValue);
+                if (NewValue == OldValue) return;
+            }
+            else
+            {
+                /* The Guarded Mutex isn't locked, so simply set the bits */
+                NewValue = OldValue + BitsToAdd;
+                NewValue = InterlockedCompareExchange(&GuardedMutex->Count,
+                                                      NewValue,
+                                                      OldValue);
+                if (NewValue == OldValue) break;
+            }
+            
+            /* Old value changed, loop again */
+            OldValue = NewValue;
+        }
+        
+        /* Now we have to wait for it */
+        KeWaitForGate(&GuardedMutex->Gate, WrGuardedMutex, KernelMode);
+        ASSERT((GuardedMutex->Count & GM_LOCK_WAITER_WOKEN) != 0);
+        
+        /* Ok, the wait is done, so set the new bits */
+        BitsToRemove = GM_LOCK_BIT | GM_LOCK_WAITER_WOKEN;
+        BitsToAdd = GM_LOCK_WAITER_WOKEN;
+    }
+}
+
 //
 // This routine exits the dispatcher after a compatible operation and
 // swaps the context to the next scheduled thread on the current CPU if
@@ -163,7 +203,7 @@ KiExitDispatcher(IN KIRQL OldIrql)
     BOOLEAN PendingApc;
 
     /* Make sure we're at synchronization level */
-    ASSERT_IRQL_EQUAL(SYNCH_LEVEL);
+    ASSERT(KeGetCurrentIrql() == SYNCH_LEVEL);
 
     /* Check if we have deferred threads */
     KiCheckDeferredReadyList(Prcb);
@@ -243,6 +283,7 @@ KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode,
     BOOLEAN Swappable;
     PLARGE_INTEGER OriginalDueTime;
     LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
+    ULONG Hand = 0;
 
     /* If this is a user-mode wait of 0 seconds, yield execution */
     if (!(Interval->QuadPart) && (WaitMode != KernelMode))
@@ -288,7 +329,7 @@ KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode,
 
             /* Check if the timer expired */
             InterruptTime.QuadPart = KeQueryInterruptTime();
-            if (InterruptTime.QuadPart >= Timer->DueTime.QuadPart)
+            if ((ULONGLONG)InterruptTime.QuadPart >= Timer->DueTime.QuadPart)
             {
                 /* It did, so we don't need to wait */
                 goto NoWait;
@@ -309,7 +350,7 @@ KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode,
             /* Insert the timer and swap the thread */
             ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
             KiSetThreadSwapBusy(Thread);
-            KiInsertWaitTimer(Timer);
+            KxInsertTimer(Timer, Hand);
             WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
 
             /* Check if were swapped ok */
@@ -374,6 +415,7 @@ KeWaitForSingleObject(IN PVOID Object,
     BOOLEAN Swappable;
     LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
     PLARGE_INTEGER OriginalDueTime = Timeout;
+    ULONG Hand = 0;
 
     /* Check if the lock is already held */
     if (!Thread->WaitNext) goto WaitStart;
@@ -426,7 +468,7 @@ KeWaitForSingleObject(IN PVOID Object,
             else if (CurrentObject->Header.SignalState > 0)
             {
                 /* Another satisfied object */
-                KiSatisfyNonMutantWait(CurrentObject, Thread);
+                KiSatisfyNonMutantWait(CurrentObject);
                 WaitStatus = STATUS_WAIT_0;
                 goto DontWait;
             }
@@ -440,7 +482,8 @@ KeWaitForSingleObject(IN PVOID Object,
             {
                 /* Check if the timer expired */
                 InterruptTime.QuadPart = KeQueryInterruptTime();
-                if (InterruptTime.QuadPart >= Timer->DueTime.QuadPart)
+                if ((ULONGLONG)InterruptTime.QuadPart >=
+                    Timer->DueTime.QuadPart)
                 {
                     /* It did, so we don't need to wait */
                     WaitStatus = STATUS_TIMEOUT;
@@ -472,7 +515,7 @@ KeWaitForSingleObject(IN PVOID Object,
             if (Timeout)
             {
                 /* Insert it */
-                KiInsertWaitTimer(Timer);
+                KxInsertTimer(Timer, Hand);
             }
             else
             {
@@ -538,7 +581,7 @@ KeWaitForMultipleObjects(IN ULONG Count,
     BOOLEAN Swappable;
     PLARGE_INTEGER OriginalDueTime = Timeout;
     LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
-    ULONG Index;
+    ULONG Index, Hand = 0;
 
     /* Make sure the Wait Count is valid */
     if (!WaitBlockArray)
@@ -547,7 +590,7 @@ KeWaitForMultipleObjects(IN ULONG Count,
         if (Count > THREAD_WAIT_OBJECTS)
         {
             /* Bugcheck */
-            KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
+            KeBugCheck(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
         }
 
         /* Use the Thread's Wait Block */
@@ -559,7 +602,7 @@ KeWaitForMultipleObjects(IN ULONG Count,
         if (Count > MAXIMUM_WAIT_OBJECTS)
         {
             /* Bugcheck */
-            KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
+            KeBugCheck(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
         }
     }
 
@@ -571,6 +614,12 @@ KeWaitForMultipleObjects(IN ULONG Count,
 
     /*  Otherwise, we already have the lock, so initialize the wait */
     Thread->WaitNext = FALSE;
+    /*  Note that KxMultiThreadWait is a macro, defined in ke_x.h, that  */
+    /*  uses  (and modifies some of) the following local                 */
+    /*  variables:                                                       */
+    /*  Thread, Index, WaitBlock, Timer, Timeout, Hand and Swappable.    */
+    /*  If it looks like this code doesn't actually wait for any objects */
+    /*  at all, it's because the setup is done by that macro.            */
     KxMultiThreadWait();
 
     /* Start wait loop */
@@ -626,7 +675,7 @@ KeWaitForMultipleObjects(IN ULONG Count,
                     else if (CurrentObject->Header.SignalState > 0)
                     {
                         /* Another signaled object, unwait and return */
-                        KiSatisfyNonMutantWait(CurrentObject, Thread);
+                        KiSatisfyNonMutantWait(CurrentObject);
                         WaitStatus = Index;
                         goto DontWait;
                     }
@@ -649,7 +698,7 @@ KeWaitForMultipleObjects(IN ULONG Count,
                     {
                         /* Check if it has an invalid count */
                         if ((Thread == CurrentObject->OwnerThread) &&
-                            (CurrentObject->Header.SignalState == MINLONG))
+                            (CurrentObject->Header.SignalState == (LONG)MINLONG))
                         {
                             /* Raise an exception */
                             KiReleaseDispatcherLock(Thread->WaitIrql);
@@ -702,7 +751,8 @@ KeWaitForMultipleObjects(IN ULONG Count,
             {
                 /* Check if the timer expired */
                 InterruptTime.QuadPart = KeQueryInterruptTime();
-                if (InterruptTime.QuadPart >= Timer->DueTime.QuadPart)
+                if ((ULONGLONG)InterruptTime.QuadPart >=
+                    Timer->DueTime.QuadPart)
                 {
                     /* It did, so we don't need to wait */
                     WaitStatus = STATUS_TIMEOUT;
@@ -748,7 +798,7 @@ KeWaitForMultipleObjects(IN ULONG Count,
             if (Timeout)
             {
                 /* Insert it */
-                KiInsertWaitTimer(Timer);
+                KxInsertTimer(Timer, Hand);
             }
             else
             {
@@ -799,25 +849,24 @@ NtDelayExecution(IN BOOLEAN Alertable,
 {
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     LARGE_INTEGER SafeInterval;
-    NTSTATUS Status = STATUS_SUCCESS;
+    NTSTATUS Status;
 
     /* Check the previous mode */
-    if(PreviousMode != KernelMode)
+    if (PreviousMode != KernelMode)
     {
         /* Enter SEH for probing */
-        _SEH_TRY
+        _SEH2_TRY
         {
             /* Probe and capture the time out */
             SafeInterval = ProbeForReadLargeInteger(DelayInterval);
             DelayInterval = &SafeInterval;
         }
-        _SEH_HANDLE
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            /* Get SEH exception */
-            Status = _SEH_GetExceptionCode();
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
         }
-        _SEH_END;
-        if (!NT_SUCCESS(Status)) return Status;
+        _SEH2_END;
    }
 
    /* Call the Kernel Function */