Skip to main content

dope_sys/io/poll/
mod.rs

1use std::{
2    marker,
3    os::fd::{AsRawFd as _, BorrowedFd},
4    slice,
5};
6
7pub use libc::nfds_t;
8
9use o3::base::marker::ThreadBound;
10
11use crate::{
12    Errno,
13    io::poll,
14    kernel::{self, errno},
15};
16
17pub mod raw;
18
19/// Largest registration count the native poll call accepts.
20pub const MAX_ENTRIES: usize = nfds_t::MAX as usize;
21
22/// One native poll registration and the events the kernel reported for it.
23#[derive(Clone, Copy, Debug)]
24#[repr(transparent)]
25pub struct Entry<'fd>(
26    libc::pollfd,
27    marker::PhantomData<(BorrowedFd<'fd>, ThreadBound)>,
28);
29
30impl<'fd> Entry<'fd> {
31    /// Registers one descriptor for readability.
32    pub fn readable(fd: BorrowedFd<'fd>) -> Self {
33        Self::new(fd, libc::POLLIN)
34    }
35
36    /// Registers one descriptor for writability.
37    pub fn writable(fd: BorrowedFd<'fd>) -> Self {
38        Self::new(fd, libc::POLLOUT)
39    }
40
41    fn new(fd: BorrowedFd<'fd>, events: libc::c_short) -> Self {
42        Self(
43            libc::pollfd {
44                fd: fd.as_raw_fd(),
45                events,
46                revents: 0,
47            },
48            marker::PhantomData,
49        )
50    }
51
52    /// Whether the kernel reported any event for this registration.
53    pub const fn is_ready(self) -> bool {
54        self.0.revents != 0
55    }
56
57    /// Whether the kernel reported readability.
58    pub const fn is_readable(self) -> bool {
59        self.0.revents & libc::POLLIN != 0
60    }
61
62    /// Raw event bits reported for this registration.
63    pub const fn revents(self) -> i16 {
64        self.0.revents
65    }
66
67    /// Stops polling this registration after its owner handles the terminal event.
68    pub fn retire(&mut self) {
69        self.0.fd = -1;
70        self.0.revents = 0;
71    }
72}
73
74/// Projects the raw registrations for the native wait call.
75fn raw<'a>(entries: &'a mut [Entry<'_>]) -> &'a mut [libc::pollfd] {
76    // SAFETY: Entry is repr(transparent) over pollfd, so this slice has the exact
77    // layout and length of the entries it borrows.
78    unsafe { slice::from_raw_parts_mut(entries.as_mut_ptr().cast(), entries.len()) }
79}
80
81pub struct Events<'a, 'fd> {
82    entries: &'a [Entry<'fd>],
83    count: usize,
84}
85
86impl<'a, 'fd> Events<'a, 'fd> {
87    pub const fn count(&self) -> usize {
88        self.count
89    }
90    pub const fn entries(&self) -> &'a [Entry<'fd>] {
91        self.entries
92    }
93}
94
95/// Native polling against a caller-owned, bounded descriptor collection.
96pub trait Poll: errno::Source {
97    fn wait<'a, 'fd: 'a, T: poll::raw::Entries<'fd>, E: From<Errno>>(
98        owner: &'a mut T,
99        timeout: i32,
100    ) -> Result<poll::Events<'a, 'fd>, E> {
101        const {
102            assert!(T::MAX as nfds_t as usize == T::MAX);
103        }
104        let entries = owner.entries();
105        let raw = raw(entries);
106        // SAFETY: the entries stay live and uniquely borrowed for the call.
107        let raw = unsafe { libc::poll(raw.as_mut_ptr(), raw.len() as nfds_t, timeout) };
108        // SAFETY: poll returns -1 or the number of ready registrations it was given.
109        let count = unsafe {
110            kernel::raw::Status::new(raw)
111                .try_count::<E>(|| kernel::raw::Code::last::<Self>().into())
112        }?
113        .get();
114        Ok(poll::Events { entries, count })
115    }
116}
117
118impl<T: errno::Source> Poll for T {}