141 lines
3.6 KiB
C
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;
|
|
}
|