/*++ * @name ExTimedWaitForUnblockPushLock * * The ExTimedWaitForUnblockPushLock routine waits for a pushlock * to be unblocked, for a specified internal. * * @param PushLock * Pointer to a pushlock whose waiter list needs to be optimized. * * @param WaitBlock * Pointer to the pushlock's wait block. * * @param Timeout * Amount of time to wait for this pushlock to be unblocked. * * @return STATUS_SUCCESS is the pushlock is now unblocked, otherwise the error * code returned by KeWaitForSingleObject. * * @remarks If the wait fails, then a manual unblock is attempted. * *--*/ NTSTATUS FASTCALL ExTimedWaitForUnblockPushLock(IN PEX_PUSH_LOCK PushLock, IN PVOID WaitBlock, IN PLARGE_INTEGER Timeout) { NTSTATUS Status; /* Initialize the wait event */ KeInitializeEvent(&((PEX_PUSH_LOCK_WAIT_BLOCK)WaitBlock)->WakeEvent, SynchronizationEvent, FALSE); #ifdef CONFIG_SMP /* Spin on the push lock if necessary */ if (ExPushLockSpinCount) { ULONG i = ExPushLockSpinCount; do { /* Check if we got lucky and can leave early */ if (!(*(volatile LONG *)&((PEX_PUSH_LOCK_WAIT_BLOCK)WaitBlock)->Flags & EX_PUSH_LOCK_WAITING)) return STATUS_SUCCESS; YieldProcessor(); } while (--i); } #endif /* Now try to remove the wait bit */ if (InterlockedBitTestAndReset(&((PEX_PUSH_LOCK_WAIT_BLOCK)WaitBlock)->Flags, EX_PUSH_LOCK_FLAGS_WAIT_V)) { /* Nobody removed it already, let's do a full wait */ Status = KeWaitForSingleObject(&((PEX_PUSH_LOCK_WAIT_BLOCK)WaitBlock)-> WakeEvent, WrPushLock, KernelMode, FALSE, Timeout); /* Check if the wait was satisfied */ if (Status != STATUS_SUCCESS) { /* Try unblocking the pushlock if it was not */ ExfUnblockPushLock(PushLock, WaitBlock); } } else { /* Someone beat us to it, no need to wait */ Status = STATUS_SUCCESS; } /* Return status */ return Status; }
NTKERNELAPI NTSTATUS FASTCALL ExTimedWaitForUnblockPushLock ( __inout PEX_PUSH_LOCK PushLock, __inout PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock, __in_opt PLARGE_INTEGER Timeout ) { ULONG i; NTSTATUS Status; UNREFERENCED_PARAMETER (PushLock); KeInitializeEvent (&WaitBlock->WakeEvent, SynchronizationEvent, FALSE); for (i = ExPushLockSpinCount; i > 0; i--) { if (((*(volatile LONG *)&WaitBlock->Flags)&EX_PUSH_LOCK_FLAGS_SPINNING) == 0) { return STATUS_SUCCESS; } KeYieldProcessor (); } if (InterlockedBitTestAndReset (&WaitBlock->Flags, EX_PUSH_LOCK_FLAGS_SPINNING_V)) { Status = KeWaitForSingleObject (&WaitBlock->WakeEvent, WrPushLock, KernelMode, FALSE, Timeout); if (Status != STATUS_SUCCESS) { ExfUnblockPushLock (PushLock, WaitBlock); } } else { Status = STATUS_SUCCESS; } return Status; }
VOID KphUnlockHandleTableEntry( __in PHANDLE_TABLE HandleTable, __in PHANDLE_TABLE_ENTRY HandleTableEntry ) { PEX_PUSH_LOCK handleContentionEvent; PAGED_CODE(); // Set the unlocked bit. #ifdef _M_X64 InterlockedExchangeAdd64(&HandleTableEntry->Value, 1); #else InterlockedExchangeAdd(&HandleTableEntry->Value, 1); #endif // Allow waiters to wake up. handleContentionEvent = (PEX_PUSH_LOCK)((ULONG_PTR)HandleTable + KphDynHtHandleContentionEvent); if (*(PULONG_PTR)handleContentionEvent != 0) ExfUnblockPushLock(handleContentionEvent, NULL); }