From e26f1bf9614af47319c6a5ec581d7a8c2e0ce2d6 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 18 Oct 2024 08:54:52 -0700 Subject: [PATCH] WIP Using `polling` instead of `kqueue`/`epoll` --- wayland-backend/Cargo.toml | 1 + .../src/rs/server_impl/common_poll.rs | 103 ++---------------- wayland-backend/src/rs/server_impl/handle.rs | 46 ++------ 3 files changed, 17 insertions(+), 133 deletions(-) diff --git a/wayland-backend/Cargo.toml b/wayland-backend/Cargo.toml index ca4d682f34c..5fb9c57b090 100644 --- a/wayland-backend/Cargo.toml +++ b/wayland-backend/Cargo.toml @@ -20,6 +20,7 @@ scoped-tls = "1.0" downcast-rs = "1.2" raw-window-handle = { version = "0.5.0", optional = true } rwh_06 = { package = "raw-window-handle", version = "0.6.0", optional = true } +polling = "3.7.2" [dependencies.smallvec] version = "1.9" diff --git a/wayland-backend/src/rs/server_impl/common_poll.rs b/wayland-backend/src/rs/server_impl/common_poll.rs index ee8b1ff014a..0126c9cd1ed 100644 --- a/wayland-backend/src/rs/server_impl/common_poll.rs +++ b/wayland-backend/src/rs/server_impl/common_poll.rs @@ -14,17 +14,6 @@ use crate::{ types::server::InitError, }; -#[cfg(any(target_os = "linux", target_os = "android"))] -use rustix::event::epoll; - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - target_os = "macos" -))] -use rustix::event::kqueue::*; use smallvec::SmallVec; #[derive(Debug)] @@ -34,21 +23,8 @@ pub struct InnerBackend { impl InnerBackend { pub fn new() -> Result { - #[cfg(any(target_os = "linux", target_os = "android"))] - let poll_fd = epoll::create(epoll::CreateFlags::CLOEXEC) - .map_err(Into::into) - .map_err(InitError::Io)?; - - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - target_os = "macos" - ))] - let poll_fd = kqueue().map_err(Into::into).map_err(InitError::Io)?; - - Ok(Self { state: Arc::new(Mutex::new(State::new(poll_fd))) }) + let state = State::new().map_err(Into::into).map_err(InitError::Io)?; + Ok(Self { state: Arc::new(Mutex::new(state)) }) } pub fn flush(&self, client: Option) -> std::io::Result<()> { @@ -60,7 +36,7 @@ impl InnerBackend { } pub fn poll_fd(&self) -> BorrowedFd { - let raw_fd = self.state.lock().unwrap().poll_fd.as_raw_fd(); + let raw_fd = self.state.lock().unwrap().poller.as_raw_fd(); // This allows the lifetime of the BorrowedFd to be tied to &self rather than the lock guard, // which is the real safety concern unsafe { BorrowedFd::borrow_raw(raw_fd) } @@ -77,56 +53,18 @@ impl InnerBackend { ret } - #[cfg(any(target_os = "linux", target_os = "android"))] pub fn dispatch_all_clients(&self, data: &mut D) -> std::io::Result { - use std::os::unix::io::AsFd; - - let poll_fd = self.poll_fd(); let mut dispatched = 0; loop { - let mut events = epoll::EventVec::with_capacity(32); - epoll::wait(poll_fd.as_fd(), &mut events, 0)?; + let mut events = polling::Events::new(); // TODO with capacity? + self.state.lock().unwrap().poller.wait(&mut events, Some(std::time::Duration::ZERO))?; if events.is_empty() { break; } for event in events.iter() { - let id = InnerClientId::from_u64(event.data.u64()); - // remove the cb while we call it, to gracefully handle reentrancy - if let Ok(count) = self.dispatch_events_for(data, id) { - dispatched += count; - } - } - let cleanup = self.state.lock().unwrap().cleanup(); - cleanup(&self.handle(), data); - } - - Ok(dispatched) - } - - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - target_os = "macos" - ))] - pub fn dispatch_all_clients(&self, data: &mut D) -> std::io::Result { - use std::time::Duration; - - let poll_fd = self.poll_fd(); - let mut dispatched = 0; - loop { - let mut events = Vec::with_capacity(32); - let nevents = unsafe { kevent(&poll_fd, &[], &mut events, Some(Duration::ZERO))? }; - - if nevents == 0 { - break; - } - - for event in events.iter().take(nevents) { - let id = InnerClientId::from_u64(event.udata() as u64); + let id = InnerClientId::from_u64(event.key as u64); // remove the cb while we call it, to gracefully handle reentrancy if let Ok(count) = self.dispatch_events_for(data, id) { dispatched += count; @@ -161,34 +99,7 @@ impl InnerBackend { } } Err(e) => { - #[cfg(any(target_os = "linux", target_os = "android"))] - { - epoll::delete(&state.poll_fd, client)?; - } - - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - target_os = "macos" - ))] - { - use rustix::event::kqueue::*; - use std::os::unix::io::{AsFd, AsRawFd}; - - let evt = Event::new( - EventFilter::Read(client.as_fd().as_raw_fd()), - EventFlags::DELETE, - client_id.as_u64() as isize, - ); - - let mut events = Vec::new(); - unsafe { - kevent(&state.poll_fd, &[evt], &mut events, None) - .map(|_| ())?; - } - } + let _ = state.poller.delete(client); return Err(e); } }; diff --git a/wayland-backend/src/rs/server_impl/handle.rs b/wayland-backend/src/rs/server_impl/handle.rs index 7d1cff1ce08..5bdadcaeff7 100644 --- a/wayland-backend/src/rs/server_impl/handle.rs +++ b/wayland-backend/src/rs/server_impl/handle.rs @@ -1,7 +1,7 @@ use std::{ ffi::CString, os::unix::{ - io::{OwnedFd, RawFd}, + io::{AsFd, RawFd}, net::UnixStream, }, sync::{Arc, Mutex, Weak}, @@ -24,19 +24,19 @@ pub struct State { pub(crate) clients: ClientStore, pub(crate) registry: Registry, pub(crate) pending_destructors: Vec>, - pub(crate) poll_fd: OwnedFd, + pub(crate) poller: polling::Poller, } impl State { - pub(crate) fn new(poll_fd: OwnedFd) -> Self { + pub(crate) fn new() -> std::io::Result { let debug = matches!(std::env::var_os("WAYLAND_DEBUG"), Some(str) if str == "1" || str == "server"); - Self { + Ok(Self { clients: ClientStore::new(debug), registry: Registry::new(), pending_destructors: Vec::new(), - poll_fd, - } + poller: polling::Poller::new()?, + }) } pub(crate) fn cleanup<'a>(&mut self) -> impl FnOnce(&super::Handle, &mut D) + 'a { @@ -316,37 +316,9 @@ impl ErasedState for State { let id = self.clients.create_client(stream, data); let client = self.clients.get_client(id.clone()).unwrap(); - // register the client to the internal epoll - #[cfg(any(target_os = "linux", target_os = "android"))] - let ret = { - use rustix::event::epoll; - epoll::add( - &self.poll_fd, - client, - epoll::EventData::new_u64(id.as_u64()), - epoll::EventFlags::IN, - ) - }; - - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - target_os = "macos" - ))] - let ret = { - use rustix::event::kqueue::*; - use std::os::unix::io::{AsFd, AsRawFd}; - - let evt = Event::new( - EventFilter::Read(client.as_fd().as_raw_fd()), - EventFlags::ADD | EventFlags::RECEIPT, - id.as_u64() as isize, - ); - - let mut events = Vec::new(); - unsafe { kevent(&self.poll_fd, &[evt], &mut events, None).map(|_| ()) } + // XXX 32-bit usize + let ret = unsafe { + self.poller.add(&client.as_fd(), polling::Event::writable(id.as_u64() as usize)) }; match ret {