[PATCH 1/6] ntoskrnl.exe: Implement KeWaitForMultipleObjects().

Zebediah Figura z.figura12 at gmail.com
Sat Nov 24 22:34:38 CST 2018


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
We have plenty of space in which to store a kernel handle inside a
DISPATCHER_HEADER. However, the storage is volatile, and there is no way to
know when to close it. Therefore, we create the handle when
KeWaitForMultipleObjects() is called, and keep it open as long as at least
one thread is waiting on the object.

 dlls/ntoskrnl.exe/Makefile.in |   3 +-
 dlls/ntoskrnl.exe/ntoskrnl.c  |  13 -----
 dlls/ntoskrnl.exe/sync.c      | 114 ++++++++++++++++++++++++++++++++++++++++++
 include/ddk/ntddk.h           |   9 ----
 include/ddk/wdm.h             |  10 ++++
 5 files changed, 126 insertions(+), 23 deletions(-)
 create mode 100644 dlls/ntoskrnl.exe/sync.c

diff --git a/dlls/ntoskrnl.exe/Makefile.in b/dlls/ntoskrnl.exe/Makefile.in
index afb22fe3e0..8cafaada85 100644
--- a/dlls/ntoskrnl.exe/Makefile.in
+++ b/dlls/ntoskrnl.exe/Makefile.in
@@ -5,6 +5,7 @@ DELAYIMPORTS = setupapi user32
 
 C_SRCS = \
 	instr.c \
-	ntoskrnl.c
+	ntoskrnl.c \
+	sync.c
 
 RC_SRCS = ntoskrnl.rc
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 3b42e29b27..4c84a789d6 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -2488,19 +2488,6 @@ NTSTATUS WINAPI KeWaitForSingleObject(PVOID Object,
     return STATUS_NOT_IMPLEMENTED;
 }
 
-/***********************************************************************
- *           KeWaitForMultipleObjects   (NTOSKRNL.EXE.@)
- */
-NTSTATUS WINAPI KeWaitForMultipleObjects(ULONG Count, PVOID Object[], WAIT_TYPE WaitType,
-                                         KWAIT_REASON WaitReason, KPROCESSOR_MODE WaitMode,
-                                         BOOLEAN Alertable, PLARGE_INTEGER Timeout,
-                                         PKWAIT_BLOCK WaitBlockArray)
-{
-    FIXME( "stub: %u, %p, %d, %d, %d, %d, %p, %p\n", Count, Object, WaitType, WaitReason, WaitMode,
-           Alertable, Timeout, WaitBlockArray );
-    return STATUS_NOT_IMPLEMENTED;
-}
-
 /***********************************************************************
  *           IoRegisterFileSystem   (NTOSKRNL.EXE.@)
  */
diff --git a/dlls/ntoskrnl.exe/sync.c b/dlls/ntoskrnl.exe/sync.c
new file mode 100644
index 0000000000..19af4f677a
--- /dev/null
+++ b/dlls/ntoskrnl.exe/sync.c
@@ -0,0 +1,114 @@
+/*
+ * Kernel synchronization
+ *
+ * Copyright (C) 2018 Zebediah Figura
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winbase.h"
+#include "winternl.h"
+#include "ddk/ntddk.h"
+#include "ddk/wdm.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(ntoskrnl);
+
+enum object_type
+{
+    TYPE_MANUAL_EVENT = 0,
+    TYPE_AUTO_EVENT = 1,
+};
+
+static CRITICAL_SECTION sync_cs;
+static CRITICAL_SECTION_DEBUG sync_cs_debug =
+{
+    0, 0, &sync_cs,
+    { &sync_cs_debug.ProcessLocksList, &sync_cs_debug.ProcessLocksList },
+    0, 0, { (DWORD_PTR)(__FILE__ ": sync_cs") }
+};
+static CRITICAL_SECTION sync_cs = { &sync_cs_debug, -1, 0, 0, 0, 0 };
+
+/***********************************************************************
+ *           KeWaitForMultipleObjects   (NTOSKRNL.EXE.@)
+ */
+NTSTATUS WINAPI KeWaitForMultipleObjects(ULONG count, void *pobjs[],
+    WAIT_TYPE wait_type, KWAIT_REASON reason, KPROCESSOR_MODE mode,
+    BOOLEAN alertable, LARGE_INTEGER *timeout, KWAIT_BLOCK *wait_blocks)
+{
+    DISPATCHER_HEADER **objs = (DISPATCHER_HEADER **)pobjs;
+    HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+    NTSTATUS ret;
+    ULONG i;
+
+    TRACE("count %u, objs %p, wait_type %u, reason %u, mode %d, alertable %u, timeout %p, wait_blocks %p.\n",
+        count, objs, wait_type, reason, mode, alertable, timeout, wait_blocks);
+
+    /* We co-opt DISPATCHER_HEADER.WaitListHead:
+     * Blink stores a handle to the synchronization object,
+     * Flink stores the number of threads currently waiting on this object. */
+
+    EnterCriticalSection( &sync_cs );
+    for (i = 0; i < count; i++)
+    {
+        ++*((ULONG_PTR *)&objs[i]->WaitListHead.Flink);
+        if (!objs[i]->WaitListHead.Blink)
+        {
+            switch (objs[i]->Type)
+            {
+            case TYPE_MANUAL_EVENT:
+                objs[i]->WaitListHead.Blink = CreateEventW( NULL, TRUE, objs[i]->SignalState, NULL );
+                break;
+            case TYPE_AUTO_EVENT:
+                objs[i]->WaitListHead.Blink = CreateEventW( NULL, FALSE, objs[i]->SignalState, NULL );
+                break;
+            }
+        }
+
+        handles[i] = objs[i]->WaitListHead.Blink;
+    }
+    LeaveCriticalSection( &sync_cs );
+
+    ret = NtWaitForMultipleObjects( count, handles, (wait_type == WaitAny), alertable, timeout );
+
+    EnterCriticalSection( &sync_cs );
+    for (i = 0; i < count; i++)
+    {
+        if (ret == i || (!ret && wait_type == WaitAll))
+        {
+            switch (objs[i]->Type)
+            {
+            case TYPE_AUTO_EVENT:
+                objs[i]->SignalState = FALSE;
+                break;
+            }
+        }
+
+        if (!--*((ULONG_PTR *)&objs[i]->WaitListHead.Flink))
+        {
+            CloseHandle(objs[i]->WaitListHead.Blink);
+            objs[i]->WaitListHead.Blink = NULL;
+        }
+    }
+    LeaveCriticalSection( &sync_cs );
+
+    return ret;
+}
diff --git a/include/ddk/ntddk.h b/include/ddk/ntddk.h
index fdf035d148..dc051e1e18 100644
--- a/include/ddk/ntddk.h
+++ b/include/ddk/ntddk.h
@@ -140,15 +140,6 @@ typedef struct _FILE_VALID_DATA_LENGTH_INFORMATION
   LARGE_INTEGER ValidDataLength;
 } FILE_VALID_DATA_LENGTH_INFORMATION, *PFILE_VALID_DATA_LENGTH_INFORMATION;
 
-typedef struct _KWAIT_BLOCK {
-    LIST_ENTRY WaitListEntry;
-    struct _KTHREAD *RESTRICTED_POINTER Thread;
-    PVOID Object;
-    struct _KWAIT_BLOCK *RESTRICTED_POINTER NextWaitBlock;
-    USHORT WaitKey;
-    USHORT WaitType;
-} KWAIT_BLOCK, *PKWAIT_BLOCK, *RESTRICTED_POINTER PRKWAIT_BLOCK;
-
 typedef struct _RTL_BALANCED_LINKS {
     struct _RTL_BALANCED_LINKS *Parent;
     struct _RTL_BALANCED_LINKS *LeftChild;
diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h
index cd057d5a9f..ec2fc151ec 100644
--- a/include/ddk/wdm.h
+++ b/include/ddk/wdm.h
@@ -144,6 +144,15 @@ typedef enum _KWAIT_REASON
     MaximumWaitReason,
 } KWAIT_REASON;
 
+typedef struct _KWAIT_BLOCK {
+    LIST_ENTRY WaitListEntry;
+    struct _KTHREAD *RESTRICTED_POINTER Thread;
+    PVOID Object;
+    struct _KWAIT_BLOCK *RESTRICTED_POINTER NextWaitBlock;
+    USHORT WaitKey;
+    USHORT WaitType;
+} KWAIT_BLOCK, *PKWAIT_BLOCK, *RESTRICTED_POINTER PRKWAIT_BLOCK;
+
 typedef struct _ALLOCATE_FUNCTION *PALLOCATE_FUNCTION;
 typedef struct _IO_TIMER *PIO_TIMER;
 typedef struct _IO_TIMER_ROUTINE *PIO_TIMER_ROUTINE;
@@ -1422,6 +1431,7 @@ LONG      WINAPI KeResetEvent(PRKEVENT);
 LONG      WINAPI KeSetEvent(PRKEVENT,KPRIORITY,BOOLEAN);
 KPRIORITY WINAPI KeSetPriorityThread(PKTHREAD,KPRIORITY);
 void      WINAPI KeSetSystemAffinityThread(KAFFINITY);
+NTSTATUS  WINAPI KeWaitForMultipleObjects(ULONG,void*[],WAIT_TYPE,KWAIT_REASON,KPROCESSOR_MODE,BOOLEAN,LARGE_INTEGER*,KWAIT_BLOCK*);
 
 PVOID     WINAPI MmAllocateContiguousMemory(SIZE_T,PHYSICAL_ADDRESS);
 PVOID     WINAPI MmAllocateNonCachedMemory(SIZE_T);
-- 
2.14.1




More information about the wine-devel mailing list