mirror of
https://github.com/mirror/processhacker
synced 2026-06-08 16:03:24 +00:00
* fixed handle table bugs
* added PhQueryInformationHandleTable/PhSetInformationHandleTable * fixed PhfPulse(All)Condition * added Wake Event git-svn-id: svn://svn.code.sf.net/p/processhacker/code@2979 21ef857c-d57f-4fe0-8362-d861dc6d29cd
This commit is contained in:
+129
-10
@@ -46,7 +46,7 @@ PPH_HANDLE_TABLE PhCreateHandleTable()
|
||||
handleTable = PhAllocate(sizeof(PH_HANDLE_TABLE));
|
||||
|
||||
PhInitializeQueuedLock(&handleTable->Lock);
|
||||
PhInitializeQueuedLock(&handleTable->LockedCondition);
|
||||
PhInitializeQueuedLock(&handleTable->HandleWakeEvent);
|
||||
|
||||
handleTable->NextValue = 0;
|
||||
|
||||
@@ -148,6 +148,29 @@ VOID PhDestroyHandleTable(
|
||||
PhFree(HandleTable);
|
||||
}
|
||||
|
||||
VOID PhpBlockOnLockedHandleTableEntry(
|
||||
__inout PPH_HANDLE_TABLE HandleTable,
|
||||
__in PPH_HANDLE_TABLE_ENTRY HandleTableEntry
|
||||
)
|
||||
{
|
||||
PH_QUEUED_WAIT_BLOCK waitBlock;
|
||||
ULONG_PTR value;
|
||||
|
||||
PhQueueWakeEvent(&HandleTable->HandleWakeEvent, &waitBlock);
|
||||
|
||||
value = HandleTableEntry->Value;
|
||||
|
||||
if (value & PH_HANDLE_TABLE_ENTRY_LOCKED)
|
||||
{
|
||||
// Entry has been unlocked; cancel the wait.
|
||||
PhSetWakeEvent(&HandleTable->HandleWakeEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
PhWaitForWakeEvent(&HandleTable->HandleWakeEvent, &waitBlock, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
VOID PhLockHandleTableEntry(
|
||||
__inout PPH_HANDLE_TABLE HandleTable,
|
||||
__inout PPH_HANDLE_TABLE_ENTRY HandleTableEntry
|
||||
@@ -158,7 +181,7 @@ VOID PhLockHandleTableEntry(
|
||||
PH_HANDLE_TABLE_ENTRY_LOCKED_SHIFT
|
||||
))
|
||||
{
|
||||
PhWaitForCondition(&HandleTable->LockedCondition, NULL, NULL);
|
||||
PhpBlockOnLockedHandleTableEntry(HandleTable, HandleTableEntry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +211,7 @@ BOOLEAN PhLockInUseHandleTableEntry(
|
||||
}
|
||||
}
|
||||
|
||||
PhWaitForCondition(&HandleTable->LockedCondition, NULL, NULL);
|
||||
PhpBlockOnLockedHandleTableEntry(HandleTable, HandleTableEntry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +224,7 @@ VOID PhUnlockHandleTableEntry(
|
||||
(PLONG)&HandleTableEntry->Value,
|
||||
PH_HANDLE_TABLE_ENTRY_LOCKED_SHIFT
|
||||
);
|
||||
PhPulseAllCondition(&HandleTable->LockedCondition);
|
||||
PhSetWakeEvent(&HandleTable->HandleWakeEvent);
|
||||
}
|
||||
|
||||
HANDLE PhCreateHandle(
|
||||
@@ -218,7 +241,8 @@ HANDLE PhCreateHandle(
|
||||
return NULL;
|
||||
|
||||
// Copy the given handle table entry to the allocated entry.
|
||||
entry->TypeAndValue.Type = PH_HANDLE_TABLE_ENTRY_IN_USE | PH_HANDLE_TABLE_ENTRY_LOCKED;
|
||||
entry->TypeAndValue.Type = PH_HANDLE_TABLE_ENTRY_IN_USE;
|
||||
entry->TypeAndValue.Locked = TRUE;
|
||||
entry->TypeAndValue.Value = HandleTableEntry->TypeAndValue.Value;
|
||||
entry->Value2 = HandleTableEntry->Value2;
|
||||
|
||||
@@ -251,9 +275,9 @@ BOOLEAN PhDestroyHandle(
|
||||
(PVOID)(PH_HANDLE_TABLE_ENTRY_FREE | PH_HANDLE_TABLE_ENTRY_LOCKED)
|
||||
);
|
||||
|
||||
// The handle table entry now has the lock bit cleared, so we
|
||||
// The handle table entry now has the (not) locked bit set, so we
|
||||
// should wake waiters.
|
||||
PhPulseAllCondition(&HandleTable->LockedCondition);
|
||||
PhSetWakeEvent(&HandleTable->HandleWakeEvent);
|
||||
|
||||
PhpFreeHandleTableEntry(HandleTable, handleValue, HandleTableEntry);
|
||||
|
||||
@@ -341,6 +365,101 @@ VOID PhSweepHandleTable(
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS PhQueryInformationHandleTable(
|
||||
__in PPH_HANDLE_TABLE HandleTable,
|
||||
__in PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass,
|
||||
__out_bcount_opt(BufferLength) PVOID Buffer,
|
||||
__in ULONG BufferLength,
|
||||
__out_opt PULONG ReturnLength
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
ULONG returnLength;
|
||||
|
||||
switch (InformationClass)
|
||||
{
|
||||
case HandleTableBasicInformation:
|
||||
{
|
||||
PPH_HANDLE_TABLE_BASIC_INFORMATION basicInfo = Buffer;
|
||||
|
||||
if (BufferLength == sizeof(PH_HANDLE_TABLE_BASIC_INFORMATION))
|
||||
{
|
||||
basicInfo->Count = HandleTable->Count;
|
||||
basicInfo->Flags = HandleTable->Flags;
|
||||
basicInfo->TableLevel = HandleTable->TableValue & PH_HANDLE_TABLE_LEVEL_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
}
|
||||
|
||||
returnLength = sizeof(PH_HANDLE_TABLE_BASIC_INFORMATION);
|
||||
}
|
||||
break;
|
||||
case HandleTableFlagsInformation:
|
||||
{
|
||||
PPH_HANDLE_TABLE_FLAGS_INFORMATION flagsInfo = Buffer;
|
||||
|
||||
if (BufferLength == sizeof(PH_HANDLE_TABLE_FLAGS_INFORMATION))
|
||||
{
|
||||
flagsInfo->Flags = HandleTable->Flags;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
}
|
||||
|
||||
returnLength = sizeof(PH_HANDLE_TABLE_FLAGS_INFORMATION);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
status = STATUS_INVALID_INFO_CLASS;
|
||||
}
|
||||
|
||||
if (ReturnLength)
|
||||
*ReturnLength = returnLength;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS PhSetInformationHandleTable(
|
||||
__inout PPH_HANDLE_TABLE HandleTable,
|
||||
__in PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass,
|
||||
__in_bcount(BufferLength) PVOID Buffer,
|
||||
__in ULONG BufferLength
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
switch (InformationClass)
|
||||
{
|
||||
case HandleTableFlagsInformation:
|
||||
{
|
||||
PPH_HANDLE_TABLE_FLAGS_INFORMATION flagsInfo = Buffer;
|
||||
ULONG flags;
|
||||
|
||||
if (BufferLength == sizeof(PH_HANDLE_TABLE_FLAGS_INFORMATION))
|
||||
{
|
||||
flags = flagsInfo->Flags;
|
||||
|
||||
if ((flags & PH_HANDLE_TABLE_VALID_FLAGS) == flags)
|
||||
HandleTable->Flags = flags;
|
||||
else
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
status = STATUS_INVALID_INFO_CLASS;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
PPH_HANDLE_TABLE_ENTRY PhpAllocateHandleTableEntry(
|
||||
__inout PPH_HANDLE_TABLE HandleTable,
|
||||
__out PULONG HandleValue
|
||||
@@ -598,7 +717,7 @@ BOOLEAN PhpAllocateMoreHandleTableEntries(
|
||||
table1 = PhpCreateHandleTableLevel1(HandleTable);
|
||||
|
||||
#ifdef PH_HANDLE_TABLE_SAFE
|
||||
if (table1)
|
||||
if (!table1)
|
||||
{
|
||||
PhpFreeHandleTableLevel2(table2);
|
||||
return FALSE;
|
||||
@@ -868,10 +987,10 @@ ULONG PhpMoveFreeHandleTableEntries(
|
||||
count < PH_HANDLE_TABLE_FREE_COUNT
|
||||
)
|
||||
{
|
||||
freeValueAlt = PH_HANDLE_VALUE_INVALID;
|
||||
index = PH_HANDLE_VALUE_INVALID;
|
||||
}
|
||||
|
||||
return freeValueAlt;
|
||||
return index;
|
||||
}
|
||||
|
||||
PPH_HANDLE_TABLE_ENTRY PhpCreateHandleTableLevel0(
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
typedef struct _PH_HANDLE_TABLE
|
||||
{
|
||||
PH_QUEUED_LOCK Lock;
|
||||
PH_QUEUED_LOCK LockedCondition;
|
||||
PH_QUEUED_LOCK HandleWakeEvent;
|
||||
|
||||
ULONG Count;
|
||||
ULONG_PTR TableValue;
|
||||
@@ -93,6 +93,11 @@ FORCEINLINE ULONG PhpDecodeHandle(
|
||||
return ((ULONG)Handle - PH_HANDLE_VALUE_BIAS) >> PH_HANDLE_VALUE_SHIFT;
|
||||
}
|
||||
|
||||
VOID PhpBlockOnLockedHandleTableEntry(
|
||||
__inout PPH_HANDLE_TABLE HandleTable,
|
||||
__in PPH_HANDLE_TABLE_ENTRY HandleTableEntry
|
||||
);
|
||||
|
||||
PPH_HANDLE_TABLE_ENTRY PhpAllocateHandleTableEntry(
|
||||
__inout PPH_HANDLE_TABLE HandleTable,
|
||||
__out PULONG HandleValue
|
||||
|
||||
@@ -1662,6 +1662,7 @@ typedef struct _PH_HANDLE_TABLE_ENTRY
|
||||
#define PH_HANDLE_TABLE_FREE_COUNT 64
|
||||
|
||||
#define PH_HANDLE_TABLE_STRICT_FIFO 0x1
|
||||
#define PH_HANDLE_TABLE_VALID_FLAGS 0x1
|
||||
|
||||
VOID PhHandleTableInitialization();
|
||||
|
||||
@@ -1721,6 +1722,40 @@ VOID PhSweepHandleTable(
|
||||
__in PVOID Context
|
||||
);
|
||||
|
||||
typedef enum _PH_HANDLE_TABLE_INFORMATION_CLASS
|
||||
{
|
||||
HandleTableBasicInformation,
|
||||
HandleTableFlagsInformation,
|
||||
MaxHandleTableInfoClass
|
||||
} PH_HANDLE_TABLE_INFORMATION_CLASS;
|
||||
|
||||
typedef struct _PH_HANDLE_TABLE_BASIC_INFORMATION
|
||||
{
|
||||
ULONG Count;
|
||||
ULONG Flags;
|
||||
ULONG TableLevel;
|
||||
} PH_HANDLE_TABLE_BASIC_INFORMATION, *PPH_HANDLE_TABLE_BASIC_INFORMATION;
|
||||
|
||||
typedef struct _PH_HANDLE_TABLE_FLAGS_INFORMATION
|
||||
{
|
||||
ULONG Flags;
|
||||
} PH_HANDLE_TABLE_FLAGS_INFORMATION, *PPH_HANDLE_TABLE_FLAGS_INFORMATION;
|
||||
|
||||
NTSTATUS PhQueryInformationHandleTable(
|
||||
__in PPH_HANDLE_TABLE HandleTable,
|
||||
__in PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass,
|
||||
__out_bcount_opt(BufferLength) PVOID Buffer,
|
||||
__in ULONG BufferLength,
|
||||
__out_opt PULONG ReturnLength
|
||||
);
|
||||
|
||||
NTSTATUS PhSetInformationHandleTable(
|
||||
__inout PPH_HANDLE_TABLE HandleTable,
|
||||
__in PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass,
|
||||
__in_bcount(BufferLength) PVOID Buffer,
|
||||
__in ULONG BufferLength
|
||||
);
|
||||
|
||||
// workqueue
|
||||
|
||||
typedef struct _PH_WORK_QUEUE
|
||||
|
||||
@@ -103,6 +103,24 @@ VOID FASTCALL PhfWaitForCondition(
|
||||
__in_opt PLARGE_INTEGER Timeout
|
||||
);
|
||||
|
||||
#define PhQueueWakeEvent PhfQueueWakeEvent
|
||||
VOID FASTCALL PhfQueueWakeEvent(
|
||||
__inout PPH_QUEUED_LOCK WakeEvent,
|
||||
__inout PPH_QUEUED_WAIT_BLOCK WaitBlock
|
||||
);
|
||||
|
||||
#define PhSetWakeEvent PhfSetWakeEvent
|
||||
VOID FASTCALL PhfSetWakeEvent(
|
||||
__inout PPH_QUEUED_LOCK WakeEvent
|
||||
);
|
||||
|
||||
#define PhWaitForWakeEvent PhfWaitForWakeEvent
|
||||
NTSTATUS FASTCALL PhfWaitForWakeEvent(
|
||||
__inout PPH_QUEUED_LOCK WakeEvent,
|
||||
__inout PPH_QUEUED_WAIT_BLOCK WaitBlock,
|
||||
__in_opt PLARGE_INTEGER Timeout
|
||||
);
|
||||
|
||||
// Inline functions
|
||||
|
||||
FORCEINLINE VOID PhAcquireQueuedLockExclusiveFast(
|
||||
@@ -213,10 +231,18 @@ FORCEINLINE BOOLEAN PhTryAcquireReleaseQueuedLockExclusive(
|
||||
// compiler re-ordering the following check in either
|
||||
// direction.
|
||||
MemoryBarrier();
|
||||
owned = !!(QueuedLock->Value & PH_QUEUED_LOCK_OWNED);
|
||||
owned = !(QueuedLock->Value & PH_QUEUED_LOCK_OWNED);
|
||||
MemoryBarrier();
|
||||
|
||||
return owned;
|
||||
}
|
||||
|
||||
FORCEINLINE VOID PhSetWakeEventFast(
|
||||
__inout PPH_QUEUED_LOCK WakeEvent
|
||||
)
|
||||
{
|
||||
if (WakeEvent->Value)
|
||||
PhSetWakeEvent(WakeEvent);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -286,8 +286,9 @@ FORCEINLINE PPH_QUEUED_WAIT_BLOCK PhpFindLastQueuedWaitBlock(
|
||||
*
|
||||
* \param WaitBlock A wait block.
|
||||
*/
|
||||
__mayRaise FORCEINLINE VOID PhpBlockOnQueuedWaitBlock(
|
||||
__inout PPH_QUEUED_WAIT_BLOCK WaitBlock
|
||||
__mayRaise FORCEINLINE NTSTATUS PhpBlockOnQueuedWaitBlock(
|
||||
__inout PPH_QUEUED_WAIT_BLOCK WaitBlock,
|
||||
__in_opt PLARGE_INTEGER Timeout
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
@@ -309,10 +310,16 @@ __mayRaise FORCEINLINE VOID PhpBlockOnQueuedWaitBlock(
|
||||
PhQueuedLockKeyedEventHandle,
|
||||
WaitBlock,
|
||||
FALSE,
|
||||
NULL
|
||||
Timeout
|
||||
)))
|
||||
PhRaiseStatus(status);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -683,7 +690,7 @@ VOID FASTCALL PhfAcquireQueuedLockExclusive(
|
||||
if (optimize)
|
||||
PhpfOptimizeQueuedLockList(QueuedLock, currentValue);
|
||||
|
||||
PhpBlockOnQueuedWaitBlock(&waitBlock);
|
||||
PhpBlockOnQueuedWaitBlock(&waitBlock, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -744,7 +751,7 @@ VOID FASTCALL PhfAcquireQueuedLockShared(
|
||||
if (optimize)
|
||||
PhpfOptimizeQueuedLockList(QueuedLock, currentValue);
|
||||
|
||||
PhpBlockOnQueuedWaitBlock(&waitBlock);
|
||||
PhpBlockOnQueuedWaitBlock(&waitBlock, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -930,24 +937,32 @@ VOID FASTCALL PhfTryWakePushLock(
|
||||
* Wakes one thread sleeping on a condition variable.
|
||||
*
|
||||
* \param Condition A condition variable.
|
||||
*
|
||||
* \remarks The associated lock must be acquired before calling
|
||||
* the function.
|
||||
*/
|
||||
VOID FASTCALL PhfPulseCondition(
|
||||
__inout PPH_QUEUED_LOCK Condition
|
||||
)
|
||||
{
|
||||
PhpfWakeQueuedLockEx(Condition, Condition->Value, TRUE, FALSE);
|
||||
if (Condition->Value & PH_QUEUED_LOCK_WAITERS)
|
||||
PhpfWakeQueuedLockEx(Condition, Condition->Value, TRUE, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wakes all threads sleeping on a condition variable.
|
||||
*
|
||||
* \param Condition A condition variable.
|
||||
*
|
||||
* \remarks The associated lock must be acquired before calling
|
||||
* the function.
|
||||
*/
|
||||
VOID FASTCALL PhfPulseAllCondition(
|
||||
__inout PPH_QUEUED_LOCK Condition
|
||||
)
|
||||
{
|
||||
PhpfWakeQueuedLockEx(Condition, Condition->Value, TRUE, TRUE);
|
||||
if (Condition->Value & PH_QUEUED_LOCK_WAITERS)
|
||||
PhpfWakeQueuedLockEx(Condition, Condition->Value, TRUE, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -956,6 +971,9 @@ VOID FASTCALL PhfPulseAllCondition(
|
||||
* \param Condition A condition variable.
|
||||
* \param Lock A queued lock to release/acquire.
|
||||
* \param Timeout Not implemented.
|
||||
*
|
||||
* \remarks The associated lock must be acquired before calling
|
||||
* the function.
|
||||
*/
|
||||
VOID FASTCALL PhfWaitForCondition(
|
||||
__inout PPH_QUEUED_LOCK Condition,
|
||||
@@ -992,7 +1010,7 @@ VOID FASTCALL PhfWaitForCondition(
|
||||
PhReleaseQueuedLockExclusiveFast(Lock);
|
||||
}
|
||||
|
||||
PhpBlockOnQueuedWaitBlock(&waitBlock);
|
||||
PhpBlockOnQueuedWaitBlock(&waitBlock, NULL);
|
||||
|
||||
if (Lock)
|
||||
{
|
||||
@@ -1005,3 +1023,94 @@ VOID FASTCALL PhfWaitForCondition(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues a wait block to a wake event.
|
||||
*
|
||||
* \param WakeEvent A wake event.
|
||||
* \param WaitBlock A wait block.
|
||||
*
|
||||
* \remarks If you later determine that the wait should
|
||||
* not occur, you must call PhfSetWakeEvent() to dequeue
|
||||
* the wait block.
|
||||
*/
|
||||
VOID FASTCALL PhfQueueWakeEvent(
|
||||
__inout PPH_QUEUED_LOCK WakeEvent,
|
||||
__inout PPH_QUEUED_WAIT_BLOCK WaitBlock
|
||||
)
|
||||
{
|
||||
PPH_QUEUED_WAIT_BLOCK value;
|
||||
PPH_QUEUED_WAIT_BLOCK newValue;
|
||||
|
||||
WaitBlock->Flags = PH_QUEUED_WAITER_SPINNING;
|
||||
|
||||
value = (PPH_QUEUED_WAIT_BLOCK)WakeEvent->Value;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
WaitBlock->Next = value;
|
||||
|
||||
if ((newValue = _InterlockedCompareExchangePointer(
|
||||
(PPVOID)&WakeEvent->Value,
|
||||
WaitBlock,
|
||||
value
|
||||
)) == value)
|
||||
break;
|
||||
|
||||
value = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a wake event, unblocking all queued wait blocks.
|
||||
*
|
||||
* \param WakeEvent A wake event.
|
||||
*/
|
||||
VOID FASTCALL PhfSetWakeEvent(
|
||||
__inout PPH_QUEUED_LOCK WakeEvent
|
||||
)
|
||||
{
|
||||
PPH_QUEUED_WAIT_BLOCK waitBlock;
|
||||
|
||||
// Pop all waiters and unblock them.
|
||||
|
||||
waitBlock = _InterlockedExchangePointer((PPVOID)&WakeEvent->Value, NULL);
|
||||
|
||||
while (waitBlock)
|
||||
{
|
||||
waitBlock = waitBlock->Next;
|
||||
PhpUnblockQueuedWaitBlock(waitBlock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for a wake event to be set.
|
||||
*
|
||||
* \param WakeEvent A wake event.
|
||||
* \param WaitBlock A wait block previously queued to
|
||||
* the wake event using PhfQueueWakeEvent().
|
||||
* \param Timeout A timeout value.
|
||||
*
|
||||
* \param Wake events are subject to spurious wakeups. You
|
||||
* should call this function in a loop which checks a
|
||||
* predicate.
|
||||
*/
|
||||
NTSTATUS FASTCALL PhfWaitForWakeEvent(
|
||||
__inout PPH_QUEUED_LOCK WakeEvent,
|
||||
__inout PPH_QUEUED_WAIT_BLOCK WaitBlock,
|
||||
__in_opt PLARGE_INTEGER Timeout
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
status = PhpBlockOnQueuedWaitBlock(WaitBlock, Timeout);
|
||||
|
||||
if (status != STATUS_SUCCESS)
|
||||
{
|
||||
// Probably a timeout. There's no way of unlinking
|
||||
// the wait block safely, so just wake everyone.
|
||||
PhSetWakeEvent(WakeEvent);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user