Flush Wayland events before having to send too many file descriptors at once

Works around a bug in the wayland-backend dependency failing to limit
the number of file descriptors sent in one message to MAX_FDS_OUT = 28
This commit is contained in:
Gergő Sályi 2025-04-24 14:50:24 +02:00
parent cd22b9bebe
commit 6eec049e48
2 changed files with 30 additions and 9 deletions

View file

@ -13,7 +13,8 @@ use std::{
sync::{
Arc,
mpsc::{channel, Receiver},
}
},
rc::Rc,
};
use clap::Parser;
@ -50,6 +51,7 @@ use crate::{
};
pub struct State {
pub connection: Rc<Connection>,
pub compositor_state: CompositorState,
pub registry_state: RegistryState,
pub output_state: OutputState,
@ -95,7 +97,7 @@ fn run() -> anyhow::Result<()> {
// Initialize wayland client
// ********************************
let conn = Connection::connect_to_env().unwrap();
let conn = Rc::new(Connection::connect_to_env().unwrap());
let (globals, mut event_queue) = registry_queue_init(&conn).unwrap();
let qh = event_queue.handle();
@ -150,6 +152,7 @@ fn run() -> anyhow::Result<()> {
.unwrap_or(Compositor::Sway);
let mut state = State {
connection: Rc::clone(&conn),
compositor_state,
registry_state,
output_state: OutputState::new(&globals, &qh),
@ -185,7 +188,7 @@ fn run() -> anyhow::Result<()> {
let token_signal = signal_pipe.as_ref().map(|pipe| poll.add_readable(pipe));
loop {
flush_blocking(&event_queue);
flush_blocking(&conn);
let read_guard = ensure_prepare_read(&mut state, &mut event_queue);
poll.poll().expect("Main event loop poll failed");
if poll.ready(token_wayland) {
@ -218,15 +221,15 @@ fn run() -> anyhow::Result<()> {
}
}
fn flush_blocking(event_queue: &EventQueue<State>) {
fn flush_blocking(connection: &Connection) {
loop {
let result = event_queue.flush();
let result = connection.flush();
if result.is_ok() { return }
if let Err(WaylandError::Io(io_error)) = &result {
if io_error.kind() == io::ErrorKind::WouldBlock {
warn!("Wayland flush needs to block");
let mut poll_fds = [PollFd::from_borrowed_fd(
event_queue.as_fd(),
connection.as_fd(),
PollFlags::OUT,
)];
retry_on_intr(|| poll(&mut poll_fds, -1)).unwrap();

View file

@ -49,7 +49,7 @@ use smithay_client_toolkit::reexports::protocols::wp::{
};
use crate::{
State,
flush_blocking, State,
gpu::{
DRM_FORMAT_XRGB8888, fmt_modifier,
GpuMemory, GpuUploader, GpuWallpaper,
@ -57,6 +57,8 @@ use crate::{
image::{load_wallpaper, output_wallpaper_files, WallpaperFile},
};
const MAX_FDS_OUT: usize = 28;
impl CompositorHandler for State {
fn scale_factor_changed(
&mut self,
@ -937,6 +939,8 @@ fn load_wallpapers(
let mut reused_count = 0usize;
let mut loaded_count = 0usize;
let mut error_count = 0usize;
flush_blocking(&state.connection);
let mut fds_need_flush = 0usize;
for wallpaper_file in wallpaper_files {
if log::log_enabled!(log::Level::Debug) {
if wallpaper_file.path == wallpaper_file.canon_path {
@ -992,6 +996,12 @@ fn load_wallpapers(
}
match uploader.upload() {
Ok(gpu_wallpaper) => {
let fds_count = gpu_wallpaper.memory_planes_len;
if fds_need_flush + fds_count > MAX_FDS_OUT {
flush_blocking(&state.connection);
fds_need_flush = 0;
}
fds_need_flush += fds_count;
let wallpaper = wallpaper_dmabuf(
&state.dmabuf_state,
qh,
@ -1015,6 +1025,11 @@ fn load_wallpapers(
}
}
}
if fds_need_flush + 1 > MAX_FDS_OUT {
flush_blocking(&state.connection);
fds_need_flush = 0;
}
fds_need_flush += 1;
let mut shm_pool = match RawPool::new(shm_size, &state.shm) {
Ok(shm_pool) => shm_pool,
Err(e) => {
@ -1058,8 +1073,11 @@ fn load_wallpapers(
});
loaded_count += 1;
}
debug!("Wallpapers for new output: {} reused, {} loaded, {} errors",
reused_count, loaded_count, error_count);
if fds_need_flush > 0 {
flush_blocking(&state.connection);
}
debug!("Wallpapers for new output: {} loaded, {} reused, {} errors",
loaded_count, reused_count, error_count);
debug!("Wallpapers are available for workspaces: {}",
workspace_backgrounds.iter()
.map(|bg| bg.workspace_name.as_str())