Save the old irql in ExTryToAcquireFastMutex.
[reactos.git] / reactos / hal / halx86 / generic / fmutex.c
index fc6f61f..2ada2b4 100644 (file)
@@ -1,54 +1,97 @@
-/* $Id$
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
+ * PROJECT:         ReactOS HAL
  * FILE:            ntoskrnl/hal/x86/fmutex.c
- * PURPOSE:         Implements fast mutexes
- * PROGRAMMER:      David Welch (welch@cwcom.net)
- *                  Eric Kohl (ekohl@rz-online.de)
- * UPDATE HISTORY:
- *                  Created 09/06/2000
+ * PURPOSE:         Deprecated HAL Fast Mutex
+ * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
+ */
+
+/*
+ * NOTE: Even HAL itself has #defines to use the Exi* APIs inside NTOSKRNL.
+ *       These are only exported here for compatibility with really old
+ *       drivers. Also note that in theory, these can be made much faster
+ *       by using assembly and inlining all the operations, including
+ *       raising and lowering irql.
  */
 
 /* INCLUDES *****************************************************************/
 
-#include <ddk/ntddk.h>
+#include <hal.h>
+#define NDEBUG
+#include <debug.h>
 
-#include <internal/debug.h>
+#undef ExAcquireFastMutex
+#undef ExReleaseFastMutex
+#undef ExTryToAcquireFastMutex
 
 /* FUNCTIONS *****************************************************************/
 
-#undef KeEnterCriticalRegion
-#undef KeLeaveCriticalRegion
-VOID FASTCALL
-ExAcquireFastMutex (PFAST_MUTEX        FastMutex)
+VOID
+FASTCALL
+ExAcquireFastMutex(PFAST_MUTEX FastMutex)
 {
-   KeEnterCriticalRegion();
-   ExAcquireFastMutexUnsafe(FastMutex);
-}
+    KIRQL OldIrql;
 
+    /* Raise IRQL to APC */
+    OldIrql = KfRaiseIrql(APC_LEVEL);
 
-VOID FASTCALL
-ExReleaseFastMutex (PFAST_MUTEX        FastMutex)
-{
-  ExReleaseFastMutexUnsafe(FastMutex);
-  KeLeaveCriticalRegion();
+    /* Decrease the count */
+    if (InterlockedDecrement(&FastMutex->Count))
+    {
+        /* Someone is still holding it, use slow path */
+        FastMutex->Contention++;
+        KeWaitForSingleObject(&FastMutex->Gate,
+                              WrExecutive,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+    }
+
+    /* Set the owner and IRQL */
+    FastMutex->Owner = KeGetCurrentThread();
+    FastMutex->OldIrql = OldIrql;
 }
 
+VOID
+FASTCALL
+ExReleaseFastMutex(PFAST_MUTEX FastMutex)
+{
+    /* Erase the owner */
+    FastMutex->Owner = (PVOID)1;
 
-BOOLEAN FASTCALL
-ExTryToAcquireFastMutex (PFAST_MUTEX FastMutex)
+    /* Increase the count */
+    if (InterlockedIncrement(&FastMutex->Count) <= 0)
+    {
+        /* Someone was waiting for it, signal the waiter */
+        KeSetEventBoostPriority(&FastMutex->Gate, IO_NO_INCREMENT);
+    }
+
+    /* Lower IRQL back */
+    KfLowerIrql(FastMutex->OldIrql);
+}
+
+BOOLEAN
+FASTCALL
+ExTryToAcquireFastMutex(PFAST_MUTEX FastMutex)
 {
-  KeEnterCriticalRegion();
-  if (InterlockedExchange(&FastMutex->Count, 0) == 1)
+    KIRQL OldIrql;
+
+    /* Raise to APC_LEVEL */
+    OldIrql = KfRaiseIrql(APC_LEVEL);
+
+    /* Check if we can quickly acquire it */
+    if (InterlockedCompareExchange(&FastMutex->Count, 0, 1) == 1)
     {
-      FastMutex->Owner = KeGetCurrentThread();
-      return(TRUE);
+        /* We have, set us as owners */
+        FastMutex->Owner = KeGetCurrentThread();
+        FastMutex->OldIrql = OldIrql;
+        return TRUE;
     }
-  else
+    else
     {
-      KeLeaveCriticalRegion();
-      return(FALSE);
+        /* Acquire attempt failed */
+        KfLowerIrql(OldIrql);
+        return FALSE;
     }
 }