Skip to content

Commit

Permalink
Fix focus change deadlock in linux_wayland backend
Browse files Browse the repository at this point in the history
Currently, if a game using the linux_wayland backend loses focus, it
will deadlock with the following stack:

```
(gdb) bt
    at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:38
... (omitted for brevity)
    at src/lib.rs:506
    data=0x7ffc4e5c5fb0, _toplevel=0x558428e38e40, width=800, height=600, _states=0x5584298b6770)
    at src/native/linux_wayland.rs:508
...
   from /lib/x86_64-linux-gnu/libwayland-client.so.0
...
```

What's happening here is that the wayland backend is holding onto the
mutex guard for the `native_display()` when it dispatches the resize
event to event listeners.

This hits the `EventHandler` impl for `Stage` in macroquad 0.4.13, which
attempts to re-lock the `native_display()` while it is already locked by
the wayland backend
https://docs.rs/crate/macroquad/0.4.13/source/src/lib.rs#506

The fix here is to guarantee that the native display is released before
dispatching events.
This looks like it was already done for the `payload.decorations`
codepath, but not for the event handlers. I can't see a motivation for
continuing to hold the lock past where we read the last data off the
display, so I've simply moved the manual drop up to always execute.
  • Loading branch information
Adjective-Object authored and not-fl3 committed Jan 2, 2025
1 parent b4fa8fe commit 9aafb1f
Showing 1 changed file with 2 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/native/linux_wayland.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,7 @@ unsafe extern "C" fn xdg_toplevel_handle_configure(
height: i32,
_states: *mut wl_array,
) -> () {
println!("xdg_toplevel_handle_configure");
assert!(!data.is_null());
let payload: &mut WaylandPayload = &mut *(data as *mut _);
let mut d = crate::native_display().lock().unwrap();
Expand All @@ -497,9 +498,9 @@ unsafe extern "C" fn xdg_toplevel_handle_configure(

d.screen_width = width;
d.screen_height = height;
drop(d);

if let Some(ref decorations) = payload.decorations {
drop(d);
decorations.resize(&mut payload.client, width, height);
}

Expand Down

0 comments on commit 9aafb1f

Please sign in to comment.