Skip to content

Commit

Permalink
WIP Using polling instead of kqueue/epoll
Browse files Browse the repository at this point in the history
  • Loading branch information
ids1024 committed Oct 18, 2024
1 parent 10cb4c7 commit e26f1bf
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 133 deletions.
1 change: 1 addition & 0 deletions wayland-backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
103 changes: 7 additions & 96 deletions wayland-backend/src/rs/server_impl/common_poll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -34,21 +23,8 @@ pub struct InnerBackend<D: 'static> {

impl<D> InnerBackend<D> {
pub fn new() -> Result<Self, InitError> {
#[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<ClientId>) -> std::io::Result<()> {
Expand All @@ -60,7 +36,7 @@ impl<D> InnerBackend<D> {
}

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) }
Expand All @@ -77,56 +53,18 @@ impl<D> InnerBackend<D> {
ret
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn dispatch_all_clients(&self, data: &mut D) -> std::io::Result<usize> {
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<usize> {
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;
Expand Down Expand Up @@ -161,34 +99,7 @@ impl<D> InnerBackend<D> {
}
}
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);
}
};
Expand Down
46 changes: 9 additions & 37 deletions wayland-backend/src/rs/server_impl/handle.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{
ffi::CString,
os::unix::{
io::{OwnedFd, RawFd},
io::{AsFd, RawFd},
net::UnixStream,
},
sync::{Arc, Mutex, Weak},
Expand All @@ -24,19 +24,19 @@ pub struct State<D: 'static> {
pub(crate) clients: ClientStore<D>,
pub(crate) registry: Registry<D>,
pub(crate) pending_destructors: Vec<PendingDestructor<D>>,
pub(crate) poll_fd: OwnedFd,
pub(crate) poller: polling::Poller,
}

impl<D> State<D> {
pub(crate) fn new(poll_fd: OwnedFd) -> Self {
pub(crate) fn new() -> std::io::Result<Self> {
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 {
Expand Down Expand Up @@ -316,37 +316,9 @@ impl<D> ErasedState for State<D> {
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 {
Expand Down

0 comments on commit e26f1bf

Please sign in to comment.