/*
- * ReactOS kernel
- * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/* $Id: fmutex.c,v 1.21 2004/08/15 16:39:01 chorns Exp $
- *
- * PROJECT: ReactOS kernel
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Kernel
* FILE: ntoskrnl/ex/fmutex.c
* PURPOSE: Implements fast mutexes
- * PROGRAMMER: David Welch (welch@cwcom.net)
- * PORTABILITY: Checked.
- * UPDATE HISTORY:
- * Created 22/05/98
+ * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#include <internal/debug.h>
+VOID
+FASTCALL
+KiAcquireFastMutex(IN PFAST_MUTEX FastMutex);
+
/* FUNCTIONS *****************************************************************/
/*
* @implemented
*/
-VOID FASTCALL
+VOID
+FASTCALL
+ExEnterCriticalRegionAndAcquireFastMutexUnsafe(PFAST_MUTEX 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;
+}
+
+/*
+ * @implemented
+ */
+VOID
+FASTCALL
+ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(PFAST_MUTEX FastMutex)
+{
+ 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();
+}
+
+/*
+ * @implemented
+ */
+VOID
+FASTCALL
+ExAcquireFastMutex(PFAST_MUTEX FastMutex)
+{
+ 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;
+}
+
+/*
+ * @implemented
+ */
+VOID
+FASTCALL
+ExReleaseFastMutex (PFAST_MUTEX FastMutex)
+{
+ 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);
+}
+
+/*
+ * @implemented
+ */
+VOID
+FASTCALL
ExAcquireFastMutexUnsafe(PFAST_MUTEX FastMutex)
{
- assert(FastMutex->Owner != KeGetCurrentThread());
- InterlockedIncrement((LONG *)&FastMutex->Contention);
- while (InterlockedExchange(&FastMutex->Count, 0) == 0)
- {
- KeWaitForSingleObject(&FastMutex->Event,
- Executive,
- KernelMode,
- FALSE,
- NULL);
- }
- InterlockedDecrement((LONG *)&FastMutex->Contention);
- FastMutex->Owner = KeGetCurrentThread();
+ 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;
}
/*
* @implemented
*/
-VOID FASTCALL
+VOID
+FASTCALL
ExReleaseFastMutexUnsafe(PFAST_MUTEX FastMutex)
{
- assert(FastMutex->Owner == KeGetCurrentThread());
- FastMutex->Owner = NULL;
- InterlockedExchange(&FastMutex->Count, 1);
- if (FastMutex->Contention > 0)
+ 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
{
- KeSetEvent(&FastMutex->Event, 0, FALSE);
+ /* Acquire attempt failed */
+ KfLowerIrql(OldIrql);
+ return FALSE;
}
}