/*++ Copyright (c) 2000 Microsoft Corporation Module Name: dpcplt.c Abstract: This module implements platform specific code to support Deferred Procedure Calls (DPCs). Author: David N. Cutler (davec) 30-Aug-2000 Environment: Kernel mode only. Revision History: --*/ #include "ki.h" VOID KiRetireDpcList ( PKPRCB Prcb ) /*++ Routine Description: This function processes the DPC list for the specified processor. N.B. This function is entered with interrupts disabled and exits with interrupts disabled. Arguments: Prcb - Supplies the address of the processor block. Return Value: None. --*/ { PKDPC Dpc; PVOID DeferredContext; PKDEFERRED_ROUTINE DeferredRoutine; PLIST_ENTRY Entry; PLIST_ENTRY ListHead; PVOID SystemArgument1; PVOID SystemArgument2; ULONG TimerHand; // // Loop processing DPC list entries until the specified DPC list is empty. // // N.B. This following code appears to have a redundant loop, but it does // not. The point of this code is to avoid as many dispatch interrupts // as possible. // ListHead = &Prcb->DpcListHead; do { Prcb->DpcRoutineActive = TRUE; // // If the timer hand value is nonzero, then process expired timers. // if ((TimerHand = Prcb->TimerHand) != 0) { Prcb->TimerHand = 0; _enable(); KiTimerExpiration(NULL, NULL, UlongToHandle(TimerHand - 1), NULL); _disable(); } // // If the DPC list is not empty, then process the DPC list. // if (Prcb->DpcQueueDepth != 0) { // // Acquire the DPC lock for the current processor and check if // the DPC list is empty. If the DPC list is not empty, then // remove the first entry from the DPC list, capture the DPC // parameters, set the DPC inserted state false, decrement the // DPC queue depth, release the DPC lock, enable interrupts, and // call the specified DPC routine. Otherwise, release the DPC // lock and enable interrupts. // do { KeAcquireSpinLockAtDpcLevel(&Prcb->DpcLock); Entry = Prcb->DpcListHead.Flink; if (Entry != ListHead) { RemoveEntryList(Entry); Dpc = CONTAINING_RECORD(Entry, KDPC, DpcListEntry); DeferredRoutine = Dpc->DeferredRoutine; DeferredContext = Dpc->DeferredContext; SystemArgument1 = Dpc->SystemArgument1; SystemArgument2 = Dpc->SystemArgument2; Dpc->Lock = NULL; Prcb->DpcQueueDepth -= 1; KeReleaseSpinLockFromDpcLevel(&Prcb->DpcLock); _enable(); (DeferredRoutine)(Dpc, DeferredContext, SystemArgument1, SystemArgument2); ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); _disable(); } else { ASSERT(Prcb->DpcQueueDepth == 0); KeReleaseSpinLockFromDpcLevel(&Prcb->DpcLock); } } while (ListHead != *((PLIST_ENTRY volatile *)&ListHead->Flink)); } Prcb->DpcRoutineActive = FALSE; Prcb->DpcInterruptRequested = FALSE; } while (ListHead != *((PLIST_ENTRY volatile *)&ListHead->Flink)); return; }