Zebediah Figura : ntoskrnl: Enumerate child devices on a separate thread.

Alexandre Julliard julliard at winehq.org
Mon Jul 11 15:51:38 CDT 2022


Module: wine
Branch: master
Commit: 9fbdf2b43435caf62742d997bf8b3fb8752f606c
URL:    https://gitlab.winehq.org/wine/wine/-/commit/9fbdf2b43435caf62742d997bf8b3fb8752f606c

Author: Zebediah Figura <zfigura at codeweavers.com>
Date:   Sat Jul  9 15:46:54 2022 -0500

ntoskrnl: Enumerate child devices on a separate thread.

---

 dlls/ntoskrnl.exe/ntoskrnl_private.h |  1 +
 dlls/ntoskrnl.exe/pnp.c              | 40 +++++++++++++++++++++++++++++++++++-
 dlls/ntoskrnl.exe/tests/driver_pnp.c | 10 ++++-----
 3 files changed, 45 insertions(+), 6 deletions(-)

diff --git a/dlls/ntoskrnl.exe/ntoskrnl_private.h b/dlls/ntoskrnl.exe/ntoskrnl_private.h
index c736a9805a0..ef1fa99057c 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl_private.h
+++ b/dlls/ntoskrnl.exe/ntoskrnl_private.h
@@ -22,6 +22,7 @@
 #define __WINE_NTOSKRNL_PRIVATE_H
 
 #include <stdarg.h>
+#include <stdbool.h>
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
 #include "windef.h"
diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c
index 5d9ca2dca38..71c03586897 100644
--- a/dlls/ntoskrnl.exe/pnp.c
+++ b/dlls/ntoskrnl.exe/pnp.c
@@ -38,6 +38,12 @@ DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
 
 WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
 
+DECLARE_CRITICAL_SECTION(invalidated_devices_cs);
+static CONDITION_VARIABLE invalidated_devices_cv = CONDITION_VARIABLE_INIT;
+
+static DEVICE_OBJECT **invalidated_devices;
+static size_t invalidated_devices_count;
+
 static inline const char *debugstr_propkey( const DEVPROPKEY *id )
 {
     if (!id) return "(null)";
@@ -468,8 +474,14 @@ void WINAPI IoInvalidateDeviceRelations( DEVICE_OBJECT *device_object, DEVICE_RE
     switch (type)
     {
         case BusRelations:
-            handle_bus_relations( device_object );
+            EnterCriticalSection( &invalidated_devices_cs );
+            invalidated_devices = realloc( invalidated_devices,
+                    (invalidated_devices_count + 1) * sizeof(*invalidated_devices) );
+            invalidated_devices[invalidated_devices_count++] = device_object;
+            LeaveCriticalSection( &invalidated_devices_cs );
+            WakeConditionVariable( &invalidated_devices_cv );
             break;
+
         default:
             FIXME("Unhandled relation %#x.\n", type);
             break;
@@ -1086,6 +1098,30 @@ static NTSTATUS WINAPI pnp_manager_driver_entry( DRIVER_OBJECT *driver, UNICODE_
     return STATUS_SUCCESS;
 }
 
+static DWORD CALLBACK device_enum_thread_proc(void *arg)
+{
+    for (;;)
+    {
+        DEVICE_OBJECT *device;
+
+        EnterCriticalSection( &invalidated_devices_cs );
+
+        while (!invalidated_devices_count)
+            SleepConditionVariableCS( &invalidated_devices_cv, &invalidated_devices_cs, INFINITE );
+
+        device = invalidated_devices[--invalidated_devices_count];
+
+        /* Don't hold the CS while enumerating the device. Tests show that
+         * calling IoInvalidateDeviceRelations() from another thread shouldn't
+         * block, even if this thread is blocked in an IRP handler. */
+        LeaveCriticalSection( &invalidated_devices_cs );
+
+        handle_bus_relations( device );
+    }
+
+    return 0;
+}
+
 void pnp_manager_start(void)
 {
     static const WCHAR driver_nameW[] = {'\\','D','r','i','v','e','r','\\','P','n','p','M','a','n','a','g','e','r',0};
@@ -1109,6 +1145,8 @@ void pnp_manager_start(void)
     RpcStringFreeW( &binding_str );
     if (err)
         ERR("RpcBindingFromStringBinding() failed, error %#lx\n", err);
+
+    CreateThread( NULL, 0, device_enum_thread_proc, NULL, 0, NULL );
 }
 
 void pnp_manager_stop_driver( struct wine_driver *driver )
diff --git a/dlls/ntoskrnl.exe/tests/driver_pnp.c b/dlls/ntoskrnl.exe/tests/driver_pnp.c
index 4b269f00bfc..9727292d65d 100644
--- a/dlls/ntoskrnl.exe/tests/driver_pnp.c
+++ b/dlls/ntoskrnl.exe/tests/driver_pnp.c
@@ -272,11 +272,11 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp)
             device->power_state = PowerDeviceD0;
 
             status = ZwWaitForSingleObject(device->plug_event, TRUE, &wait_time);
-            todo_wine ok(!status, "Failed to wait for child plug event, status %#lx.\n", status);
+            ok(!status, "Failed to wait for child plug event, status %#lx.\n", status);
             status = ZwSetEvent(device->plug_event2, NULL);
             ok(!status, "Failed to set event, status %#lx.\n", status);
             status = ZwWaitForSingleObject(device->plug_event, TRUE, &wait_time);
-            todo_wine ok(!status, "Failed to wait for child plug event, status %#lx.\n", status);
+            ok(!status, "Failed to wait for child plug event, status %#lx.\n", status);
 
             ret = STATUS_SUCCESS;
             break;
@@ -692,15 +692,15 @@ static NTSTATUS fdo_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG code)
              * for the other. */
 
             status = ZwSetEvent(plug_event, NULL);
-            todo_wine ok(!status, "Failed to set event, status %#lx.\n", status);
+            ok(!status, "Failed to set event, status %#lx.\n", status);
             status = ZwWaitForSingleObject(plug_event2, TRUE, &wait_time);
-            todo_wine ok(!status, "Failed to wait for child plug event, status %#lx.\n", status);
+            ok(!status, "Failed to wait for child plug event, status %#lx.\n", status);
             ok(surprise_removal_count == 1, "Got %u surprise removal events.\n", surprise_removal_count);
             /* We shouldn't get IRP_MN_REMOVE_DEVICE until all user-space
              * handles to the device are closed (and the user-space thread is
              * currently blocked in this ioctl and won't close its handle
              * yet.) */
-            todo_wine ok(!remove_device_count, "Got %u remove events.\n", remove_device_count);
+            ok(!remove_device_count, "Got %u remove events.\n", remove_device_count);
 
             return STATUS_SUCCESS;
         }




More information about the wine-cvs mailing list