[PATCH 3/5] ntoskrnl.exe: Add KeGenericCallDpc() function.

Paul Gofman pgofman at codeweavers.com
Wed May 27 04:50:48 CDT 2020


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
 dlls/ntoskrnl.exe/ntoskrnl.c        | 113 ++++++++++++++++++++++++++++
 dlls/ntoskrnl.exe/ntoskrnl.exe.spec |   1 +
 include/ddk/wdm.h                   |   7 ++
 3 files changed, 121 insertions(+)

diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 2291842a67..1a0cf1c5c2 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -72,6 +72,10 @@ KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable[4] = { { 0 } };
 
 #define MAX_SERVICE_NAME 260
 
+static TP_POOL *dpc_call_tp;
+static TP_CALLBACK_ENVIRON dpc_call_tpe;
+DECLARE_CRITICAL_SECTION(dpc_call_cs);
+
 /* tid of the thread running client request */
 static DWORD request_thread;
 
@@ -3160,6 +3164,10 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
         break;
     case DLL_PROCESS_DETACH:
         if (reserved) break;
+
+        if (dpc_call_tp)
+            CloseThreadpool(dpc_call_tp);
+
         HeapDestroy( ntoskrnl_heap );
         RtlRemoveVectoredExceptionHandler( handler );
         break;
@@ -4012,6 +4020,111 @@ BOOLEAN WINAPI KdRefreshDebuggerNotPresent(void)
     return !KdDebuggerEnabled;
 }
 
+struct generic_call_dpc_context
+{
+    DEFERRED_REVERSE_BARRIER *reverse_barrier;
+    PKDEFERRED_ROUTINE routine;
+    ULONG *cpu_count_barrier;
+    void *context;
+    ULONG cpu_index;
+};
+
+static void WINAPI generic_call_dpc_callback(TP_CALLBACK_INSTANCE *instance, void *context)
+{
+    struct generic_call_dpc_context *c = context;
+    GROUP_AFFINITY old, new;
+
+    TRACE("instance %p, context %p.\n", instance, context);
+
+    NtQueryInformationThread(GetCurrentThread(), ThreadGroupInformation,
+            &old, sizeof(old), NULL);
+
+    memset(&new, 0, sizeof(new));
+
+    new.Mask = 1 << c->cpu_index;
+    NtSetInformationThread(GetCurrentThread(), ThreadGroupInformation, &new, sizeof(new));
+
+    c->routine((PKDPC)0xdeadbeef, c->context, c->cpu_count_barrier, c->reverse_barrier);
+    NtSetInformationThread(GetCurrentThread(), ThreadGroupInformation, &old, sizeof(old));
+}
+
+void WINAPI KeGenericCallDpc(PKDEFERRED_ROUTINE routine, void *context)
+{
+    ULONG cpu_count = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
+    static struct generic_call_dpc_context *contexts;
+    DEFERRED_REVERSE_BARRIER reverse_barrier;
+    static ULONG last_cpu_count;
+    ULONG cpu_count_barrier;
+    ULONG i;
+
+    TRACE("routine %p, context %p.\n", routine, context);
+
+    EnterCriticalSection(&dpc_call_cs);
+
+    if (!dpc_call_tp)
+    {
+        if (!(dpc_call_tp = CreateThreadpool(NULL)))
+        {
+            ERR("Could not create thread pool.\n");
+            LeaveCriticalSection(&dpc_call_cs);
+            return;
+        }
+
+        SetThreadpoolThreadMinimum(dpc_call_tp, cpu_count);
+        SetThreadpoolThreadMaximum(dpc_call_tp, cpu_count);
+
+        memset(&dpc_call_tpe, 0, sizeof(dpc_call_tpe));
+        dpc_call_tpe.Version = 1;
+        dpc_call_tpe.Pool = dpc_call_tp;
+    }
+
+    reverse_barrier.Barrier = cpu_count;
+    reverse_barrier.TotalProcessors = cpu_count;
+    cpu_count_barrier = cpu_count;
+
+    if (contexts)
+    {
+        if (last_cpu_count < cpu_count)
+        {
+            static struct generic_call_dpc_context *new_contexts;
+            if (!(new_contexts = heap_realloc(contexts, sizeof(*contexts) * cpu_count)))
+            {
+                ERR("No memory.\n");
+                LeaveCriticalSection(&dpc_call_cs);
+                return;
+            }
+            contexts = new_contexts;
+            SetThreadpoolThreadMinimum(dpc_call_tp, cpu_count);
+            SetThreadpoolThreadMaximum(dpc_call_tp, cpu_count);
+        }
+    }
+    else if (!(contexts = heap_alloc(sizeof(*contexts) * cpu_count)))
+    {
+        ERR("No memory.\n");
+        LeaveCriticalSection(&dpc_call_cs);
+        return;
+    }
+
+    memset(contexts, 0, sizeof(*contexts) * cpu_count);
+    last_cpu_count = cpu_count;
+
+    for (i = 0; i < cpu_count; ++i)
+    {
+        contexts[i].reverse_barrier = &reverse_barrier;
+        contexts[i].cpu_count_barrier = &cpu_count_barrier;
+        contexts[i].routine = routine;
+        contexts[i].context = context;
+        contexts[i].cpu_index = i;
+
+        TrySubmitThreadpoolCallback(generic_call_dpc_callback, &contexts[i], &dpc_call_tpe);
+    }
+
+    while (InterlockedCompareExchange((LONG *)&cpu_count_barrier, 0, 0))
+        SwitchToThread();
+
+    LeaveCriticalSection(&dpc_call_cs);
+}
+
 void WINAPI KeSignalCallDpcDone(void *barrier)
 {
     InterlockedDecrement((LONG *)barrier);
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
index 28f8d5e4cd..923ba22529 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
+++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
@@ -59,6 +59,7 @@
 @ stub KeSetTimeUpdateNotifyRoutine
 @ stub KefAcquireSpinLockAtDpcLevel
 @ stub KefReleaseSpinLockFromDpcLevel
+@ stdcall KeGenericCallDpc(ptr ptr)
 @ stdcall KeSignalCallDpcDone(ptr)
 @ stub KiAcquireSpinLock
 @ stub KiReleaseSpinLock
diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h
index b11f4d239d..1b001d7424 100644
--- a/include/ddk/wdm.h
+++ b/include/ddk/wdm.h
@@ -122,6 +122,12 @@ typedef struct _KMUTANT {
     UCHAR ApcDisable;
 } KMUTANT, *PKMUTANT, *RESTRICTED_POINTER PRKMUTANT, KMUTEX, *PKMUTEX, *RESTRICTED_POINTER PRKMUTEX;
 
+typedef struct _DEFERRED_REVERSE_BARRIER
+{
+    ULONG Barrier;
+    ULONG TotalProcessors;
+} DEFERRED_REVERSE_BARRIER;
+
 typedef enum _KWAIT_REASON
 {
     Executive,
@@ -1686,6 +1692,7 @@ BOOLEAN   WINAPI KeCancelTimer(KTIMER*);
 void      WINAPI KeClearEvent(PRKEVENT);
 NTSTATUS  WINAPI KeDelayExecutionThread(KPROCESSOR_MODE,BOOLEAN,LARGE_INTEGER*);
 void      WINAPI KeEnterCriticalRegion(void);
+void      WINAPI KeGenericCallDpc(PKDEFERRED_ROUTINE,PVOID);
 ULONG     WINAPI KeGetCurrentProcessorNumber(void);
 PKTHREAD  WINAPI KeGetCurrentThread(void);
 void      WINAPI KeInitializeEvent(PRKEVENT,EVENT_TYPE,BOOLEAN);
-- 
2.26.2




More information about the wine-devel mailing list