mirror of
https://github.com/mirror/processhacker
synced 2026-06-08 16:03:24 +00:00
0551d76fe7
* fixed critical bug in PhAcquireQueuedLockSharedFast git-svn-id: svn://svn.code.sf.net/p/processhacker/code@2901 21ef857c-d57f-4fe0-8362-d861dc6d29cd
188 lines
5.0 KiB
C
188 lines
5.0 KiB
C
#ifndef QUEUEDLOCK_H
|
|
#define QUEUEDLOCK_H
|
|
|
|
#define PH_QUEUED_LOCK_OWNED ((ULONG_PTR)0x1)
|
|
#define PH_QUEUED_LOCK_OWNED_SHIFT 0
|
|
#define PH_QUEUED_LOCK_WAITERS ((ULONG_PTR)0x2)
|
|
|
|
// Valid only if Waiters = 0
|
|
#define PH_QUEUED_LOCK_SHARED_INC ((ULONG_PTR)0x4)
|
|
#define PH_QUEUED_LOCK_SHARED_SHIFT 2
|
|
|
|
// Valid only if Waiters = 1
|
|
#define PH_QUEUED_LOCK_TRAVERSING ((ULONG_PTR)0x4)
|
|
#define PH_QUEUED_LOCK_MULTIPLE_SHARED ((ULONG_PTR)0x8)
|
|
|
|
#define PH_QUEUED_LOCK_FLAGS ((ULONG_PTR)0xf)
|
|
|
|
#define PhGetQueuedLockSharedOwners(Value) \
|
|
((ULONG_PTR)(Value) >> PH_QUEUED_LOCK_SHARED_SHIFT)
|
|
#define PhGetQueuedLockWaitBlock(Value) \
|
|
((PPH_QUEUED_WAIT_BLOCK)((ULONG_PTR)(Value) & ~PH_QUEUED_LOCK_FLAGS))
|
|
|
|
typedef struct _PH_QUEUED_LOCK
|
|
{
|
|
ULONG_PTR Value;
|
|
} PH_QUEUED_LOCK, *PPH_QUEUED_LOCK;
|
|
|
|
#define PH_QUEUED_WAITER_EXCLUSIVE 0x1
|
|
#define PH_QUEUED_WAITER_SPINNING 0x2
|
|
#define PH_QUEUED_WAITER_SPINNING_SHIFT 1
|
|
|
|
typedef struct DECLSPEC_ALIGN(16) _PH_QUEUED_WAIT_BLOCK
|
|
{
|
|
/** A pointer to the next wait block, i.e. the
|
|
* wait block pushed onto the list before this
|
|
* one.
|
|
*/
|
|
struct _PH_QUEUED_WAIT_BLOCK *Next;
|
|
/** A pointer to the previous wait block, i.e. the
|
|
* wait block pushed onto the list after this
|
|
* one.
|
|
*/
|
|
struct _PH_QUEUED_WAIT_BLOCK *Previous;
|
|
/** A pointer to the last wait block, i.e. the
|
|
* first waiter pushed onto the list.
|
|
*/
|
|
struct _PH_QUEUED_WAIT_BLOCK *Last;
|
|
|
|
ULONG SharedOwners;
|
|
ULONG Flags;
|
|
} PH_QUEUED_WAIT_BLOCK, *PPH_QUEUED_WAIT_BLOCK;
|
|
|
|
BOOLEAN PhQueuedLockInitialization();
|
|
|
|
FORCEINLINE VOID PhInitializeQueuedLock(
|
|
__out PPH_QUEUED_LOCK QueuedLock
|
|
)
|
|
{
|
|
QueuedLock->Value = 0;
|
|
}
|
|
|
|
#define PhAcquireQueuedLockExclusive PhfAcquireQueuedLockExclusive
|
|
VOID FASTCALL PhfAcquireQueuedLockExclusive(
|
|
__inout PPH_QUEUED_LOCK QueuedLock
|
|
);
|
|
|
|
#define PhAcquireQueuedLockShared PhfAcquireQueuedLockShared
|
|
VOID FASTCALL PhfAcquireQueuedLockShared(
|
|
__inout PPH_QUEUED_LOCK QueuedLock
|
|
);
|
|
|
|
#define PhReleaseQueuedLockExclusive PhfReleaseQueuedLockExclusive
|
|
VOID FASTCALL PhfReleaseQueuedLockExclusive(
|
|
__inout PPH_QUEUED_LOCK QueuedLock
|
|
);
|
|
|
|
#define PhReleaseQueuedLockShared PhfReleaseQueuedLockShared
|
|
VOID FASTCALL PhfReleaseQueuedLockShared(
|
|
__inout PPH_QUEUED_LOCK QueuedLock
|
|
);
|
|
|
|
#define PhTryWakePushLock PhfTryWakePushLock
|
|
VOID FASTCALL PhfTryWakePushLock(
|
|
__inout PPH_QUEUED_LOCK QueuedLock
|
|
);
|
|
|
|
#define PhPulseCondition PhfPulseCondition
|
|
VOID FASTCALL PhfPulseCondition(
|
|
__inout PPH_QUEUED_LOCK Condition
|
|
);
|
|
|
|
#define PhPulseAllCondition PhfPulseAllCondition
|
|
VOID FASTCALL PhfPulseAllCondition(
|
|
__inout PPH_QUEUED_LOCK Condition
|
|
);
|
|
|
|
#define PhWaitForCondition PhfWaitForCondition
|
|
VOID FASTCALL PhfWaitForCondition(
|
|
__inout PPH_QUEUED_LOCK Condition,
|
|
__inout_opt PPH_QUEUED_LOCK Lock,
|
|
__in_opt PLARGE_INTEGER Timeout
|
|
);
|
|
|
|
// Inline functions
|
|
|
|
FORCEINLINE VOID PhAcquireQueuedLockExclusiveFast(
|
|
__inout PPH_QUEUED_LOCK QueuedLock
|
|
)
|
|
{
|
|
#ifdef _M_IX86
|
|
if (_interlockedbittestandset((PLONG)&QueuedLock->Value, PH_QUEUED_LOCK_OWNED_SHIFT))
|
|
#else
|
|
if (_interlockedbittestandset64((PLONG64)&QueuedLock->Value, PH_QUEUED_LOCK_OWNED_SHIFT))
|
|
#endif
|
|
{
|
|
// Owned bit was already set. Slow path.
|
|
PhAcquireQueuedLockExclusive(QueuedLock);
|
|
}
|
|
}
|
|
|
|
FORCEINLINE VOID PhAcquireQueuedLockSharedFast(
|
|
__inout PPH_QUEUED_LOCK QueuedLock
|
|
)
|
|
{
|
|
if ((ULONG_PTR)_InterlockedCompareExchangePointer(
|
|
(PPVOID)&QueuedLock->Value,
|
|
(PVOID)(PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_SHARED_INC),
|
|
(PVOID)0
|
|
) != 0)
|
|
{
|
|
PhAcquireQueuedLockShared(QueuedLock);
|
|
}
|
|
}
|
|
|
|
FORCEINLINE BOOLEAN PhTryAcquirePushLockExclusive(
|
|
__inout PPH_QUEUED_LOCK QueuedLock
|
|
)
|
|
{
|
|
#ifdef _M_IX86
|
|
if (!_interlockedbittestandset((PLONG)&QueuedLock->Value, PH_QUEUED_LOCK_OWNED_SHIFT))
|
|
#else
|
|
if (!_interlockedbittestandset64((PLONG64)&QueuedLock->Value, PH_QUEUED_LOCK_OWNED_SHIFT))
|
|
#endif
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
FORCEINLINE VOID PhReleaseQueuedLockExclusiveFast(
|
|
__inout PPH_QUEUED_LOCK QueuedLock
|
|
)
|
|
{
|
|
ULONG_PTR value;
|
|
|
|
value = (ULONG_PTR)_InterlockedExchangeAddPointer((PLONG_PTR)&QueuedLock->Value, -(LONG_PTR)PH_QUEUED_LOCK_OWNED);
|
|
|
|
// Only check for waiters here, not the traversing bit, since
|
|
// that isn't common.
|
|
if (value & PH_QUEUED_LOCK_WAITERS)
|
|
{
|
|
PhTryWakePushLock(QueuedLock);
|
|
}
|
|
}
|
|
|
|
FORCEINLINE VOID PhReleaseQueuedLockSharedFast(
|
|
__inout PPH_QUEUED_LOCK QueuedLock
|
|
)
|
|
{
|
|
ULONG_PTR value;
|
|
|
|
value = PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_SHARED_INC;
|
|
|
|
if ((ULONG_PTR)_InterlockedCompareExchangePointer(
|
|
(PPVOID)&QueuedLock->Value,
|
|
(PVOID)0,
|
|
(PVOID)value
|
|
) != value)
|
|
{
|
|
PhReleaseQueuedLockShared(QueuedLock);
|
|
}
|
|
}
|
|
|
|
#endif
|