wayland: use mutexes to ensure that MwLLDestroyImpl never conflicts with wayland events.

This commit is contained in:
IoIxD
2026-01-03 18:27:34 -07:00
parent bed668b84a
commit a148b3bedf
2 changed files with 86 additions and 8 deletions

View File

@@ -16,6 +16,7 @@
#include <wayland-client.h> #include <wayland-client.h>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include <cairo/cairo.h> #include <cairo/cairo.h>
#include <pthread.h>
MWDECL int MwLLWaylandCallInit(void); MWDECL int MwLLWaylandCallInit(void);
@@ -191,6 +192,12 @@ struct _MwLLWayland {
struct _MwLLWaylandShmBuffer cursor; struct _MwLLWaylandShmBuffer cursor;
struct _MwLLWaylandShmBuffer* icon; struct _MwLLWaylandShmBuffer* icon;
/*
Events mutex. Any time a keyboard/mouse event happens, we try to lock this for 100 milliseconds, then give up if we can't do it. This is used in conjunction with some code in the MwLLDestroyImpl to make sure that destroy is NEVER interferes with an ongoing event.
IOI_XD: This sounds like a hilariously rare edge case, so it's almost funnier that this happened with 100% certainty for me and I spent day(s) trying to figure out what was happening. */
pthread_mutex_t eventsMutex;
cairo_surface_t* cs; cairo_surface_t* cs;
cairo_t* cairo; cairo_t* cairo;
}; };

View File

@@ -340,10 +340,18 @@ static void zwp_primary_selection_device_manager_v1_interface_destroy(struct _Mw
static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial, static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial,
struct wl_surface* surface, wl_fixed_t surface_x, struct wl_surface* surface, wl_fixed_t surface_x,
wl_fixed_t surface_y) { wl_fixed_t surface_y) {
MwLL self = data; MwLL self = data;
struct timespec t;
t.tv_nsec = 100;
if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) {
return;
};
self->wayland.pointer_serial = serial; self->wayland.pointer_serial = serial;
wl_pointer_set_cursor(wl_pointer, serial, self->wayland.cursor.surface, 0, 0); wl_pointer_set_cursor(wl_pointer, serial, self->wayland.cursor.surface, 0, 0);
pthread_mutex_unlock(&self->wayland.eventsMutex);
}; };
/* `wl_pointer.leave` callback */ /* `wl_pointer.leave` callback */
@@ -357,6 +365,12 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time
MwLL self = data; MwLL self = data;
MwLLMouse p; MwLLMouse p;
struct timespec t;
t.tv_nsec = 100;
if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) {
return;
};
self->wayland.cur_mouse_pos.x = wl_fixed_to_double(surface_x); self->wayland.cur_mouse_pos.x = wl_fixed_to_double(surface_x);
self->wayland.cur_mouse_pos.y = wl_fixed_to_double(surface_y); self->wayland.cur_mouse_pos.y = wl_fixed_to_double(surface_y);
@@ -364,14 +378,22 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time
MwLLDispatch(self, move, &p); MwLLDispatch(self, move, &p);
self->wayland.events_pending += 1; self->wayland.events_pending += 1;
pthread_mutex_unlock(&self->wayland.eventsMutex);
/*timed_redraw(self, time, 50, &self->wayland.cooldown_timer);*/ /*timed_redraw(self, time, 50, &self->wayland.cooldown_timer);*/
}; };
/* `wl_pointer.button` callback */ /* `wl_pointer.button` callback */
static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 serial, MwU32 time, MwU32 button, MwU32 state) { static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 serial, MwU32 time, MwU32 button, MwU32 state) {
MwLL self = data; MwLL self = data;
MwLLMouse p; MwLLMouse p;
struct timespec t;
t.tv_nsec = 100;
if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) {
return;
};
p.point = self->wayland.cur_mouse_pos; p.point = self->wayland.cur_mouse_pos;
if(p.point.x > self->wayland.x && p.point.x < self->wayland.x + self->wayland.ww && p.point.y > self->wayland.y && p.point.y < self->wayland.y + self->wayland.wh) { if(p.point.x > self->wayland.x && p.point.x < self->wayland.x + self->wayland.ww && p.point.y > self->wayland.y && p.point.y < self->wayland.y + self->wayland.wh) {
switch(button) { switch(button) {
@@ -403,6 +425,7 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri
MwLLDispatch(self, draw, NULL); MwLLDispatch(self, draw, NULL);
self->wayland.events_pending += 1; self->wayland.events_pending += 1;
} }
pthread_mutex_unlock(&self->wayland.eventsMutex);
}; };
/* `wl_pointer.axis` callback */ /* `wl_pointer.axis` callback */
@@ -450,11 +473,19 @@ static void keyboard_enter(void* data,
MwU32 serial, MwU32 serial,
struct wl_surface* surface, struct wl_surface* surface,
struct wl_array* keys) { struct wl_array* keys) {
MwLL self = data; MwLL self = data;
struct timespec t;
t.tv_nsec = 100;
if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) {
return;
};
self->wayland.keyboard_serial = serial; self->wayland.keyboard_serial = serial;
MwLLDispatch(self, focus_in, NULL); MwLLDispatch(self, focus_in, NULL);
self->wayland.events_pending += 1; self->wayland.events_pending += 1;
pthread_mutex_unlock(&self->wayland.eventsMutex);
}; };
/* `wl_keyboard.leave` callback */ /* `wl_keyboard.leave` callback */
@@ -462,9 +493,18 @@ static void keyboard_leave(void* data,
struct wl_keyboard* wl_keyboard, struct wl_keyboard* wl_keyboard,
MwU32 serial, MwU32 serial,
struct wl_surface* surface) { struct wl_surface* surface) {
MwLL self = data; MwLL self = data;
struct timespec t;
t.tv_nsec = 100;
if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) {
return;
};
MwLLDispatch(self, focus_out, NULL); MwLLDispatch(self, focus_out, NULL);
self->wayland.events_pending += 1; self->wayland.events_pending += 1;
pthread_mutex_unlock(&self->wayland.eventsMutex);
}; };
/* `wl_keyboard.key` callback */ /* `wl_keyboard.key` callback */
@@ -474,7 +514,13 @@ static void keyboard_key(void* data,
MwU32 time, MwU32 time,
MwU32 key, MwU32 key,
MwU32 state) { MwU32 state) {
MwLL self = data; MwLL self = data;
struct timespec t;
t.tv_nsec = 100;
if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) {
return;
};
if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL) { if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL) {
struct _MwLLWaylandTopLevel* wayland = self->wayland.toplevel; struct _MwLLWaylandTopLevel* wayland = self->wayland.toplevel;
xkb_layout_index_t layout; xkb_layout_index_t layout;
@@ -564,6 +610,8 @@ static void keyboard_key(void* data,
MwLLDispatch(self, draw, NULL); MwLLDispatch(self, draw, NULL);
self->wayland.events_pending += 1; self->wayland.events_pending += 1;
} }
pthread_mutex_unlock(&self->wayland.eventsMutex);
}; };
/* `wl_keyboard.modifiers` callback */ /* `wl_keyboard.modifiers` callback */
@@ -574,11 +622,19 @@ static void keyboard_modifiers(void* data,
MwU32 mods_latched, MwU32 mods_latched,
MwU32 mods_locked, MwU32 mods_locked,
MwU32 group) { MwU32 group) {
MwLL self = data; MwLL self = data;
struct timespec t;
t.tv_nsec = 100;
if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) {
return;
};
self->wayland.mod_state = 0; self->wayland.mod_state = 0;
self->wayland.mod_state |= mods_depressed; self->wayland.mod_state |= mods_depressed;
self->wayland.mod_state |= mods_locked; self->wayland.mod_state |= mods_locked;
pthread_mutex_unlock(&self->wayland.eventsMutex);
}; };
struct wl_keyboard_listener keyboard_listener = { struct wl_keyboard_listener keyboard_listener = {
@@ -1305,7 +1361,11 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) {
} }
static void MwLLDestroyImpl(MwLL handle) { static void MwLLDestroyImpl(MwLL handle) {
int i; int i;
struct timeval tv;
int select_ret;
pthread_mutex_lock(&handle->wayland.eventsMutex);
MwLLDestroyCommon(handle); MwLLDestroyCommon(handle);
@@ -1349,6 +1409,16 @@ static void MwLLDestroyImpl(MwLL handle) {
wl_keyboard_destroy(handle->wayland.keyboard); wl_keyboard_destroy(handle->wayland.keyboard);
} }
/* sleep long enough that any active attempts to wait for the mutex will have given up and we can safely unlock/destroy it */
tv.tv_sec = 0;
tv.tv_usec = 250;
do {
select_ret = select(1, NULL, NULL, NULL, &tv);
} while((select_ret == -1) && (errno == EINTR));
pthread_mutex_unlock(&handle->wayland.eventsMutex);
pthread_mutex_destroy(&handle->wayland.eventsMutex);
free(handle); free(handle);
} }
@@ -1465,6 +1535,7 @@ static void MwLLFreeColorImpl(MwLLColor color) {
static int MwLLPendingImpl(MwLL handle) { static int MwLLPendingImpl(MwLL handle) {
MwBool pending = MwFALSE; MwBool pending = MwFALSE;
struct timespec timeout; struct timespec timeout;
int i;
if(handle->wayland.always_render) { if(handle->wayland.always_render) {
return event_loop(handle); return event_loop(handle);