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:
committed by
CodingWorkshop Signing Team
parent
cb3a90c637
commit
58ba3f5db0
@@ -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,94 +37,77 @@ 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 */
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
@@ -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,30 +275,20 @@ 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 */
|
||||||
@@ -324,12 +297,14 @@ VOID
|
|||||||
NTAPI
|
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;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user