Example #1
0
/*++
 * @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);
    }
}
Example #2
0
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);
    }
}