Skip to content

Commit 1d3bce1

Browse files
committed
[NTOS:KE] Make KeFlushQueuedDpcs SMP ready
KeFlushQueuedDpcs is used by some drivers, when unloading or removing a device, to be sure no DPC is still running their code. On a UP system this can be done "inline", on an SMP system, it requires to send an IPI to each processor that has DPCs queued and also synchronize it with the calling thread, which is what KeSetSystemAffinityThread does implicitly: When a queued DPC was detected on a remote processor (implying that processor is currently running at DISPATCH_LEVEL or above), KeSetSystemAffinityThread will schedule the current thread on that processor and send a DPC interrupt. The remote processor will handle that DPC interrupt once it is back below DISPATCH_LEVEL. It will only run the current thread, after all queued DPCs (including threaded DPCs) have finished running.
1 parent bf95874 commit 1d3bce1

File tree

1 file changed

+28
-10
lines changed

1 file changed

+28
-10
lines changed

ntoskrnl/ke/dpc.c

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -914,28 +914,46 @@ KeRemoveQueueDpc(IN PKDPC Dpc)
914914
/*
915915
* @implemented
916916
*/
917+
_IRQL_requires_max_(APC_LEVEL)
917918
VOID
918919
NTAPI
919920
KeFlushQueuedDpcs(VOID)
920921
{
921-
PKPRCB CurrentPrcb = KeGetCurrentPrcb();
922+
ULONG ProcessorIndex;
923+
PKPRCB TargetPrcb;
924+
922925
PAGED_CODE();
926+
ASSERT(KeGetCurrentThread()->SystemAffinityActive == FALSE);
923927

924-
/* Check if this is an UP machine */
925-
if (KeActiveProcessors == 1)
928+
/* Loop all processors */
929+
for (ProcessorIndex = 0; ProcessorIndex < KeNumberProcessors; ProcessorIndex++)
926930
{
931+
/* Get the target processor's PRCB */
932+
TargetPrcb = KiProcessorBlock[ProcessorIndex];
933+
927934
/* Check if there are DPCs on either queues */
928-
if ((CurrentPrcb->DpcData[DPC_NORMAL].DpcQueueDepth > 0) ||
929-
(CurrentPrcb->DpcData[DPC_THREADED].DpcQueueDepth > 0))
935+
if ((TargetPrcb->DpcData[DPC_NORMAL].DpcQueueDepth > 0) ||
936+
(TargetPrcb->DpcData[DPC_THREADED].DpcQueueDepth > 0))
930937
{
931-
/* Request an interrupt */
932-
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
938+
/* Check if this is the current processor */
939+
if (TargetPrcb == KeGetCurrentPrcb())
940+
{
941+
/* Request a DPC interrupt */
942+
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
943+
}
944+
else
945+
{
946+
/* Attach to the target processor. This will cause a DPC
947+
interrupt on the target processor and flush all DPCs. */
948+
KeSetSystemAffinityThread(TargetPrcb->SetMember);
949+
}
933950
}
934951
}
935-
else
952+
953+
/* Revert back to user affinity */
954+
if (KeGetCurrentThread()->SystemAffinityActive)
936955
{
937-
/* FIXME: SMP support required */
938-
ASSERT(FALSE);
956+
KeRevertToUserAffinityThread();
939957
}
940958
}
941959

0 commit comments

Comments
 (0)