- Use _SEH2_YIELD when returning from an exception instead of returning outside the...
[reactos.git] / reactos / ntoskrnl / ke / wait.c
index dabe787..2e9c1c8 100644 (file)
@@ -117,6 +117,76 @@ KiAcquireFastMutex(IN PFAST_MUTEX FastMutex)
                           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
@@ -520,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 */
@@ -532,7 +602,7 @@ KeWaitForMultipleObjects(IN ULONG Count,
         if (Count > MAXIMUM_WAIT_OBJECTS)
         {
             /* Bugcheck */
-            KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
+            KeBugCheck(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
         }
     }
 
@@ -544,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 */
@@ -622,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);
@@ -773,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 */