Most paths that hold both the display_lock and the display_devices_init mutex acquire them in the order just mentioned. However, there are two cases where these are acquired in the opposite order, which with unfortunate thread interactions and timings can lead to a deadlock. Fix these cases to use the same order as the rest of the code.
---
The instance of this deadlock I am seeing happens when enabling the virtual desktop mode with the Wayland driver (with pristine master) with any program. It's a deadlock between two threads calling:
1. `get_display_depth` => first acquires `display_lock` (in `lock_display_devices`) then `display_devices_init` (in `adapter_get_current_settings)` 2. `desktop_update_display_devices` => `add_gpu` => first acquires `display_devices_init` then `display_lock`
The deadlock is not very easy to hit normally, but a sleep like in the attached patch below makes it 100% reproducible for me:
[add_gpu_sleep.patch](/uploads/c08632d7a9dec751840199bdb16fb9a8/add_gpu_sleep.patch)
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Most paths that hold both the display_lock and the display_devices_init mutex acquire them in the order just mentioned. However, there are two cases where these are acquired in the opposite order, which with unfortunate thread interactions and timings can lead to a deadlock. Fix these cases to use the same order as the rest of the code. --- dlls/win32u/sysparams.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 9a43de8fd76..673082056b1 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -1251,8 +1251,8 @@ static void add_gpu( const struct gdi_gpu *gpu, void *param )
if (!ctx->mutex) { - ctx->mutex = get_display_device_init_mutex(); pthread_mutex_lock( &display_lock ); + ctx->mutex = get_display_device_init_mutex(); prepare_devices(); }
@@ -1717,8 +1717,8 @@ static BOOL update_display_cache_from_registry(void)
if (key.LastWriteTime.QuadPart <= last_query_display_time) return TRUE;
- mutex = get_display_device_init_mutex(); pthread_mutex_lock( &display_lock ); + mutex = get_display_device_init_mutex();
clear_display_devices();