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