Nuke Old Mutex Implementation

To many changes to make , so i just updated with my recent iteration.

Signed-off-by: CodingWorkshop Signing Team <signing@codingworkshop.eu.org>
This commit is contained in:
2025-09-25 14:57:10 +02:00
committed by CodingWorkshop Signing Team
parent cb3a90c637
commit 58ba3f5db0

View File

@@ -3,20 +3,20 @@
* LICENSE: BSD Clause 3 * LICENSE: BSD Clause 3
* PURPOSE: Mutexes * PURPOSE: Mutexes
* NT KERNEL: 5.11.9360 * NT KERNEL: 5.11.9360
* COPYRIGHT: 2023-2029 Dibymartanda Samanta <> * COPYRIGHT: 2023-2029 Dibymartanda Samanta <dibya.samanta@neverseen.de>
*/ */
#include <ntoskrnl.h> #include <ntoskrnl.h>
#define NTDEBUG #define NTDEBUG
extern "C" extern "C"
/*Mutex Count :
0 => Can Be aquired,
1 => Is Aquired by a Thread
In Negative Indigates, Number of Threads waiting*/
constexpr ULONG MUTEX_READY_TO_BE_AQUIRED = 0; /*Mutex Count :
0 => Can Be acquired,
1 => Is Acquired by a Thread
In Negative Indicates, Number of Threads waiting*/
constexpr ULONG MUTEX_READY_TO_BE_ACQUIRED = 0;
/*Internal Function*/ /*Internal Function*/
@@ -37,93 +37,76 @@ typedef struct _FAST_MUTEX {
typedef PFAST_MUTEX PKGUARDED_MUTEX; typedef PFAST_MUTEX PKGUARDED_MUTEX;
/*Internal Functio*/ /*Internal Function*/
VOID VOID
FASTCALL FASTCALL
KiAcquireFastMutex( KiAcquireFastMutex(
_Inout_ PFAST_MUTEX Mutex _Inout_ PFAST_MUTEX Mutex
) )
{ {
LONG AcquireMarker = {0}; LONG OldCount;
LONG AcquireBit = {0}; LONG NewCount;
LONG OldCount = {0};
PAGED_CODE(); PAGED_CODE();
/* Increment contention count */ /* Increment contention count */
InterlockedIncrement(&Mutex->Contention); InterlockedIncrement(&Mutex->Contention);
/* Initialize loop variables */ while (TRUE)
AcquireMarker = 4;
AcquireBit = 1;
while(true)
{ {
/* Read current count */ /* Read current count */
OldCount = ReadForWriteAccess(&Mutex->Count); OldCount = ReadForWriteAccess(&Mutex->Count);
/* Check if mutex is free */ /* Check if mutex is free (count == 0) */
if ((OldCount & 1) == 0) if (OldCount == 0)
{ {
/* Attempt to acquire by incrementing count */ /* Attempt to acquire by setting count to 1 */
if (InterlockedCompareExchange(&Mutex->Count, OldCount + AcquireMarker,OldCount) == OldCount) if (InterlockedCompareExchange(&Mutex->Count, 1, 0) == 0)
{
/* Wait for the mutex event */
KeWaitForSingleObject(&Mutex->Event,WrFastMutex,KernelMode,false,0);
AcquireMarker = 2;
AcquireBit = 3;
continue;
}
}
else
{
/* Attempt to mark mutex as owned */
if (InterlockedCompareExchange(&Mutex->Count, AcquireBit ^ OldCount,OldCount) == OldCount)
{ {
/* Mutex acquired successfully */ /* Mutex acquired successfully */
break; break;
} }
} }
else
{
/* Mutex is owned, increment waiter count (make it more negative) */
NewCount = OldCount - 1;
if (InterlockedCompareExchange(&Mutex->Count, NewCount, OldCount) == OldCount)
{
/* Wait for the mutex event */
KeWaitForSingleObject(&Mutex->Event, WrFastMutex, KernelMode, FALSE, NULL);
/* Continue loop to try acquiring again */
}
}
} }
} }
VOID
FASTCALL FASTCALL
KeReleaseFastMutexContended( KeReleaseFastMutexContended(
IN PFAST_MUTEX FastMutex, IN PFAST_MUTEX FastMutex,
IN LONG OldValue) IN LONG OldValue)
{ {
BOOLEAN WakeWaiter = false; LONG NewValue;
LONG NewValue = {0};
PKTHREAD WokenThread = nullptr;
KPRIORITY HandoffPriority = {0};
/* Loop until we successfully update the mutex state */ /* If there are waiters (negative count), wake one up */
for (;;) if (OldValue < 0)
{ {
WakeWaiter = false; /* Increment count (reduce number of waiters) but keep it owned */
NewValue = OldValue + FM_LOCK_BIT; NewValue = OldValue + 1;
if (NewValue == 0)
if (!(OldValue & FM_LOCK_WAITER_WOKEN))
{ {
NewValue = OldValue - FM_LOCK_BIT; /* No more waiters, mutex becomes free */
WakeWaiter = true; NewValue = 0;
} }
LONG PreviousValue = InterlockedCompareExchange(&FastMutex->Lock, NewValue, OldValue); if (InterlockedCompareExchange(&FastMutex->Count, NewValue, OldValue) == OldValue)
if (PreviousValue == OldValue)
break;
OldValue = PreviousValue;
}
if (WakeWaiter)
{ {
/* Wake up a waiter */ /* Wake up a waiter */
KeSetEventBoostPriority(&FastMutex->Event); KeSetEvent(&FastMutex->Event, IO_NO_INCREMENT, FALSE);
}
} }
} }
/* Exported Function */ /* Exported Function */
@@ -133,14 +116,14 @@ KeInitializeFastMutex(
_Out_ PFAST_MUTEX Mutex _Out_ PFAST_MUTEX Mutex
) )
{ {
/* Initialize the mutex structure */ /* Initialize the mutex structure */
RtlZeroMemory(Mutex, sizeof(FAST_MUTEX)); RtlZeroMemory(Mutex, sizeof(FAST_MUTEX));
/* Set initial values */ /* Set initial values - 0 means free/available */
Mutex->Owner = nullptr; Mutex->Owner = NULL;
Mutex->Contention = 0; Mutex->Contention = 0;
Mutex->Count = 1; Mutex->Count = 0; // 0 = free
Mutex->RecursionDepth = 0;
/* Initialize the Mutex Gate */ /* Initialize the Mutex Gate */
KeInitializeEvent(&Mutex->Event, SynchronizationEvent, FALSE); KeInitializeEvent(&Mutex->Event, SynchronizationEvent, FALSE);
@@ -151,23 +134,25 @@ VECTORCALL
KeTryToAcquireFastMutex( KeTryToAcquireFastMutex(
_Inout_ PFAST_MUTEX Mutex) _Inout_ PFAST_MUTEX Mutex)
{ {
KIRQL CurrentIrql = KeGetCurrentIrql(); KIRQL OldIrql;
BOOLEAN Result = false;
if(_InterlockedBitTestAndReset(&FastMutex->Count, MUTEX_READY_TO_BE_AQUIRED)) /* Raise IRQL to APC_LEVEL */
OldIrql = KeRaiseIrqlToSynchLevel();
/* Try to acquire the mutex atomically */
if (InterlockedCompareExchange(&Mutex->Count, 1, 0) == 0)
{ {
FastMutex->Owner = (PVOID)KeGetCurrentThread(); /* Successfully acquired */
Mutex->OldIrql = KeRaiseIrql(APC_LEVEL); Mutex->Owner = (PVOID)KeGetCurrentThread();
Result = TRUE; Mutex->OldIrql = OldIrql;
return TRUE;
} }
else else
{ {
/* Failed to acquire the mutex */ /* Failed to acquire the mutex */
KeLowerIrql(CurrentIrql); KeLowerIrql(OldIrql);
KeYieldProcessor(); return FALSE;
Result = FALSE;
} }
return Result;
} }
VOID VOID
@@ -175,24 +160,21 @@ NTAPI
KeEnterCriticalRegionAndAcquireFastMutexUnsafe( KeEnterCriticalRegionAndAcquireFastMutexUnsafe(
_In_ PFAST_MUTEX FastMutex) _In_ PFAST_MUTEX FastMutex)
{ {
PKTHREAD OwnerThread = nullptr; PKTHREAD OwnerThread;
KeEnterCriticalRegion(); KeEnterCriticalRegion();
/* Get the current thread again (following the pseudocode) */ /* Get the current thread */
OwnerThread = KeGetCurrentThread(); OwnerThread = KeGetCurrentThread();
/* Try to acquire the FastMutex */ /* Try to acquire the FastMutex */
if (_InterlockedBitTestAndReset(&FastMutex->Lock, 0)) if (InterlockedCompareExchange(&FastMutex->Count, 1, 0) != 0)
{
/* FastMutex was free, we acquired it */
FastMutex->Owner = OwnerThread;
}
else
{ {
/* FastMutex was locked, we need to wait */ /* FastMutex was locked, we need to wait */
KiAcquireFastMutex(FastMutex); KiAcquireFastMutex(FastMutex);
FastMutex->Owner = OwnerThread;
} }
FastMutex->Owner = OwnerThread;
} }
VOID VOID
@@ -200,38 +182,36 @@ FASTCALL
KeReleaseFastMutexUnsafeAndLeaveCriticalRegion( KeReleaseFastMutexUnsafeAndLeaveCriticalRegion(
_In_ PFAST_MUTEX FastMutex) _In_ PFAST_MUTEX FastMutex)
{ {
LONG OldValue = {0}; LONG OldValue;
PKTHREAD CurrentThread = nullptr ;
SHORT NewValue ={0};
/* Clear the owner */ /* Clear the owner */
FastMutex->Owner = nullptr; FastMutex->Owner = NULL;
/* Try to release the FastMutex */ /* Release the FastMutex */
OldValue = InterlockedCompareExchange(&FastMutex->Lock, 1, 0); OldValue = InterlockedExchange(&FastMutex->Count, 0);
if (OldValue != 0)
if (OldValue < 0)
{ {
/* Contended case, call the contended release function */ /* There were waiters, call the contended release function */
KeReleaseFastMutexContended(FastMutex, OldValue); KeReleaseFastMutexContended(FastMutex, OldValue);
} }
/* leave critical region*/ /* Leave critical region */
KeLeaveCriticalRegion(); KeLeaveCriticalRegion();
} }
VOID VOID
NTAPI NTAPI
KeAcquireFastMutex( KeAcquireFastMutex(
_In_ PFAST_MUTEX FastMutex) _In_ PFAST_MUTEX FastMutex)
{ {
KIRQL OldIrql = {0}; KIRQL OldIrql;
/* Raise IRQL to APC_LEVEL */ /* Raise IRQL to APC_LEVEL */
OldIrql = KeRaiseIrqlToSynchLevel(); OldIrql = KeRaiseIrqlToSynchLevel();
/* Try to acquire the FastMutex */ /* Try to acquire the FastMutex */
if (InterlockedBitTestAndReset(&FastMutex->Lock, 0) == 0) if (InterlockedCompareExchange(&FastMutex->Count, 1, 0) != 0)
{ {
/* We didn't acquire it, we'll have to wait */ /* We didn't acquire it, we'll have to wait */
KiAcquireFastMutex(FastMutex); KiAcquireFastMutex(FastMutex);
@@ -247,13 +227,13 @@ NTAPI
KeAcquireFastMutexUnsafe( KeAcquireFastMutexUnsafe(
_In_ PFAST_MUTEX FastMutex) _In_ PFAST_MUTEX FastMutex)
{ {
PKTHREAD CurrentThread = nullptr; PKTHREAD CurrentThread;
/* Get the current thread */ /* Get the current thread */
CurrentThread = KeGetCurrentThread(); CurrentThread = KeGetCurrentThread();
/* Try to acquire the FastMutex */ /* Try to acquire the FastMutex */
if (!InterlockedBitTestAndReset(&FastMutex->Lock, 0)) if (InterlockedCompareExchange(&FastMutex->Count, 1, 0) != 0)
{ {
/* FastMutex was locked, we need to wait */ /* FastMutex was locked, we need to wait */
KiAcquireFastMutex(FastMutex); KiAcquireFastMutex(FastMutex);
@@ -269,21 +249,24 @@ KeReleaseFastMutex(
_Inout_ PFAST_MUTEX FastMutex _Inout_ PFAST_MUTEX FastMutex
) )
{ {
KIRQL OldIrql ={0}; KIRQL OldIrql;
LONG OldCount ={0}; LONG OldCount;
FastMutex->Owner = nullptr; /* Clear owner and get saved IRQL */
FastMutex->Owner = NULL;
OldIrql = FastMutex->OldIrql; OldIrql = FastMutex->OldIrql;
OldCount = InterlockedExchangeAdd(&FastMutex->Count, 1); /* Release the mutex */
OldCount = InterlockedExchange(&FastMutex->Count, 0);
if (OldCount != 0 && /* Check if there were waiters */
(OldCount & 2) == 0 && if (OldCount < 0)
InterlockedCompareExchange(&FastMutex->Count, OldCount - 1, OldCount + 1) == OldCount + 1)
{ {
/* Wake up waiters */
KeSetEvent(&FastMutex->Event, IO_NO_INCREMENT, FALSE); KeSetEvent(&FastMutex->Event, IO_NO_INCREMENT, FALSE);
} }
/* Restore IRQL */
KeLowerIrql(OldIrql); KeLowerIrql(OldIrql);
} }
@@ -292,31 +275,21 @@ NTAPI
KeReleaseFastMutexUnsafe( KeReleaseFastMutexUnsafe(
_In_ PFAST_MUTEX FastMutex) _In_ PFAST_MUTEX FastMutex)
{ {
LONG OldValue = {0}; LONG OldValue;
/* Clear the owner */ /* Clear the owner */
FastMutex->Owner = nullptr; FastMutex->Owner = NULL;
/* Release the lock and get the old value */ /* Release the lock and get the old value */
OldValue = InterlockedExchangeAdd(&FastMutex->Lock, 1); OldValue = InterlockedExchange(&FastMutex->Count, 0);
/* Check if there were waiters */ /* Check if there were waiters */
if (OldValue != 0) if (OldValue < 0)
{ {
/* Check if no waiter has been woken up yet */ /* Wake up waiters */
if ((OldValue & FM_LOCK_WAITER_WOKEN) == 0)
{
/* Try to wake up a waiter */
if (OldValue + 1 == InterlockedCompareExchange(&FastMutex->Lock,
OldValue - 1,
OldValue + 1))
{
/* Wake up one waiter */
KeSetEvent(&FastMutex->Event, IO_NO_INCREMENT, FALSE); KeSetEvent(&FastMutex->Event, IO_NO_INCREMENT, FALSE);
} }
} }
}
}
/*Guarded Mutexes in Modern NT behave just like Fast Mutexes with bit of protection */ /*Guarded Mutexes in Modern NT behave just like Fast Mutexes with bit of protection */
@@ -325,11 +298,13 @@ NTAPI
KeInitializeGuardedMutex(_Out_ PKGUARDED_MUTEX GuardedMutex) KeInitializeGuardedMutex(_Out_ PKGUARDED_MUTEX GuardedMutex)
{ {
/* Initialize the GuardedMutex */ /* Initialize the GuardedMutex */
GuardedMutex->Count = 1; GuardedMutex->Count = 0; // 0 = free
GuardedMutex->Owner = nullptr; GuardedMutex->Owner = NULL;
GuardedMutex->Contention = 0; GuardedMutex->Contention = 0;
GuardedMutex->RecursionDepth = 0;
/* Initialize the Mutex Gate */ /* Initialize the Mutex Gate */
KeInitializeEvent(&Mutex->Event, SynchronizationEvent, FALSE); KeInitializeEvent(&GuardedMutex->Event, SynchronizationEvent, FALSE);
} }
VOID VOID
@@ -337,10 +312,19 @@ NTAPI
KeAcquireGuardedMutex(_Inout_ PKGUARDED_MUTEX Mutex) KeAcquireGuardedMutex(_Inout_ PKGUARDED_MUTEX Mutex)
{ {
PKTHREAD OwnerThread = KeGetCurrentThread(); PKTHREAD OwnerThread = KeGetCurrentThread();
KIRQL OldIrql;
/* Raise IRQL and enter guarded region */
OldIrql = KeRaiseIrqlToSynchLevel();
KeEnterGuardedRegion(); KeEnterGuardedRegion();
if (!_Interlockedbittestandreset(&Mutex->Count, 0) )
if (InterlockedCompareExchange(&Mutex->Count, 1, 0) != 0)
{
KiAcquireFastMutex(Mutex); KiAcquireFastMutex(Mutex);
}
Mutex->Owner = OwnerThread; Mutex->Owner = OwnerThread;
Mutex->OldIrql = OldIrql;
} }
VOID VOID
@@ -349,11 +333,12 @@ KeAcquireGuardedMutexUnsafe(
_Inout_ PKGUARDED_MUTEX FastMutex _Inout_ PKGUARDED_MUTEX FastMutex
) )
{ {
PKTHREAD CurrentThread = nullptr; PKTHREAD CurrentThread;
KeEnterGuardedRegion(); KeEnterGuardedRegion();
CurrentThread = KeGetCurrentThread(); CurrentThread = KeGetCurrentThread();
if (!_InterlockedBitTestAndReset(&FastMutex->Count, 0)) if (InterlockedCompareExchange(&FastMutex->Count, 1, 0) != 0)
{ {
KiAcquireFastMutex(FastMutex); KiAcquireFastMutex(FastMutex);
} }
@@ -367,18 +352,17 @@ KeReleaseGuardedMutexUnsafe(
_Inout_ PKGUARDED_MUTEX FastMutex _Inout_ PKGUARDED_MUTEX FastMutex
) )
{ {
LONG OldCount ={0}; LONG OldCount;
FastMutex->Owner = nullptr; FastMutex->Owner = NULL;
OldCount = _InterlockedExchangeAdd(&FastMutex->Count, 1); OldCount = InterlockedExchange(&FastMutex->Count, 0);
if (OldCount != 0 && if (OldCount < 0)
(OldCount & FM_LOCK_WAITER_WOKEN) == 0 &&
OldCount + 1 == InterlockedCompareExchange(&FastMutex->Count, OldCount - 1, OldCount + 1))
{ {
KeSetEvent(&FastMutex->Event, IO_NO_INCREMENT, FALSE); KeSetEvent(&FastMutex->Event, IO_NO_INCREMENT, FALSE);
} }
KeLeaveGuardedRegion(); KeLeaveGuardedRegion();
} }
@@ -387,57 +371,299 @@ NTAPI
KeReleaseGuardedMutex( KeReleaseGuardedMutex(
_In_ PKGUARDED_MUTEX FastMutex) _In_ PKGUARDED_MUTEX FastMutex)
{ {
KIRQL OldIrql ={0}; KIRQL OldIrql;
LONG OldValue ={0}; LONG OldValue;
/* Save the old IRQL and clear the owner */ /* Save the old IRQL and clear the owner */
OldIrql = FastMutex->OldIrql; OldIrql = FastMutex->OldIrql;
FastMutex->Owner = nullptr; FastMutex->Owner = NULL;
/* Try to release the FastMutex */ /* Try to release the FastMutex */
OldValue = _InterlockedExchangeAdd(&Mutex->Count, 1); OldValue = InterlockedExchange(&FastMutex->Count, 0);
if (OldCount != 0 &&
(OldCount & FM_LOCK_WAITER_WOKEN) == 0 && if (OldValue < 0)
OldCount + 1 == InterlockedCompareExchange(&FastMutex->Count, OldCount - 1, OldCount + 1))
{ {
KeSetEvent(&FastMutex->Event, IO_NO_INCREMENT, FALSE); KeSetEvent(&FastMutex->Event, IO_NO_INCREMENT, FALSE);
} }
/* Lower IRQL */ /* Lower IRQL and leave guarded region */
KeLowerIrql(OldIrql); KeLowerIrql(OldIrql);
KeLeaveGuardedRegion(); KeLeaveGuardedRegion();
} }
/* Specific to Alcyone, Not found in Windows NT */ /* Specific to Alcyone, Not found in Windows NT */
VOID NTAPI KeInitializeRecursiveFastMutex(_Out_ PFAST_MUTEX Mutex) { VOID
NTAPI
KeInitializeRecursiveFastMutex(_Out_ PFAST_MUTEX Mutex)
{
KeInitializeFastMutex(Mutex); KeInitializeFastMutex(Mutex);
Mutex->Count |= FM_RECURSIVE_BIT; /* Mark as recursive by setting the recursive bit in a separate field */
Mutex->RecursionDepth = -1; // Use -1 to indicate recursive capability
} }
NTSTATUS NTAPI KeAcquireFastMutexTimeout(_Inout_ PFAST_MUTEX Mutex, _In_ PLARGE_INTEGER Timeout) { NTSTATUS
if (KeTryToAcquireFastMutex(Mutex)) { NTAPI
KeAcquireFastMutexTimeout(_Inout_ PFAST_MUTEX Mutex, _In_ PLARGE_INTEGER Timeout)
{
KIRQL OldIrql;
NTSTATUS Status;
/* Raise IRQL */
OldIrql = KeRaiseIrqlToSynchLevel();
/* Try to acquire immediately */
if (InterlockedCompareExchange(&Mutex->Count, 1, 0) == 0)
{
Mutex->Owner = KeGetCurrentThread();
Mutex->OldIrql = OldIrql;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
NTSTATUS Status = KeWaitForSingleObject(&Mutex->Event, WrFastMutex, KernelMode, FALSE, Timeout);
if (Status == STATUS_SUCCESS) { /* Increment waiter count */
KiAcquireFastMutex(Mutex); InterlockedDecrement(&Mutex->Count);
/* Wait with timeout */
Status = KeWaitForSingleObject(&Mutex->Event, WrFastMutex, KernelMode, FALSE, Timeout);
if (Status == STATUS_SUCCESS)
{
/* Try to acquire after being woken up */
if (InterlockedCompareExchange(&Mutex->Count, 1, 0) == 0)
{
Mutex->Owner = KeGetCurrentThread();
Mutex->OldIrql = OldIrql;
} }
else
{
/* Someone else got it, this shouldn't happen normally */
KeLowerIrql(OldIrql);
Status = STATUS_TIMEOUT;
}
}
else
{
/* Timeout or other error - remove ourselves from waiter count */
InterlockedIncrement(&Mutex->Count);
KeLowerIrql(OldIrql);
}
return Status; return Status;
} }
BOOLEAN NTAPI KeIsMutexOwned(_In_ PFAST_MUTEX Mutex) { BOOLEAN
NTAPI
KeIsMutexOwned(_In_ PFAST_MUTEX Mutex)
{
return (Mutex->Owner == KeGetCurrentThread()); return (Mutex->Owner == KeGetCurrentThread());
} }
NTSTATUS NTAPI KeAcquireGuardedMutexTimeout(_Inout_ PKGUARDED_MUTEX Mutex, _In_ PLARGE_INTEGER Timeout) { NTSTATUS
NTAPI
KeAcquireGuardedMutexTimeout(_Inout_ PKGUARDED_MUTEX Mutex, _In_ PLARGE_INTEGER Timeout)
{
KIRQL OldIrql;
NTSTATUS Status;
/* Raise IRQL and enter guarded region */
OldIrql = KeRaiseIrqlToSynchLevel();
KeEnterGuardedRegion(); KeEnterGuardedRegion();
NTSTATUS Status = KeAcquireFastMutexTimeout(Mutex, Timeout);
if (Status != STATUS_SUCCESS) { /* Try to acquire immediately */
if (InterlockedCompareExchange(&Mutex->Count, 1, 0) == 0)
{
Mutex->Owner = KeGetCurrentThread();
Mutex->OldIrql = OldIrql;
return STATUS_SUCCESS;
}
/* Increment waiter count */
InterlockedDecrement(&Mutex->Count);
/* Wait with timeout */
Status = KeWaitForSingleObject(&Mutex->Event, WrGuardedMutex, KernelMode, FALSE, Timeout);
if (Status == STATUS_SUCCESS)
{
/* Try to acquire after being woken up */
if (InterlockedCompareExchange(&Mutex->Count, 1, 0) == 0)
{
Mutex->Owner = KeGetCurrentThread();
Mutex->OldIrql = OldIrql;
}
else
{
/* Someone else got it, this shouldn't happen normally */
KeLowerIrql(OldIrql);
KeLeaveGuardedRegion();
Status = STATUS_TIMEOUT;
}
}
else
{
/* Timeout or other error - remove ourselves from waiter count */
InterlockedIncrement(&Mutex->Count);
KeLowerIrql(OldIrql);
KeLeaveGuardedRegion(); KeLeaveGuardedRegion();
} }
return Status; return Status;
} }
/* Additional Alcyone-specific recursive mutex functions */
VOID
NTAPI
KeAcquireRecursiveFastMutex(_Inout_ PFAST_MUTEX Mutex)
{
PKTHREAD CurrentThread = KeGetCurrentThread();
KIRQL OldIrql;
/* Check if this is a recursive mutex */
if (Mutex->RecursionDepth == -1)
{
/* Check if current thread already owns it */
if (Mutex->Owner == CurrentThread)
{
/* Increment recursion depth */
InterlockedIncrement(&Mutex->RecursionDepth);
return;
}
}
/* Not recursive or not owned by current thread - acquire normally */
OldIrql = KeRaiseIrqlToSynchLevel();
if (InterlockedCompareExchange(&Mutex->Count, 1, 0) != 0)
{
KiAcquireFastMutex(Mutex);
}
Mutex->Owner = CurrentThread;
Mutex->OldIrql = OldIrql;
/* Set recursion depth to 1 for recursive mutexes */
if (Mutex->RecursionDepth == -1)
{
Mutex->RecursionDepth = 1;
}
}
VOID
NTAPI
KeReleaseRecursiveFastMutex(_Inout_ PFAST_MUTEX Mutex)
{
PKTHREAD CurrentThread = KeGetCurrentThread();
KIRQL OldIrql;
LONG OldCount;
/* Verify ownership */
if (Mutex->Owner != CurrentThread)
{
KeBugCheckEx(MUTEX_LEVEL_NUMBER_VIOLATION,
(ULONG_PTR)Mutex,
(ULONG_PTR)CurrentThread,
(ULONG_PTR)Mutex->Owner,
0);
return;
}
/* Handle recursive case */
if (Mutex->RecursionDepth > 1)
{
InterlockedDecrement(&Mutex->RecursionDepth);
return;
}
/* Clear owner and get saved IRQL */
Mutex->Owner = NULL;
OldIrql = Mutex->OldIrql;
/* Reset recursion depth for recursive mutexes */
if (Mutex->RecursionDepth != 0)
{
Mutex->RecursionDepth = -1; // Mark as recursive but not owned
}
/* Release the mutex */
OldCount = InterlockedExchange(&Mutex->Count, 0);
/* Check if there were waiters */
if (OldCount < 0)
{
KeSetEvent(&Mutex->Event, IO_NO_INCREMENT, FALSE);
}
/* Restore IRQL */
KeLowerIrql(OldIrql);
}
/* Utility functions for debugging and monitoring */
ULONG
NTAPI
KeGetMutexContentionCount(_In_ PFAST_MUTEX Mutex)
{
return Mutex->Contention;
}
PKTHREAD
NTAPI
KeGetMutexOwner(_In_ PFAST_MUTEX Mutex)
{
return (PKTHREAD)Mutex->Owner;
}
LONG
NTAPI
KeGetMutexRecursionDepth(_In_ PFAST_MUTEX Mutex)
{
return Mutex->RecursionDepth;
}
BOOLEAN
NTAPI
KeIsMutexRecursive(_In_ PFAST_MUTEX Mutex)
{
return (Mutex->RecursionDepth == -1 || Mutex->RecursionDepth > 0);
}
/* Enhanced try-acquire with recursion support */
BOOLEAN
NTAPI
KeTryToAcquireRecursiveFastMutex(_Inout_ PFAST_MUTEX Mutex)
{
PKTHREAD CurrentThread = KeGetCurrentThread();
KIRQL OldIrql;
/* Check if this is a recursive mutex and current thread owns it */
if (Mutex->RecursionDepth != 0 && Mutex->Owner == CurrentThread)
{
/* Increment recursion depth */
InterlockedIncrement(&Mutex->RecursionDepth);
return TRUE;
}
/* Try normal acquisition */
OldIrql = KeRaiseIrqlToSynchLevel();
if (InterlockedCompareExchange(&Mutex->Count, 1, 0) == 0)
{
Mutex->Owner = CurrentThread;
Mutex->OldIrql = OldIrql;
/* Set recursion depth to 1 for recursive mutexes */
if (Mutex->RecursionDepth == -1)
{
Mutex->RecursionDepth = 1;
}
return TRUE;
}
else
{
KeLowerIrql(OldIrql);
return FALSE;
}
}