Brendan Shanks : sechost: Fix hang when a device notification callback tries to register/unregister a notify.
Alexandre Julliard
julliard at winehq.org
Tue Nov 9 15:55:06 CST 2021
Module: wine
Branch: master
Commit: b9b4c215f5725446ef649e5be2ab9075485fc551
URL: https://source.winehq.org/git/wine.git/?a=commit;h=b9b4c215f5725446ef649e5be2ab9075485fc551
Author: Brendan Shanks <bshanks at codeweavers.com>
Date: Mon Nov 8 14:38:57 2021 -0800
sechost: Fix hang when a device notification callback tries to register/unregister a notify.
Fixes 4 second hang in Yooka-Laylee and the Impossible Lair when a
controller is connected.
Signed-off-by: Brendan Shanks <bshanks at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/sechost/service.c | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/dlls/sechost/service.c b/dlls/sechost/service.c
index c447263bd0f..e6f4eb75db0 100644
--- a/dlls/sechost/service.c
+++ b/dlls/sechost/service.c
@@ -1992,9 +1992,11 @@ static DWORD WINAPI device_notify_proc( void *arg )
RPC_WSTR binding_str;
DWORD err = ERROR_SUCCESS;
struct device_notify_registration *registration;
+ struct device_notification_details *details_copy;
+ unsigned int details_copy_nelems, details_copy_size;
plugplay_rpc_handle handle = NULL;
DWORD code = 0;
- unsigned int size;
+ unsigned int i, size;
BYTE *buf;
if ((err = RpcStringBindingComposeW( NULL, protseq, NULL, endpoint, NULL, &binding_str )))
@@ -2026,6 +2028,9 @@ static DWORD WINAPI device_notify_proc( void *arg )
return 1;
}
+ details_copy_size = 8;
+ details_copy = heap_alloc( details_copy_size * sizeof(*details_copy) );
+
for (;;)
{
buf = NULL;
@@ -2046,15 +2051,31 @@ static DWORD WINAPI device_notify_proc( void *arg )
break;
}
+ /* Make a copy to avoid a hang if a callback tries to register or unregister for notifications. */
+ i = 0;
+ details_copy_nelems = 0;
EnterCriticalSection( &service_cs );
LIST_FOR_EACH_ENTRY(registration, &device_notify_list, struct device_notify_registration, entry)
{
- registration->details.cb( registration->details.handle, code, (DEV_BROADCAST_HDR *)buf );
+ details_copy[i++] = registration->details;
+ details_copy_nelems++;
+ if (i == details_copy_size)
+ {
+ details_copy_size *= 2;
+ details_copy = heap_realloc( details_copy, details_copy_size * sizeof(*details_copy) );
+ }
}
LeaveCriticalSection(&service_cs);
+
+ for (i = 0; i < details_copy_nelems; i++)
+ {
+ details_copy[i].cb( details_copy[i].handle, code, (DEV_BROADCAST_HDR *)buf );
+ }
MIDL_user_free(buf);
}
+ heap_free( details_copy );
+
__TRY
{
plugplay_unregister_listener( handle );
More information about the wine-cvs
mailing list