Save the old irql in ExTryToAcquireFastMutex.
[reactos.git] / reactos / ntoskrnl / ex / fmutex.c
index 7c915f4..6b229e2 100644 (file)
 /*
  * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
+ * PROJECT:         ReactOS Kernel
  * FILE:            ntoskrnl/ex/fmutex.c
  * PURPOSE:         Implements fast mutexes
- * PROGRAMMER:      David Welch (welch@cwcom.net)
- * UPDATE HISTORY:
- *                  Created 22/05/98
+ * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
  */
 
 /* INCLUDES *****************************************************************/
 
-#include <ddk/ntddk.h>
-
+#include <ntoskrnl.h>
 #include <internal/debug.h>
 
+VOID
+FASTCALL
+KiAcquireFastMutex(IN PFAST_MUTEX FastMutex);
+
 /* FUNCTIONS *****************************************************************/
 
-VOID ExAcquireFastMutex(PFAST_MUTEX FastMutex)
+/*
+ * @implemented
+ */
+VOID
+FASTCALL
+ExEnterCriticalRegionAndAcquireFastMutexUnsafe(PFAST_MUTEX FastMutex)
 {
-   KeEnterCriticalRegion();
-   ExAcquireFastMutexUnsafe(FastMutex);
+    PKTHREAD Thread = KeGetCurrentThread();
+
+    /* Enter the Critical Region */
+    KeEnterCriticalRegion();
+    ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
+           (Thread == NULL) ||
+           (Thread->CombinedApcDisable != 0) ||
+           (Thread->Teb == NULL) ||
+           (Thread->Teb >= (PTEB)MM_SYSTEM_RANGE_START));
+    ASSERT((Thread == NULL) || (FastMutex->Owner != Thread));
+
+    /* Decrease the count */
+    if (InterlockedDecrement(&FastMutex->Count))
+    {
+        /* Someone is still holding it, use slow path */
+        KiAcquireFastMutex(FastMutex);
+    }
+
+    /* Set the owner */
+    FastMutex->Owner = Thread;
 }
 
-VOID ExAcquireFastMutexUnsafe(PFAST_MUTEX FastMutex)
+/*
+ * @implemented
+ */
+VOID
+FASTCALL
+ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(PFAST_MUTEX FastMutex)
 {
-   if (InterlockedDecrement(&(FastMutex->Count))==0)
-     {
-       return;
-     }
-   FastMutex->Contention++;
-   KeWaitForSingleObject(&(FastMutex->Event),
-                        Executive,
-                        KernelMode,
-                        FALSE,
-                        NULL);
-   FastMutex->Owner=KeGetCurrentThread();
+    ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
+           (KeGetCurrentThread() == NULL) ||
+           (KeGetCurrentThread()->CombinedApcDisable != 0) ||
+           (KeGetCurrentThread()->Teb == NULL) ||
+           (KeGetCurrentThread()->Teb >= (PTEB)MM_SYSTEM_RANGE_START));
+    ASSERT(FastMutex->Owner == KeGetCurrentThread());
+  
+    /* Erase the owner */
+    FastMutex->Owner = NULL;
+
+    /* Increase the count */
+    if (InterlockedIncrement(&FastMutex->Count) <= 0)
+    {
+        /* Someone was waiting for it, signal the waiter */
+        KeSetEventBoostPriority(&FastMutex->Gate, IO_NO_INCREMENT);
+    }
+
+    /* Leave the critical region */
+    KeLeaveCriticalRegion();
 }
 
-VOID ExInitializeFastMutex(PFAST_MUTEX FastMutex)
+/*
+ * @implemented
+ */
+VOID
+FASTCALL
+ExAcquireFastMutex(PFAST_MUTEX FastMutex)
 {
-   FastMutex->Count=1;
-   FastMutex->Owner=NULL;
-   FastMutex->Contention=0;
-   KeInitializeEvent(&(FastMutex->Event),
-                    SynchronizationEvent,
-                    FALSE);
+    KIRQL OldIrql;
+    ASSERT_IRQL_LESS_OR_EQUAL(APC_LEVEL);
+
+    /* Raise IRQL to APC */
+    OldIrql = KfRaiseIrql(APC_LEVEL);
+   
+    /* Decrease the count */
+    if (InterlockedDecrement(&FastMutex->Count))
+    {
+        /* Someone is still holding it, use slow path */
+        KiAcquireFastMutex(FastMutex);
+    }
+
+    /* Set the owner and IRQL */
+    FastMutex->Owner = KeGetCurrentThread();
+    FastMutex->OldIrql = OldIrql;
 }
 
-VOID ExReleaseFastMutexUnsafe(PFAST_MUTEX FastMutex)
+/*
+ * @implemented
+ */
+VOID
+FASTCALL
+ExReleaseFastMutex (PFAST_MUTEX FastMutex)
 {
-   assert(FastMutex->Owner == KeGetCurrentThread());
-   FastMutex->Owner=NULL;
-   if (InterlockedIncrement(&(FastMutex->Count))<=0)
-     {
-       return;
-     }      
-   KeSetEvent(&(FastMutex->Event),0,FALSE);
+    ASSERT_IRQL(APC_LEVEL);
+
+    /* Erase the owner */
+    FastMutex->Owner = NULL;
+
+    /* 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);
 }
 
-VOID ExReleaseFastMutex(PFAST_MUTEX FastMutex)
+/*
+ * @implemented
+ */
+VOID
+FASTCALL
+ExAcquireFastMutexUnsafe(PFAST_MUTEX FastMutex)
 {
-   ExReleaseFastMutexUnsafe(FastMutex);
-   KeLeaveCriticalRegion();
+    PKTHREAD Thread = KeGetCurrentThread();
+    ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
+           (Thread == NULL) ||
+           (Thread->CombinedApcDisable != 0) ||
+           (Thread->Teb == NULL) ||
+           (Thread->Teb >= (PTEB)MM_SYSTEM_RANGE_START));
+    ASSERT((Thread == NULL) || (FastMutex->Owner != Thread));
+
+    /* Decrease the count */
+    if (InterlockedDecrement(&FastMutex->Count))
+    {
+        /* Someone is still holding it, use slow path */
+        KiAcquireFastMutex(FastMutex);
+    }
+
+    /* Set the owner */
+    FastMutex->Owner = Thread;
 }
 
-BOOLEAN ExTryToAcquireFastMutex(PFAST_MUTEX FastMutex)
+/*
+ * @implemented
+ */
+VOID
+FASTCALL
+ExReleaseFastMutexUnsafe(PFAST_MUTEX FastMutex)
 {
-   UNIMPLEMENTED;
+    ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
+           (KeGetCurrentThread() == NULL) ||
+           (KeGetCurrentThread()->CombinedApcDisable != 0) ||
+           (KeGetCurrentThread()->Teb == NULL) ||
+           (KeGetCurrentThread()->Teb >= (PTEB)MM_SYSTEM_RANGE_START));
+    ASSERT(FastMutex->Owner == KeGetCurrentThread());
+  
+    /* Erase the owner */
+    FastMutex->Owner = NULL;
+
+    /* Increase the count */
+    if (InterlockedIncrement(&FastMutex->Count) <= 0)
+    {
+        /* Someone was waiting for it, signal the waiter */
+        KeSetEventBoostPriority(&FastMutex->Gate, IO_NO_INCREMENT);
+    }
 }
 
+/*
+ * @implemented
+ */
+BOOLEAN
+FASTCALL
+ExTryToAcquireFastMutex(PFAST_MUTEX FastMutex)
+{
+    KIRQL OldIrql;
+    ASSERT_IRQL_LESS_OR_EQUAL(APC_LEVEL);
+
+    /* Raise to APC_LEVEL */
+    OldIrql = KfRaiseIrql(APC_LEVEL);
 
+    /* Check if we can quickly acquire it */
+    if (InterlockedCompareExchange(&FastMutex->Count, 0, 1) == 1)
+    {
+        /* We have, set us as owners */
+        FastMutex->Owner = KeGetCurrentThread();
+        FastMutex->OldIrql = OldIrql;
+        return TRUE;
+    }
+    else
+    {
+        /* Acquire attempt failed */
+        KfLowerIrql(OldIrql);
+        return FALSE;
+    }
+}
 
+/* EOF */