use std::{io, os::fd::BorrowedFd, time::Duration};
use rustix::{
event::{PollFd, PollFlags, Timespec, poll},
io::Errno,
};
use super::{Directions, RawSource, Ready, list::List, pipe::Pipe};
pub(crate) struct Poller {
wake: Pipe,
list: List,
}
impl Poller {
pub(crate) const LIVE: bool = false;
pub(crate) fn new() -> io::Result<Self> {
Ok(Self {
wake: Pipe::new()?,
list: List::new(),
})
}
pub(crate) fn notify(&self) -> io::Result<()> {
self.wake.notify()
}
pub(crate) fn add(&self, _key: usize, _descriptor: RawSource) -> io::Result<()> {
self.list.add();
Ok(())
}
pub(crate) fn modify(
&self,
key: usize,
descriptor: RawSource,
_from: Directions,
to: Directions,
) -> io::Result<()> {
self.list.modify(key, descriptor, to);
Ok(())
}
pub(crate) fn delete(
&self,
key: usize,
_descriptor: RawSource,
_from: Directions,
) -> io::Result<()> {
self.list.delete(key);
Ok(())
}
pub(crate) fn wait(&self, timeout: Option<Duration>) -> io::Result<Vec<Ready>> {
let watched = self.list.snapshot();
let mut fds = Vec::with_capacity(watched.len() + 1);
fds.push(PollFd::from_borrowed_fd(
self.wake.read_end(),
PollFlags::IN,
));
for &(_key, descriptor, directions) in &watched {
let mut flags = PollFlags::empty();
if directions.readable {
flags |= PollFlags::IN;
}
if directions.writable {
flags |= PollFlags::OUT;
}
let fd = unsafe { BorrowedFd::borrow_raw(descriptor) };
fds.push(PollFd::from_borrowed_fd(fd, flags));
}
let timeout = timeout.and_then(|t| Timespec::try_from(t).ok());
match poll(&mut fds, timeout.as_ref()) {
Ok(_) => {}
Err(Errno::INTR) => return Ok(Vec::new()),
Err(e) => return Err(e.into()),
}
if fds[0].revents().contains(PollFlags::IN) {
self.wake.drain();
}
Ok(watched
.iter()
.zip(&fds[1..])
.filter_map(|(&(key, _, _), fd)| {
let revents = fd.revents();
let hung_up = revents.intersects(PollFlags::ERR | PollFlags::HUP | PollFlags::NVAL);
let directions = Directions {
readable: revents.contains(PollFlags::IN) || hung_up,
writable: revents.contains(PollFlags::OUT) || hung_up,
};
(!directions.is_empty()).then_some(Ready {
key,
directions,
dropped: Directions::NONE,
})
})
.collect())
}
}