dinput: Simplify the internal thread and don't require loader lock.

When thread shuts down, instead of holding and releasing a module ref.

This keeps the thread alive until the module is unloaded, instead of
keeping track of live IDirectInput instances.

Signed-off-by: Rémi Bernon <rbernon@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Rémi Bernon 2021-12-10 09:44:44 +01:00 committed by Alexandre Julliard
parent 286b99a4a2
commit b67cda8975
2 changed files with 42 additions and 82 deletions

View File

@ -78,9 +78,18 @@ HINSTANCE DINPUT_instance;
static HWND di_em_win; static HWND di_em_win;
static BOOL check_hook_thread(void); static HANDLE dinput_thread;
static DWORD dinput_thread_id;
static CRITICAL_SECTION dinput_hook_crit; static CRITICAL_SECTION dinput_hook_crit;
static struct list direct_input_list = LIST_INIT( direct_input_list ); static CRITICAL_SECTION_DEBUG dinput_critsect_debug =
{
0, 0, &dinput_hook_crit,
{ &dinput_critsect_debug.ProcessLocksList, &dinput_critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": dinput_hook_crit") }
};
static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0, 0 };
static struct list acquired_mouse_list = LIST_INIT( acquired_mouse_list ); static struct list acquired_mouse_list = LIST_INIT( acquired_mouse_list );
static struct list acquired_rawmouse_list = LIST_INIT( acquired_rawmouse_list ); static struct list acquired_rawmouse_list = LIST_INIT( acquired_rawmouse_list );
static struct list acquired_keyboard_list = LIST_INIT( acquired_keyboard_list ); static struct list acquired_keyboard_list = LIST_INIT( acquired_keyboard_list );
@ -453,18 +462,7 @@ static HRESULT initialize_directinput_instance(IDirectInputImpl *This, DWORD dwV
list_init( &This->device_players ); list_init( &This->device_players );
/* Add self to the list of the IDirectInputs */
EnterCriticalSection( &dinput_hook_crit );
list_add_head( &direct_input_list, &This->entry );
LeaveCriticalSection( &dinput_hook_crit );
This->initialized = TRUE; This->initialized = TRUE;
if (!check_hook_thread())
{
uninitialize_directinput_instance( This );
return DIERR_GENERIC;
}
} }
return DI_OK; return DI_OK;
@ -475,17 +473,11 @@ static void uninitialize_directinput_instance(IDirectInputImpl *This)
if (This->initialized) if (This->initialized)
{ {
struct DevicePlayer *device_player, *device_player2; struct DevicePlayer *device_player, *device_player2;
/* Remove self from the list of the IDirectInputs */
EnterCriticalSection( &dinput_hook_crit );
list_remove( &This->entry );
LeaveCriticalSection( &dinput_hook_crit );
LIST_FOR_EACH_ENTRY_SAFE( device_player, device_player2, LIST_FOR_EACH_ENTRY_SAFE( device_player, device_player2,
&This->device_players, struct DevicePlayer, entry ) &This->device_players, struct DevicePlayer, entry )
free( device_player ); free( device_player );
check_hook_thread();
This->initialized = FALSE; This->initialized = FALSE;
} }
} }
@ -1262,13 +1254,13 @@ static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam
return CallNextHookEx( 0, code, wparam, lparam ); return CallNextHookEx( 0, code, wparam, lparam );
} }
static DWORD WINAPI hook_thread_proc(void *param) static DWORD WINAPI dinput_thread_proc( void *params )
{ {
HANDLE events[128], start_event = params;
static HHOOK kbd_hook, mouse_hook; static HHOOK kbd_hook, mouse_hook;
struct dinput_device *impl, *next; struct dinput_device *impl, *next;
SIZE_T events_count = 0; SIZE_T events_count = 0;
HANDLE finished_event; HANDLE finished_event;
HANDLE events[128];
HRESULT hr; HRESULT hr;
DWORD ret; DWORD ret;
MSG msg; MSG msg;
@ -1277,7 +1269,7 @@ static DWORD WINAPI hook_thread_proc(void *param)
/* Force creation of the message queue */ /* Force creation of the message queue */
PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ); PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE );
SetEvent(param); SetEvent( start_event );
while ((ret = MsgWaitForMultipleObjectsEx( events_count, events, INFINITE, QS_ALLINPUT, 0 )) <= events_count) while ((ret = MsgWaitForMultipleObjectsEx( events_count, events, INFINITE, QS_ALLINPUT, 0 )) <= events_count)
{ {
@ -1354,61 +1346,36 @@ static DWORD WINAPI hook_thread_proc(void *param)
done: done:
DestroyWindow( di_em_win ); DestroyWindow( di_em_win );
di_em_win = NULL; di_em_win = NULL;
return 0;
FreeLibraryAndExitThread(DINPUT_instance, 0);
} }
static DWORD hook_thread_id; static BOOL WINAPI dinput_thread_start_once( INIT_ONCE *once, void *param, void **context )
static HANDLE hook_thread_event;
static CRITICAL_SECTION_DEBUG dinput_critsect_debug =
{ {
0, 0, &dinput_hook_crit, HANDLE start_event;
{ &dinput_critsect_debug.ProcessLocksList, &dinput_critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": dinput_hook_crit") }
};
static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0, 0 };
static BOOL check_hook_thread(void) start_event = CreateEventW( NULL, FALSE, FALSE, NULL );
if (!start_event) ERR( "failed to create start event, error %u\n", GetLastError() );
dinput_thread = CreateThread( NULL, 0, dinput_thread_proc, start_event, 0, &dinput_thread_id );
if (!dinput_thread) ERR( "failed to create internal thread, error %u\n", GetLastError() );
WaitForSingleObject( start_event, INFINITE );
CloseHandle( start_event );
return TRUE;
}
static void dinput_thread_start(void)
{ {
static HANDLE hook_thread; static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
HMODULE module; InitOnceExecuteOnce( &init_once, dinput_thread_start_once, NULL, NULL );
HANDLE wait_handle = NULL; }
EnterCriticalSection(&dinput_hook_crit); static void dinput_thread_stop(void)
{
TRACE("IDirectInputs left: %d\n", list_count(&direct_input_list)); PostThreadMessageW( dinput_thread_id, WM_USER + 0x10, 0, 0 );
if (!list_empty(&direct_input_list) && !hook_thread) WaitForSingleObject( dinput_thread, INFINITE );
{ CloseHandle( dinput_thread );
GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const WCHAR*)DINPUT_instance, &module);
hook_thread_event = CreateEventW(NULL, FALSE, FALSE, NULL);
hook_thread = CreateThread(NULL, 0, hook_thread_proc, hook_thread_event, 0, &hook_thread_id);
}
else if (list_empty(&direct_input_list) && hook_thread)
{
DWORD tid = hook_thread_id;
if (hook_thread_event) /* if thread is not started yet */
{
WaitForSingleObject(hook_thread_event, INFINITE);
CloseHandle(hook_thread_event);
hook_thread_event = NULL;
}
hook_thread_id = 0;
PostThreadMessageW(tid, WM_USER+0x10, 0, 0);
wait_handle = hook_thread;
hook_thread = NULL;
}
LeaveCriticalSection(&dinput_hook_crit);
if (wait_handle)
{
WaitForSingleObject(wait_handle, INFINITE);
CloseHandle(wait_handle);
}
return hook_thread_id != 0;
} }
void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired ) void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired )
@ -1418,6 +1385,8 @@ void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired )
struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface );
HANDLE hook_change_finished_event = NULL; HANDLE hook_change_finished_event = NULL;
dinput_thread_start();
EnterCriticalSection(&dinput_hook_crit); EnterCriticalSection(&dinput_hook_crit);
if (impl->dwCoopLevel & DISCL_FOREGROUND) if (impl->dwCoopLevel & DISCL_FOREGROUND)
@ -1437,13 +1406,6 @@ void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired )
callwndproc_hook = NULL; callwndproc_hook = NULL;
} }
if (hook_thread_event) /* if thread is not started yet */
{
WaitForSingleObject(hook_thread_event, INFINITE);
CloseHandle(hook_thread_event);
hook_thread_event = NULL;
}
if (impl->use_raw_input) if (impl->use_raw_input)
{ {
if (acquired) if (acquired)
@ -1470,7 +1432,7 @@ void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired )
} }
hook_change_finished_event = CreateEventW( NULL, FALSE, FALSE, NULL ); hook_change_finished_event = CreateEventW( NULL, FALSE, FALSE, NULL );
PostThreadMessageW( hook_thread_id, WM_USER+0x10, 1, (LPARAM)hook_change_finished_event ); PostThreadMessageW( dinput_thread_id, WM_USER + 0x10, 1, (LPARAM)hook_change_finished_event );
LeaveCriticalSection(&dinput_hook_crit); LeaveCriticalSection(&dinput_hook_crit);
@ -1505,6 +1467,7 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved)
break; break;
case DLL_PROCESS_DETACH: case DLL_PROCESS_DETACH:
if (reserved) break; if (reserved) break;
dinput_thread_stop();
unregister_di_em_win_class(); unregister_di_em_win_class();
DeleteCriticalSection(&dinput_hook_crit); DeleteCriticalSection(&dinput_hook_crit);
break; break;

View File

@ -40,10 +40,7 @@ struct IDirectInputImpl
IDirectInputJoyConfig8 IDirectInputJoyConfig8_iface; IDirectInputJoyConfig8 IDirectInputJoyConfig8_iface;
LONG ref; LONG ref;
BOOL initialized; BOOL initialized;
struct list entry; /* entry into list of all IDirectInputs */
DWORD evsequence; /* unique sequence number for events */ DWORD evsequence; /* unique sequence number for events */
DWORD dwVersion; /* direct input version number */ DWORD dwVersion; /* direct input version number */
struct list device_players; /* device instance guid to player name */ struct list device_players; /* device instance guid to player name */