From a00b7710ee4e64cecc10bd1f802e45625ff09aef Mon Sep 17 00:00:00 2001 From: Christian Meissl Date: Thu, 20 Jun 2024 21:49:22 +0200 Subject: [PATCH] backend: use distinct event queue for client sys some drivers seem to unconditionally dispatch the default event queue. this can lead to spurious dispatching of wayland-rs managed objects breaking the tls invariant. prevent this from happening by moving everything off the default event queue to a distinct event queue --- wayland-backend/CHANGELOG.md | 2 + wayland-backend/src/sys/client_impl/mod.rs | 59 ++++++---------------- 2 files changed, 18 insertions(+), 43 deletions(-) diff --git a/wayland-backend/CHANGELOG.md b/wayland-backend/CHANGELOG.md index 433ada7baa6..67991e15323 100644 --- a/wayland-backend/CHANGELOG.md +++ b/wayland-backend/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- backend/sys: client dispatching now always uses distinct event queue + #### Additions - `Backend::manage_object` for handling foreign proxies with the sys backend diff --git a/wayland-backend/src/sys/client_impl/mod.rs b/wayland-backend/src/sys/client_impl/mod.rs index 8d427847849..24bc920f075 100644 --- a/wayland-backend/src/sys/client_impl/mod.rs +++ b/wayland-backend/src/sys/client_impl/mod.rs @@ -168,6 +168,7 @@ struct ProxyUserData { #[derive(Debug)] struct ConnectionState { display: *mut wl_display, + owns_display: bool, evq: *mut wl_event_queue, display_id: InnerObjectId, last_error: Option, @@ -247,30 +248,17 @@ impl InnerBackend { wl_log_trampoline_to_rust_client ); } - let display_alive = Arc::new(AtomicBool::new(true)); - Ok(Self { - inner: Arc::new(Inner { - state: Mutex::new(ConnectionState { - display, - evq: std::ptr::null_mut(), - display_id: InnerObjectId { - id: 1, - ptr: display as *mut wl_proxy, - alive: Some(display_alive), - interface: &WL_DISPLAY_INTERFACE, - }, - last_error: None, - known_proxies: HashSet::new(), - }), - debug: has_debug_client_env(), - dispatch_lock: Mutex::new(Dispatcher), - }), - }) + Ok(Self::from_display(display, true)) } pub unsafe fn from_foreign_display(display: *mut wl_display) -> Self { + Self::from_display(display, false) + } + + fn from_display(display: *mut wl_display, owned: bool) -> Self { let evq = unsafe { ffi_dispatch!(wayland_client_handle(), wl_display_create_queue, display) }; + let display_alive = owned.then(|| Arc::new(AtomicBool::new(true))); Self { inner: Arc::new(Inner { state: Mutex::new(ConnectionState { @@ -279,9 +267,10 @@ impl InnerBackend { display_id: InnerObjectId { id: 1, ptr: display as *mut wl_proxy, - alive: None, + alive: display_alive, interface: &WL_DISPLAY_INTERFACE, }, + owns_display: owned, last_error: None, known_proxies: HashSet::new(), }), @@ -387,16 +376,7 @@ impl Dispatcher { // We erase the lifetime of the Handle to be able to store it in the tls, // it's safe as it'll only last until the end of this function call anyway let ret = BACKEND.set(&backend, || unsafe { - if evq.is_null() { - ffi_dispatch!(wayland_client_handle(), wl_display_dispatch_pending, display) - } else { - ffi_dispatch!( - wayland_client_handle(), - wl_display_dispatch_queue_pending, - display, - evq - ) - } + ffi_dispatch!(wayland_client_handle(), wl_display_dispatch_queue_pending, display, evq) }); if ret < 0 { Err(backend @@ -427,11 +407,7 @@ impl InnerReadEventsGuard { }; let ret = unsafe { - if evq.is_null() { - ffi_dispatch!(wayland_client_handle(), wl_display_prepare_read, display) - } else { - ffi_dispatch!(wayland_client_handle(), wl_display_prepare_read_queue, display, evq) - } + ffi_dispatch!(wayland_client_handle(), wl_display_prepare_read_queue, display, evq) }; if ret < 0 { None @@ -648,18 +624,17 @@ impl InnerBackend { } } - let ret = if guard.evq.is_null() || child_spec.is_none() { + let ret = if child_spec.is_none() { unsafe { ffi_dispatch!( wayland_client_handle(), - wl_proxy_marshal_array_constructor_versioned, + wl_proxy_marshal_array, id.ptr, opcode as u32, argument_list.as_mut_ptr(), - child_interface_ptr, - child_version ) } + std::ptr::null_mut() } else { // We are a guest Backend, need to use a wrapper unsafe { @@ -1062,12 +1037,10 @@ impl Drop for ConnectionState { ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, proxy_ptr); } } - if self.evq.is_null() { + unsafe { ffi_dispatch!(wayland_client_handle(), wl_event_queue_destroy, self.evq) } + if self.owns_display { // we own the connection, close it unsafe { ffi_dispatch!(wayland_client_handle(), wl_display_disconnect, self.display) } - } else { - // we don't own the connecton, just destroy the event queue - unsafe { ffi_dispatch!(wayland_client_handle(), wl_event_queue_destroy, self.evq) } } } }