From: Alexandros Frantzis alexandros.frantzis@collabora.com
Introduce a thin wrapper around pthread mutex to provide more robust mutex handling and informative error messages in case of suspected deadlock, similarly to ntdll.RtlEnterCriticalSection.
Signed-off-by: Alexandros Frantzis alexandros.frantzis@collabora.com --- dlls/winewayland.drv/wayland.c | 85 +++++++++++++++++++++++++++++-- dlls/winewayland.drv/waylanddrv.h | 15 ++++++ 2 files changed, 95 insertions(+), 5 deletions(-)
diff --git a/dlls/winewayland.drv/wayland.c b/dlls/winewayland.drv/wayland.c index 650a102155b..cd154e1543f 100644 --- a/dlls/winewayland.drv/wayland.c +++ b/dlls/winewayland.drv/wayland.c @@ -28,13 +28,88 @@
#include "wine/debug.h"
+#include <errno.h> +#include <stdlib.h> +#include <time.h> + WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv);
struct wl_display *process_wl_display = NULL;
-static pthread_mutex_t thread_wayland_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +static struct wayland_mutex thread_wayland_mutex = +{ + PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, 0, 0, __FILE__ ": thread_wayland_mutex" +}; static struct wl_list thread_wayland_list = {&thread_wayland_list, &thread_wayland_list};
+/********************************************************************** + * wayland_mutex_lock + * + * Lock a mutex, emitting error messages in cases of suspected deadlock. + * In case of an unrecoverable error abort to ensure the program doesn't + * continue with an inconsistent state. + */ +void wayland_mutex_lock(struct wayland_mutex *wayland_mutex) +{ + UINT tid = GetCurrentThreadId(); + struct timespec timeout; + int err; + + clock_gettime(CLOCK_REALTIME, &timeout); + timeout.tv_sec += 5; + + while (TRUE) + { + err = pthread_mutex_timedlock(&wayland_mutex->mutex, &timeout); + if (!err) break; + + if (err == ETIMEDOUT) + { + ERR("mutex %p %s lock timed out in thread %04x, blocked by %04x, retrying (60 sec)\n", + wayland_mutex, wayland_mutex->name, tid, wayland_mutex->owner_tid); + clock_gettime(CLOCK_REALTIME, &timeout); + timeout.tv_sec += 60; + } + else + { + ERR("error locking mutex %p %s errno=%d, aborting\n", + wayland_mutex, wayland_mutex->name, errno); + abort(); + } + } + + wayland_mutex->owner_tid = tid; + wayland_mutex->lock_count++; +} + +/********************************************************************** + * wayland_mutex_unlock + * + * Unlock a mutex. + */ +void wayland_mutex_unlock(struct wayland_mutex *wayland_mutex) +{ + int err; + + wayland_mutex->lock_count--; + + if (wayland_mutex->lock_count == 0) + { + wayland_mutex->owner_tid = 0; + } + else if (wayland_mutex->lock_count < 0) + { + ERR("mutex %p %s lock_count is %d < 0\n", + wayland_mutex, wayland_mutex->name, wayland_mutex->lock_count); + } + + if ((err = pthread_mutex_unlock(&wayland_mutex->mutex))) + { + ERR("failed to unlock mutex %p %s errno=%d\n", + wayland_mutex, wayland_mutex->name, err); + } +} + /********************************************************************** * Registry handling */ @@ -120,9 +195,9 @@ BOOL wayland_init(struct wayland *wayland) wl_display_roundtrip_queue(wayland->wl_display, wayland->wl_event_queue);
/* Keep a list of all thread wayland instances. */ - pthread_mutex_lock(&thread_wayland_mutex); + wayland_mutex_lock(&thread_wayland_mutex); wl_list_insert(&thread_wayland_list, &wayland->thread_link); - pthread_mutex_unlock(&thread_wayland_mutex); + wayland_mutex_unlock(&thread_wayland_mutex);
wayland->initialized = TRUE;
@@ -138,9 +213,9 @@ void wayland_deinit(struct wayland *wayland) { TRACE("%p\n", wayland);
- pthread_mutex_lock(&thread_wayland_mutex); + wayland_mutex_lock(&thread_wayland_mutex); wl_list_remove(&wayland->thread_link); - pthread_mutex_unlock(&thread_wayland_mutex); + wayland_mutex_unlock(&thread_wayland_mutex);
if (wayland->wl_compositor) wl_compositor_destroy(wayland->wl_compositor); diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index a00a4a850da..3bcc2379a34 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -45,6 +45,14 @@ extern struct wl_display *process_wl_display DECLSPEC_HIDDEN; * Definitions for wayland types */
+struct wayland_mutex +{ + pthread_mutex_t mutex; + UINT owner_tid; + int lock_count; + const char *name; +}; + struct wayland { struct wl_list thread_link; @@ -81,6 +89,13 @@ BOOL wayland_process_init(void) DECLSPEC_HIDDEN; BOOL wayland_init(struct wayland *wayland) DECLSPEC_HIDDEN; void wayland_deinit(struct wayland *wayland) DECLSPEC_HIDDEN;
+/********************************************************************** + * Wayland mutex + */ + +void wayland_mutex_lock(struct wayland_mutex *wayland_mutex) DECLSPEC_HIDDEN; +void wayland_mutex_unlock(struct wayland_mutex *wayland_mutex) DECLSPEC_HIDDEN; + /********************************************************************** * USER driver functions */