13da5c369Sopenharmony_ci//! Wait for events to trigger on specific file descriptors
23da5c369Sopenharmony_ciuse std::os::unix::io::{AsRawFd, RawFd};
33da5c369Sopenharmony_ci
43da5c369Sopenharmony_ciuse crate::errno::Errno;
53da5c369Sopenharmony_ciuse crate::Result;
63da5c369Sopenharmony_ci
73da5c369Sopenharmony_ci/// This is a wrapper around `libc::pollfd`.
83da5c369Sopenharmony_ci///
93da5c369Sopenharmony_ci/// It's meant to be used as an argument to the [`poll`](fn.poll.html) and
103da5c369Sopenharmony_ci/// [`ppoll`](fn.ppoll.html) functions to specify the events of interest
113da5c369Sopenharmony_ci/// for a specific file descriptor.
123da5c369Sopenharmony_ci///
133da5c369Sopenharmony_ci/// After a call to `poll` or `ppoll`, the events that occurred can be
143da5c369Sopenharmony_ci/// retrieved by calling [`revents()`](#method.revents) on the `PollFd`.
153da5c369Sopenharmony_ci#[repr(transparent)]
163da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
173da5c369Sopenharmony_cipub struct PollFd {
183da5c369Sopenharmony_ci    pollfd: libc::pollfd,
193da5c369Sopenharmony_ci}
203da5c369Sopenharmony_ci
213da5c369Sopenharmony_ciimpl PollFd {
223da5c369Sopenharmony_ci    /// Creates a new `PollFd` specifying the events of interest
233da5c369Sopenharmony_ci    /// for a given file descriptor.
243da5c369Sopenharmony_ci    pub const fn new(fd: RawFd, events: PollFlags) -> PollFd {
253da5c369Sopenharmony_ci        PollFd {
263da5c369Sopenharmony_ci            pollfd: libc::pollfd {
273da5c369Sopenharmony_ci                fd,
283da5c369Sopenharmony_ci                events: events.bits(),
293da5c369Sopenharmony_ci                revents: PollFlags::empty().bits(),
303da5c369Sopenharmony_ci            },
313da5c369Sopenharmony_ci        }
323da5c369Sopenharmony_ci    }
333da5c369Sopenharmony_ci
343da5c369Sopenharmony_ci    /// Returns the events that occurred in the last call to `poll` or `ppoll`.  Will only return
353da5c369Sopenharmony_ci    /// `None` if the kernel provides status flags that Nix does not know about.
363da5c369Sopenharmony_ci    pub fn revents(self) -> Option<PollFlags> {
373da5c369Sopenharmony_ci        PollFlags::from_bits(self.pollfd.revents)
383da5c369Sopenharmony_ci    }
393da5c369Sopenharmony_ci
403da5c369Sopenharmony_ci    /// Returns if any of the events of interest occured in the last call to `poll` or `ppoll`. Will
413da5c369Sopenharmony_ci    /// only return `None` if the kernel provides status flags that Nix does not know about.
423da5c369Sopenharmony_ci    ///
433da5c369Sopenharmony_ci    /// Equivalent to `x.revents()? != PollFlags::empty()`.
443da5c369Sopenharmony_ci    ///
453da5c369Sopenharmony_ci    /// This is marginally more efficient than [`PollFd::all`].
463da5c369Sopenharmony_ci    pub fn any(self) -> Option<bool> {
473da5c369Sopenharmony_ci        Some(self.revents()? != PollFlags::empty())
483da5c369Sopenharmony_ci    }
493da5c369Sopenharmony_ci
503da5c369Sopenharmony_ci    /// Returns if all the events of interest occured in the last call to `poll` or `ppoll`. Will
513da5c369Sopenharmony_ci    /// only return `None` if the kernel provides status flags that Nix does not know about.
523da5c369Sopenharmony_ci    ///
533da5c369Sopenharmony_ci    /// Equivalent to `x.revents()? & x.events() == x.events()`.
543da5c369Sopenharmony_ci    ///
553da5c369Sopenharmony_ci    /// This is marginally less efficient than [`PollFd::any`].
563da5c369Sopenharmony_ci    pub fn all(self) -> Option<bool> {
573da5c369Sopenharmony_ci        Some(self.revents()? & self.events() == self.events())
583da5c369Sopenharmony_ci    }
593da5c369Sopenharmony_ci
603da5c369Sopenharmony_ci    /// The events of interest for this `PollFd`.
613da5c369Sopenharmony_ci    pub fn events(self) -> PollFlags {
623da5c369Sopenharmony_ci        PollFlags::from_bits(self.pollfd.events).unwrap()
633da5c369Sopenharmony_ci    }
643da5c369Sopenharmony_ci
653da5c369Sopenharmony_ci    /// Modify the events of interest for this `PollFd`.
663da5c369Sopenharmony_ci    pub fn set_events(&mut self, events: PollFlags) {
673da5c369Sopenharmony_ci        self.pollfd.events = events.bits();
683da5c369Sopenharmony_ci    }
693da5c369Sopenharmony_ci}
703da5c369Sopenharmony_ci
713da5c369Sopenharmony_ciimpl AsRawFd for PollFd {
723da5c369Sopenharmony_ci    fn as_raw_fd(&self) -> RawFd {
733da5c369Sopenharmony_ci        self.pollfd.fd
743da5c369Sopenharmony_ci    }
753da5c369Sopenharmony_ci}
763da5c369Sopenharmony_ci
773da5c369Sopenharmony_cilibc_bitflags! {
783da5c369Sopenharmony_ci    /// These flags define the different events that can be monitored by `poll` and `ppoll`
793da5c369Sopenharmony_ci    pub struct PollFlags: libc::c_short {
803da5c369Sopenharmony_ci        /// There is data to read.
813da5c369Sopenharmony_ci        POLLIN;
823da5c369Sopenharmony_ci        /// There is some exceptional condition on the file descriptor.
833da5c369Sopenharmony_ci        ///
843da5c369Sopenharmony_ci        /// Possibilities include:
853da5c369Sopenharmony_ci        ///
863da5c369Sopenharmony_ci        /// *  There is out-of-band data on a TCP socket (see
873da5c369Sopenharmony_ci        ///    [tcp(7)](https://man7.org/linux/man-pages/man7/tcp.7.html)).
883da5c369Sopenharmony_ci        /// *  A pseudoterminal master in packet mode has seen a state
893da5c369Sopenharmony_ci        ///    change on the slave (see
903da5c369Sopenharmony_ci        ///    [ioctl_tty(2)](https://man7.org/linux/man-pages/man2/ioctl_tty.2.html)).
913da5c369Sopenharmony_ci        /// *  A cgroup.events file has been modified (see
923da5c369Sopenharmony_ci        ///    [cgroups(7)](https://man7.org/linux/man-pages/man7/cgroups.7.html)).
933da5c369Sopenharmony_ci        POLLPRI;
943da5c369Sopenharmony_ci        /// Writing is now possible, though a write larger that the
953da5c369Sopenharmony_ci        /// available space in a socket or pipe will still block (unless
963da5c369Sopenharmony_ci        /// `O_NONBLOCK` is set).
973da5c369Sopenharmony_ci        POLLOUT;
983da5c369Sopenharmony_ci        /// Equivalent to [`POLLIN`](constant.POLLIN.html)
993da5c369Sopenharmony_ci        #[cfg(not(target_os = "redox"))]
1003da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
1013da5c369Sopenharmony_ci        POLLRDNORM;
1023da5c369Sopenharmony_ci        #[cfg(not(target_os = "redox"))]
1033da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
1043da5c369Sopenharmony_ci        /// Equivalent to [`POLLOUT`](constant.POLLOUT.html)
1053da5c369Sopenharmony_ci        POLLWRNORM;
1063da5c369Sopenharmony_ci        /// Priority band data can be read (generally unused on Linux).
1073da5c369Sopenharmony_ci        #[cfg(not(target_os = "redox"))]
1083da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
1093da5c369Sopenharmony_ci        POLLRDBAND;
1103da5c369Sopenharmony_ci        /// Priority data may be written.
1113da5c369Sopenharmony_ci        #[cfg(not(target_os = "redox"))]
1123da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
1133da5c369Sopenharmony_ci        POLLWRBAND;
1143da5c369Sopenharmony_ci        /// Error condition (only returned in
1153da5c369Sopenharmony_ci        /// [`PollFd::revents`](struct.PollFd.html#method.revents);
1163da5c369Sopenharmony_ci        /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
1173da5c369Sopenharmony_ci        /// This bit is also set for a file descriptor referring to the
1183da5c369Sopenharmony_ci        /// write end of a pipe when the read end has been closed.
1193da5c369Sopenharmony_ci        POLLERR;
1203da5c369Sopenharmony_ci        /// Hang up (only returned in [`PollFd::revents`](struct.PollFd.html#method.revents);
1213da5c369Sopenharmony_ci        /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
1223da5c369Sopenharmony_ci        /// Note that when reading from a channel such as a pipe or a stream
1233da5c369Sopenharmony_ci        /// socket, this event merely indicates that the peer closed its
1243da5c369Sopenharmony_ci        /// end of the channel.  Subsequent reads from the channel will
1253da5c369Sopenharmony_ci        /// return 0 (end of file) only after all outstanding data in the
1263da5c369Sopenharmony_ci        /// channel has been consumed.
1273da5c369Sopenharmony_ci        POLLHUP;
1283da5c369Sopenharmony_ci        /// Invalid request: `fd` not open (only returned in
1293da5c369Sopenharmony_ci        /// [`PollFd::revents`](struct.PollFd.html#method.revents);
1303da5c369Sopenharmony_ci        /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
1313da5c369Sopenharmony_ci        POLLNVAL;
1323da5c369Sopenharmony_ci    }
1333da5c369Sopenharmony_ci}
1343da5c369Sopenharmony_ci
1353da5c369Sopenharmony_ci/// `poll` waits for one of a set of file descriptors to become ready to perform I/O.
1363da5c369Sopenharmony_ci/// ([`poll(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html))
1373da5c369Sopenharmony_ci///
1383da5c369Sopenharmony_ci/// `fds` contains all [`PollFd`](struct.PollFd.html) to poll.
1393da5c369Sopenharmony_ci/// The function will return as soon as any event occur for any of these `PollFd`s.
1403da5c369Sopenharmony_ci///
1413da5c369Sopenharmony_ci/// The `timeout` argument specifies the number of milliseconds that `poll()`
1423da5c369Sopenharmony_ci/// should block waiting for a file descriptor to become ready.  The call
1433da5c369Sopenharmony_ci/// will block until either:
1443da5c369Sopenharmony_ci///
1453da5c369Sopenharmony_ci/// *  a file descriptor becomes ready;
1463da5c369Sopenharmony_ci/// *  the call is interrupted by a signal handler; or
1473da5c369Sopenharmony_ci/// *  the timeout expires.
1483da5c369Sopenharmony_ci///
1493da5c369Sopenharmony_ci/// Note that the timeout interval will be rounded up to the system clock
1503da5c369Sopenharmony_ci/// granularity, and kernel scheduling delays mean that the blocking
1513da5c369Sopenharmony_ci/// interval may overrun by a small amount.  Specifying a negative value
1523da5c369Sopenharmony_ci/// in timeout means an infinite timeout.  Specifying a timeout of zero
1533da5c369Sopenharmony_ci/// causes `poll()` to return immediately, even if no file descriptors are
1543da5c369Sopenharmony_ci/// ready.
1553da5c369Sopenharmony_cipub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int> {
1563da5c369Sopenharmony_ci    let res = unsafe {
1573da5c369Sopenharmony_ci        libc::poll(
1583da5c369Sopenharmony_ci            fds.as_mut_ptr() as *mut libc::pollfd,
1593da5c369Sopenharmony_ci            fds.len() as libc::nfds_t,
1603da5c369Sopenharmony_ci            timeout,
1613da5c369Sopenharmony_ci        )
1623da5c369Sopenharmony_ci    };
1633da5c369Sopenharmony_ci
1643da5c369Sopenharmony_ci    Errno::result(res)
1653da5c369Sopenharmony_ci}
1663da5c369Sopenharmony_ci
1673da5c369Sopenharmony_cifeature! {
1683da5c369Sopenharmony_ci#![feature = "signal"]
1693da5c369Sopenharmony_ci/// `ppoll()` allows an application to safely wait until either a file
1703da5c369Sopenharmony_ci/// descriptor becomes ready or until a signal is caught.
1713da5c369Sopenharmony_ci/// ([`poll(2)`](https://man7.org/linux/man-pages/man2/poll.2.html))
1723da5c369Sopenharmony_ci///
1733da5c369Sopenharmony_ci/// `ppoll` behaves like `poll`, but let you specify what signals may interrupt it
1743da5c369Sopenharmony_ci/// with the `sigmask` argument. If you want `ppoll` to block indefinitely,
1753da5c369Sopenharmony_ci/// specify `None` as `timeout` (it is like `timeout = -1` for `poll`).
1763da5c369Sopenharmony_ci/// If `sigmask` is `None`, then no signal mask manipulation is performed,
1773da5c369Sopenharmony_ci/// so in that case `ppoll` differs from `poll` only in the precision of the
1783da5c369Sopenharmony_ci/// timeout argument.
1793da5c369Sopenharmony_ci///
1803da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
1813da5c369Sopenharmony_cipub fn ppoll(
1823da5c369Sopenharmony_ci    fds: &mut [PollFd],
1833da5c369Sopenharmony_ci    timeout: Option<crate::sys::time::TimeSpec>,
1843da5c369Sopenharmony_ci    sigmask: Option<crate::sys::signal::SigSet>
1853da5c369Sopenharmony_ci    ) -> Result<libc::c_int>
1863da5c369Sopenharmony_ci{
1873da5c369Sopenharmony_ci    let timeout = timeout.as_ref().map_or(core::ptr::null(), |r| r.as_ref());
1883da5c369Sopenharmony_ci    let sigmask = sigmask.as_ref().map_or(core::ptr::null(), |r| r.as_ref());
1893da5c369Sopenharmony_ci    let res = unsafe {
1903da5c369Sopenharmony_ci        libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd,
1913da5c369Sopenharmony_ci                    fds.len() as libc::nfds_t,
1923da5c369Sopenharmony_ci                    timeout,
1933da5c369Sopenharmony_ci                    sigmask)
1943da5c369Sopenharmony_ci    };
1953da5c369Sopenharmony_ci    Errno::result(res)
1963da5c369Sopenharmony_ci}
1973da5c369Sopenharmony_ci}
198