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