/*++ * @name ExfUnblockPushLock * @implemented NT5.1 * * The ExfUnblockPushLock routine unblocks a previously blocked PushLock. * * @param PushLock * Pointer to a previously blocked PushLock. * * @return None. * * @remarks Callers of ExfUnblockPushLock can be running at any IRQL. * *--*/ VOID FASTCALL ExfUnblockPushLock(PEX_PUSH_LOCK PushLock, PVOID CurrentWaitBlock) { PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock, NextWaitBlock; KIRQL OldIrql = DISPATCH_LEVEL; /* Get the wait block and erase the previous one */ WaitBlock = InterlockedExchangePointer(&PushLock->Ptr, NULL); if (WaitBlock) { /* Check if there is a linked pushlock and raise IRQL appropriately */ if (WaitBlock->Next) KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); /* Start block loop */ while (WaitBlock) { /* Get the next block */ NextWaitBlock = WaitBlock->Next; /* Remove the wait flag from the Wait block */ if (!InterlockedBitTestAndReset(&WaitBlock->Flags, EX_PUSH_LOCK_FLAGS_WAIT_V)) { /* Nobody removed the flag before us, so signal the event */ KeSetEventBoostPriority(&WaitBlock->WakeEvent, NULL); } /* Try the next one */ WaitBlock = NextWaitBlock; } /* Lower IRQL if needed */ if (OldIrql != DISPATCH_LEVEL) KeLowerIrql(OldIrql); } /* Check if we got a wait block that's pending */ if ((CurrentWaitBlock) && (((PEX_PUSH_LOCK_WAIT_BLOCK)CurrentWaitBlock)->Flags & EX_PUSH_LOCK_FLAGS_WAIT)) { /* Wait for the pushlock to be unblocked */ ExWaitForUnblockPushLock(PushLock, CurrentWaitBlock); } }
NTKERNELAPI VOID FASTCALL ExfUnblockPushLock ( __inout PEX_PUSH_LOCK PushLock, __inout_opt PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock ) /*++ Routine Description: Unblock on a push lock Arguments: PushLock - Push lock to block on WaitBlock - Wait block previously queued for waiting or NULL if there wasn't one Return Value: None --*/ { EX_PUSH_LOCK OldValue; PEX_PUSH_LOCK_WAIT_BLOCK tWaitBlock; KIRQL OldIrql; // // Pop the entire chain and wake them all up. // OldValue.Ptr = InterlockedExchangePointer (&PushLock->Ptr, NULL); tWaitBlock = OldValue.Ptr; // // If it looks like we will wake more than one thread then raise IRQL to prevent // rescheduling during the operation. // OldIrql = DISPATCH_LEVEL; if (tWaitBlock != NULL && tWaitBlock->Next != NULL) { KeRaiseIrql (DISPATCH_LEVEL, &OldIrql); } while (tWaitBlock != NULL) { OldValue.Ptr = tWaitBlock->Next; if (!InterlockedBitTestAndReset (&tWaitBlock->Flags, EX_PUSH_LOCK_FLAGS_SPINNING_V)) { KeSetEventBoostPriority (&tWaitBlock->WakeEvent, NULL); } tWaitBlock = OldValue.Ptr; } if (OldIrql != DISPATCH_LEVEL) { KeLowerIrql (OldIrql); } if (WaitBlock != NULL && (WaitBlock->Flags&EX_PUSH_LOCK_FLAGS_SPINNING) != 0) { ExWaitForUnblockPushLock (PushLock, WaitBlock); } }