use std::io;
use std::os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd};
use std::sync::Arc;
use std::time::Duration;
use super::Readiness;
const WAKE: u64 = u64::MAX;
pub(crate) struct Poller {
epoll: Arc<OwnedFd>,
wake: Arc<OwnedFd>,
events: Vec<libc::epoll_event>,
}
#[derive(Clone)]
pub(crate) struct Notifier {
wake: Arc<OwnedFd>,
}
#[derive(Clone)]
pub(crate) struct Registrar {
epoll: Arc<OwnedFd>,
}
fn check(ret: libc::c_int) -> io::Result<libc::c_int> {
if ret < 0 {
Err(io::Error::last_os_error())
} else {
Ok(ret)
}
}
impl Poller {
pub(crate) fn new() -> io::Result<Self> {
unsafe {
let epoll = OwnedFd::from_raw_fd(check(libc::epoll_create1(libc::EPOLL_CLOEXEC))?);
let wake = OwnedFd::from_raw_fd(check(libc::eventfd(
0,
libc::EFD_CLOEXEC | libc::EFD_NONBLOCK,
))?);
let mut event = libc::epoll_event {
events: (libc::EPOLLIN | libc::EPOLLET) as u32,
u64: WAKE,
};
check(libc::epoll_ctl(
epoll.as_raw_fd(),
libc::EPOLL_CTL_ADD,
wake.as_raw_fd(),
&mut event,
))?;
Ok(Self {
epoll: Arc::new(epoll),
wake: Arc::new(wake),
events: Vec::with_capacity(256),
})
}
}
pub(crate) fn notifier(&self) -> Notifier {
Notifier {
wake: Arc::clone(&self.wake),
}
}
pub(crate) fn registrar(&self) -> Registrar {
Registrar {
epoll: Arc::clone(&self.epoll),
}
}
#[cfg(test)]
pub(crate) fn wait(
&mut self,
timeout: Option<Duration>,
mut on_event: impl FnMut(u64, Readiness),
) -> io::Result<bool> {
self.wait_at_most(usize::MAX, timeout, &mut on_event)
}
pub(crate) fn wait_at_most(
&mut self,
max: usize,
timeout: Option<Duration>,
mut on_event: impl FnMut(u64, Readiness),
) -> io::Result<bool> {
let ms = match timeout {
None => -1,
Some(t) => {
let ms = t.as_nanos().div_ceil(1_000_000);
ms.min(libc::c_int::MAX as u128) as libc::c_int
}
};
let capacity = self.events.capacity().min(max).max(1) as libc::c_int;
let n = unsafe {
let n = libc::epoll_wait(
self.epoll.as_raw_fd(),
self.events.as_mut_ptr(),
capacity,
ms,
);
if n < 0 {
let err = io::Error::last_os_error();
if err.kind() == io::ErrorKind::Interrupted {
0
} else {
return Err(err);
}
} else {
n as usize
}
};
unsafe { self.events.set_len(n) };
let mut woken = false;
for event in &self.events {
let token = event.u64;
if token == WAKE {
woken = true;
continue;
}
let bits = event.events as libc::c_int;
let hup = bits & (libc::EPOLLHUP | libc::EPOLLERR | libc::EPOLLRDHUP) != 0;
let urgent = bits & libc::EPOLLPRI != 0;
on_event(
token,
Readiness {
readable: bits & libc::EPOLLIN != 0 || hup || urgent,
writable: bits & libc::EPOLLOUT != 0
|| bits & (libc::EPOLLHUP | libc::EPOLLERR) != 0,
urgent,
hangup: hup,
},
);
}
Ok(woken)
}
}
impl Notifier {
#[cfg(feature = "iouring")]
pub(crate) fn of(wake: Arc<OwnedFd>) -> Self {
Self { wake }
}
pub(crate) fn notify(&self) {
let one = 1u64;
unsafe {
libc::write(
self.wake.as_raw_fd(),
(&one as *const u64).cast(),
size_of::<u64>(),
)
};
}
}
impl Registrar {
pub(crate) fn add(&self, fd: RawFd, token: u64, urgent: bool) -> io::Result<()> {
let pri = if urgent { libc::EPOLLPRI } else { 0 };
let mut event = libc::epoll_event {
events: (libc::EPOLLIN | pri | libc::EPOLLOUT | libc::EPOLLRDHUP | libc::EPOLLET)
as u32,
u64: token,
};
check(unsafe {
libc::epoll_ctl(self.epoll.as_raw_fd(), libc::EPOLL_CTL_ADD, fd, &mut event)
})
.map(drop)
}
pub(crate) fn add_exit(&self, pidfd: RawFd, token: u64) -> io::Result<()> {
let mut event = libc::epoll_event {
events: (libc::EPOLLIN | libc::EPOLLONESHOT) as u32,
u64: token,
};
check(unsafe {
libc::epoll_ctl(
self.epoll.as_raw_fd(),
libc::EPOLL_CTL_ADD,
pidfd,
&mut event,
)
})
.map(drop)
}
pub(crate) fn delete(&self, fd: RawFd, _urgent: bool) -> io::Result<()> {
let mut event = libc::epoll_event { events: 0, u64: 0 };
check(unsafe {
libc::epoll_ctl(self.epoll.as_raw_fd(), libc::EPOLL_CTL_DEL, fd, &mut event)
})
.map(drop)
}
}