Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP backend/rs: Using polling instead of kqueue/epoll #763

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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(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,44 +316,16 @@
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 {
Ok(()) => Ok(id),
Err(e) => {
self.kill_client(id, DisconnectReason::ConnectionClosed);
Err(e.into())

Check failure on line 328 in wayland-backend/src/rs/server_impl/handle.rs

View workflow job for this annotation

GitHub Actions / clippy

useless conversion to the same type: `std::io::Error`

error: useless conversion to the same type: `std::io::Error` --> wayland-backend/src/rs/server_impl/handle.rs:328:21 | 328 | Err(e.into()) | ^^^^^^^^ help: consider removing `.into()`: `e` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion = note: `-D clippy::useless-conversion` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::useless_conversion)]`

Check failure on line 328 in wayland-backend/src/rs/server_impl/handle.rs

View workflow job for this annotation

GitHub Actions / clippy

useless conversion to the same type: `std::io::Error`

error: useless conversion to the same type: `std::io::Error` --> wayland-backend/src/rs/server_impl/handle.rs:328:21 | 328 | Err(e.into()) | ^^^^^^^^ help: consider removing `.into()`: `e` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion = note: `-D clippy::useless-conversion` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::useless_conversion)]`
}
}
}
Expand Down
Loading