/** * Unblocks a wait block. * * \param WaitBlock A wait block. * * \remarks The wait block is in an undefined state after it is * unblocked. Do not attempt to read any values from it. All relevant * information should be saved before unblocking the wait block. */ __mayRaise FORCEINLINE VOID PhpUnblockQueuedWaitBlock( __inout PPH_QUEUED_WAIT_BLOCK WaitBlock ) { NTSTATUS status; if (!_interlockedbittestandreset((PLONG)&WaitBlock->Flags, PH_QUEUED_WAITER_SPINNING_SHIFT)) { if (!NT_SUCCESS(status = NtReleaseKeyedEvent( PhQueuedLockKeyedEventHandle, WaitBlock, FALSE, NULL ))) PhRaiseStatus(status); } }
/** * Waits for a wait block to be unblocked. * * \param WaitBlock A wait block. * \param Spin TRUE to spin, FALSE to block immediately. * \param Timeout A timeout value. */ __mayRaise FORCEINLINE NTSTATUS PhpBlockOnQueuedWaitBlock( __inout PPH_QUEUED_WAIT_BLOCK WaitBlock, __in BOOLEAN Spin, __in_opt PLARGE_INTEGER Timeout ) { NTSTATUS status; ULONG i; if (Spin) { PHLIB_INC_STATISTIC(QlBlockSpins); for (i = PhQueuedLockSpinCount; i != 0; i--) { if (!(*(volatile ULONG *)&WaitBlock->Flags & PH_QUEUED_WAITER_SPINNING)) return STATUS_SUCCESS; YieldProcessor(); } } if (_interlockedbittestandreset((PLONG)&WaitBlock->Flags, PH_QUEUED_WAITER_SPINNING_SHIFT)) { PHLIB_INC_STATISTIC(QlBlockWaits); status = NtWaitForKeyedEvent( PhQueuedLockKeyedEventHandle, WaitBlock, FALSE, Timeout ); // If an error occurred (timeout is not an error), raise an exception // as it is nearly impossible to recover from this situation. if (!NT_SUCCESS(status)) PhRaiseStatus(status); } else { status = STATUS_SUCCESS; } return status; }
inline bool interlocked_bit_test_and_reset(long* x,long bit) { return _interlockedbittestandreset(x,bit)!=0; }
void __cdecl _Atomic_flag_clear(volatile _Atomic_flag_t *_Flag, memory_order _Order) { /* atomically clear flag */ _interlockedbittestandreset(_Flag, 1); /* reset bit 0 */ }
void ReleaseLock() { LONG *p = (LONG*)&mutex; _interlockedbittestandreset(p,0); }