use std::{
marker,
os::fd::{AsRawFd as _, BorrowedFd},
slice,
};
pub use libc::nfds_t;
use o3::base::marker::ThreadBound;
use crate::{
Errno,
io::poll,
kernel::{self, errno},
};
pub mod raw;
pub const MAX_ENTRIES: usize = nfds_t::MAX as usize;
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
pub struct Entry<'fd>(
libc::pollfd,
marker::PhantomData<(BorrowedFd<'fd>, ThreadBound)>,
);
impl<'fd> Entry<'fd> {
pub fn readable(fd: BorrowedFd<'fd>) -> Self {
Self::new(fd, libc::POLLIN)
}
pub fn writable(fd: BorrowedFd<'fd>) -> Self {
Self::new(fd, libc::POLLOUT)
}
fn new(fd: BorrowedFd<'fd>, events: libc::c_short) -> Self {
Self(
libc::pollfd {
fd: fd.as_raw_fd(),
events,
revents: 0,
},
marker::PhantomData,
)
}
pub const fn is_ready(self) -> bool {
self.0.revents != 0
}
pub const fn is_readable(self) -> bool {
self.0.revents & libc::POLLIN != 0
}
pub const fn revents(self) -> i16 {
self.0.revents
}
pub fn retire(&mut self) {
self.0.fd = -1;
self.0.revents = 0;
}
}
fn raw<'a>(entries: &'a mut [Entry<'_>]) -> &'a mut [libc::pollfd] {
unsafe { slice::from_raw_parts_mut(entries.as_mut_ptr().cast(), entries.len()) }
}
pub struct Events<'a, 'fd> {
entries: &'a [Entry<'fd>],
count: usize,
}
impl<'a, 'fd> Events<'a, 'fd> {
pub const fn count(&self) -> usize {
self.count
}
pub const fn entries(&self) -> &'a [Entry<'fd>] {
self.entries
}
}
pub trait Poll: errno::Source {
fn wait<'a, 'fd: 'a, T: poll::raw::Entries<'fd>, E: From<Errno>>(
owner: &'a mut T,
timeout: i32,
) -> Result<poll::Events<'a, 'fd>, E> {
const {
assert!(T::MAX as nfds_t as usize == T::MAX);
}
let entries = owner.entries();
let raw = raw(entries);
let raw = unsafe { libc::poll(raw.as_mut_ptr(), raw.len() as nfds_t, timeout) };
let count = unsafe { kernel::raw::Status::new(raw).try_count::<Self, E>() }?.get();
Ok(poll::Events { entries, count })
}
}
impl<T: errno::Source> Poll for T {}