use super::{Poll, POLLIN, POLLOUT};
use crate::{Error, Result};
use core::mem::MaybeUninit;
use core::ptr;
use hipool::{Allocator, Boxed, Pool, PoolAlloc};
pub(crate) type BoxedPollImpl<'a, A> = Boxed<'a, PollImpl<'a, A>, A>;
#[repr(C)]
pub(crate) struct PollImpl<'a, A: Allocator = PoolAlloc> {
fd: i32,
events: Boxed<'a, [MaybeUninit<libc::epoll_event>], A>,
}
unsafe impl<A: Allocator + Pool> Send for PollImpl<'static, A> {}
impl<'a, A: Allocator + 'a> Drop for PollImpl<'a, A> {
fn drop(&mut self) {
unsafe { libc::close(self.fd) };
}
}
impl<'a, A: Allocator + 'a> PollImpl<'a, A> {
pub fn new_in(pool: &'a A) -> Result<BoxedPollImpl<'a, A>> {
let events = Boxed::uninit_slice_in::<libc::epoll_event>(pool, EPOLL_EVENT_MAX)?;
let uninit = Boxed::uninit_in::<Self>(pool)?;
let fd = unsafe { libc::epoll_create1(libc::EPOLL_CLOEXEC) };
if fd >= 0 {
let poll = uninit.write(Self { fd, events });
Ok(poll)
} else {
Err(Error::last())
}
}
}
impl<'a, A: Allocator + 'a> Poll for PollImpl<'a, A> {
fn add_event(&self, fd: i32, events: u32, e: u64) -> Result<()> {
let mut event = libc::epoll_event { events, u64: e };
let ret =
unsafe { libc::epoll_ctl(self.fd, libc::EPOLL_CTL_ADD, fd, ptr::addr_of_mut!(event)) };
if ret == 0 {
Ok(())
} else {
Err(Error::last())
}
}
fn mod_event(&self, fd: i32, events: u32, e: u64) -> Result<()> {
let mut event = libc::epoll_event { events, u64: e };
let ret =
unsafe { libc::epoll_ctl(self.fd, libc::EPOLL_CTL_MOD, fd, ptr::addr_of_mut!(event)) };
if ret == 0 {
Ok(())
} else {
Err(Error::last())
}
}
fn del_event(&self, fd: i32, e: u64) -> Result<()> {
let mut event = libc::epoll_event { events: 0, u64: e };
let ret =
unsafe { libc::epoll_ctl(self.fd, libc::EPOLL_CTL_DEL, fd, ptr::addr_of_mut!(event)) };
if ret == 0 {
Ok(())
} else {
Err(Error::last())
}
}
fn wait<F>(&mut self, timeout: i32, mut f: F) -> Result<u32>
where
F: FnMut(u32, u64),
{
let events = self.events.as_ptr().cast::<libc::epoll_event>();
let cnt = unsafe { libc::epoll_wait(self.fd, events, self.events.len() as i32, timeout) };
if cnt >= 0 {
for event in &mut self.events[0..cnt as usize] {
let event = unsafe { event.assume_init_ref() };
let mut events = event.events & (POLLIN | POLLOUT);
if events == 0 {
events = POLLIN | POLLOUT;
}
f(events, event.u64);
}
Ok(cnt as u32)
} else {
Err(Error::last())
}
}
}
const EPOLL_EVENT_MAX: usize = 512;