Skip to content

Commit

Permalink
backend: use distinct event queue for client sys
Browse files Browse the repository at this point in the history
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
  • Loading branch information
cmeissl committed Jun 20, 2024
1 parent 48e74e9 commit 34560ff
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 40 deletions.
2 changes: 2 additions & 0 deletions wayland-backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
54 changes: 14 additions & 40 deletions wayland-backend/src/sys/client_impl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<WaylandError>,
Expand Down Expand Up @@ -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 {
Expand All @@ -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(),
}),
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -648,7 +624,7 @@ 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(),
Expand Down Expand Up @@ -1062,12 +1038,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) }
}
}
}

0 comments on commit 34560ff

Please sign in to comment.