windows-nt/Source/XPSP1/NT/base/ntos/ke/amd64/dpcplt.c
2020-09-26 16:20:57 +08:00

141 lines
3.6 KiB
C

/*++
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;
}