Module: wine Branch: master Commit: 80d1d087877cb2012203927795596fca8da3945b URL: https://gitlab.winehq.org/wine/wine/-/commit/80d1d087877cb2012203927795596fc...
Author: Rémi Bernon rbernon@codeweavers.com Date: Sun Jan 22 12:30:44 2023 +0100
dinput: Keep track of input thread users using public refcounts.
And start the input thread when first user is created, then stop it when last user is destroyed.
The thread will not need to enter the hook critical section on stop, as no public reference are held and devices are already unacquired.
---
dlls/dinput/device.c | 3 +++ dlls/dinput/dinput.c | 3 +++ dlls/dinput/dinput_main.c | 49 +++++++++++++++++++++++--------------------- dlls/dinput/dinput_private.h | 3 +++ 4 files changed, 35 insertions(+), 23 deletions(-)
diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 7f97067bd81..04788b22f9a 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -734,6 +734,7 @@ static ULONG WINAPI dinput_device_Release( IDirectInputDevice8W *iface ) if (!ref) { IDirectInputDevice_Unacquire( iface ); + input_thread_remove_user(); dinput_device_internal_release( impl ); }
@@ -2127,6 +2128,8 @@ void dinput_device_init( struct dinput_device *device, const struct dinput_devic InitializeCriticalSection( &device->crit ); dinput_internal_addref( (device->dinput = dinput) ); device->vtbl = vtbl; + + input_thread_add_user(); }
static const GUID *object_instance_guid( const DIDEVICEOBJECTINSTANCEW *instance ) diff --git a/dlls/dinput/dinput.c b/dlls/dinput/dinput.c index 7cf06364dc3..db367e1f1ba 100644 --- a/dlls/dinput/dinput.c +++ b/dlls/dinput/dinput.c @@ -146,6 +146,7 @@ static ULONG WINAPI dinput7_Release( IDirectInput7W *iface )
if (!ref) { + input_thread_remove_user(); dinput_internal_release( impl ); }
@@ -819,6 +820,8 @@ static HRESULT dinput_create( IUnknown **out ) #else *out = (IUnknown *)&impl->IDirectInput8W_iface; #endif + + input_thread_add_user(); return DI_OK; }
diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index aceed841df5..f264c367305 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -69,6 +69,7 @@ static HWND di_em_win;
static HANDLE dinput_thread; static DWORD dinput_thread_id; +static UINT input_thread_user_count;
static CRITICAL_SECTION dinput_hook_crit; static CRITICAL_SECTION_DEBUG dinput_critsect_debug = @@ -347,34 +348,39 @@ done: return 0; }
-static BOOL WINAPI dinput_thread_start_once( INIT_ONCE *once, void *param, void **context ) +void input_thread_add_user(void) { - HANDLE start_event; - - start_event = CreateEventW( NULL, FALSE, FALSE, NULL ); - if (!start_event) ERR( "failed to create start event, error %lu\n", GetLastError() ); + EnterCriticalSection( &dinput_hook_crit ); + if (!input_thread_user_count++) + { + HANDLE start_event;
- dinput_thread = CreateThread( NULL, 0, dinput_thread_proc, start_event, 0, &dinput_thread_id ); - if (!dinput_thread) ERR( "failed to create internal thread, error %lu\n", GetLastError() ); + TRACE( "Starting input thread.\n" );
- WaitForSingleObject( start_event, INFINITE ); - CloseHandle( start_event ); + if (!(start_event = CreateEventW( NULL, FALSE, FALSE, NULL ))) + ERR( "Failed to create start event, error %lu\n", GetLastError() ); + else if (!(dinput_thread = CreateThread( NULL, 0, dinput_thread_proc, start_event, 0, &dinput_thread_id ))) + ERR( "Failed to create internal thread, error %lu\n", GetLastError() ); + else + WaitForSingleObject( start_event, INFINITE );
- return TRUE; + CloseHandle( start_event ); + } + LeaveCriticalSection( &dinput_hook_crit ); }
-static void dinput_thread_start(void) +void input_thread_remove_user(void) { - static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; - InitOnceExecuteOnce( &init_once, dinput_thread_start_once, NULL, NULL ); -} + EnterCriticalSection( &dinput_hook_crit ); + if (!--input_thread_user_count) + { + TRACE( "Stopping input thread.\n" );
-static void dinput_thread_stop(void) -{ - PostThreadMessageW( dinput_thread_id, WM_USER + 0x10, 0, 0 ); - if (WaitForSingleObject( dinput_thread, 500 ) == WAIT_TIMEOUT) - WARN("Timeout while waiting for internal thread\n"); - CloseHandle( dinput_thread ); + PostThreadMessageW( dinput_thread_id, WM_USER + 0x10, 0, 0 ); + WaitForSingleObject( dinput_thread, INFINITE ); + CloseHandle( dinput_thread ); + } + LeaveCriticalSection( &dinput_hook_crit ); }
void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired ) @@ -384,8 +390,6 @@ void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired ) struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); HANDLE hook_change_finished_event = NULL;
- dinput_thread_start(); - EnterCriticalSection(&dinput_hook_crit);
if (impl->dwCoopLevel & DISCL_FOREGROUND) @@ -468,7 +472,6 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved ) break; case DLL_PROCESS_DETACH: if (reserved) break; - dinput_thread_stop(); unregister_di_em_win_class(); break; } diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h index fb9558716a3..f10d5120c89 100644 --- a/dlls/dinput/dinput_private.h +++ b/dlls/dinput/dinput_private.h @@ -63,6 +63,9 @@ struct DevicePlayer { struct list entry; };
+extern void input_thread_add_user(void); +extern void input_thread_remove_user(void); + extern void dinput_hooks_acquire_device( IDirectInputDevice8W *iface ); extern void dinput_hooks_unacquire_device( IDirectInputDevice8W *iface ); extern int dinput_mouse_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lparam );