https://git.reactos.org/?p=reactos.git;a=commitdiff;h=1d3bce1a598e988ed26580503911886113c5cc24

commit 1d3bce1a598e988ed26580503911886113c5cc24
Author:     Timo Kreuzer <timo.kreu...@reactos.org>
AuthorDate: Sun Nov 26 12:24:24 2023 +0200
Commit:     Timo Kreuzer <timo.kreu...@reactos.org>
CommitDate: Sun Oct 20 16:28:11 2024 +0300

    [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), Ke [...]
---
 ntoskrnl/ke/dpc.c | 38 ++++++++++++++++++++++++++++----------
 1 file changed, 28 insertions(+), 10 deletions(-)

diff --git a/ntoskrnl/ke/dpc.c b/ntoskrnl/ke/dpc.c
index 5ed9f51aad0..04d45fe1665 100644
--- a/ntoskrnl/ke/dpc.c
+++ b/ntoskrnl/ke/dpc.c
@@ -914,28 +914,46 @@ KeRemoveQueueDpc(IN PKDPC Dpc)
 /*
  * @implemented
  */
+_IRQL_requires_max_(APC_LEVEL)
 VOID
 NTAPI
 KeFlushQueuedDpcs(VOID)
 {
-    PKPRCB CurrentPrcb = KeGetCurrentPrcb();
+    ULONG ProcessorIndex;
+    PKPRCB TargetPrcb;
+
     PAGED_CODE();
+    ASSERT(KeGetCurrentThread()->SystemAffinityActive == FALSE);
 
-    /* Check if this is an UP machine */
-    if (KeActiveProcessors == 1)
+    /* Loop all processors */
+    for (ProcessorIndex = 0; ProcessorIndex < KeNumberProcessors; 
ProcessorIndex++)
     {
+        /* Get the target processor's PRCB */
+        TargetPrcb = KiProcessorBlock[ProcessorIndex];
+
         /* Check if there are DPCs on either queues */
-        if ((CurrentPrcb->DpcData[DPC_NORMAL].DpcQueueDepth > 0) ||
-            (CurrentPrcb->DpcData[DPC_THREADED].DpcQueueDepth > 0))
+        if ((TargetPrcb->DpcData[DPC_NORMAL].DpcQueueDepth > 0) ||
+            (TargetPrcb->DpcData[DPC_THREADED].DpcQueueDepth > 0))
         {
-            /* Request an interrupt */
-            HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
+            /* Check if this is the current processor */
+            if (TargetPrcb == KeGetCurrentPrcb())
+            {
+                /* Request a DPC interrupt */
+                HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
+            }
+            else
+            {
+                /* Attach to the target processor. This will cause a DPC
+                   interrupt on the target processor and flush all DPCs. */
+                KeSetSystemAffinityThread(TargetPrcb->SetMember);
+            }
         }
     }
-    else
+
+    /* Revert back to user affinity */
+    if (KeGetCurrentThread()->SystemAffinityActive)
     {
-        /* FIXME: SMP support required */
-        ASSERT(FALSE);
+        KeRevertToUserAffinityThread();
     }
 }
 

Reply via email to