From 9fbdf2b43435caf62742d997bf8b3fb8752f606c Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 9 Jul 2022 15:46:54 -0500 Subject: [PATCH] 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 +#include #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; }