1//! Wait for events to trigger on specific file descriptors 2use std::os::unix::io::{AsRawFd, RawFd}; 3 4use crate::errno::Errno; 5use crate::Result; 6 7/// This is a wrapper around `libc::pollfd`. 8/// 9/// It's meant to be used as an argument to the [`poll`](fn.poll.html) and 10/// [`ppoll`](fn.ppoll.html) functions to specify the events of interest 11/// for a specific file descriptor. 12/// 13/// After a call to `poll` or `ppoll`, the events that occurred can be 14/// retrieved by calling [`revents()`](#method.revents) on the `PollFd`. 15#[repr(transparent)] 16#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 17pub struct PollFd { 18 pollfd: libc::pollfd, 19} 20 21impl PollFd { 22 /// Creates a new `PollFd` specifying the events of interest 23 /// for a given file descriptor. 24 pub const fn new(fd: RawFd, events: PollFlags) -> PollFd { 25 PollFd { 26 pollfd: libc::pollfd { 27 fd, 28 events: events.bits(), 29 revents: PollFlags::empty().bits(), 30 }, 31 } 32 } 33 34 /// Returns the events that occurred in the last call to `poll` or `ppoll`. Will only return 35 /// `None` if the kernel provides status flags that Nix does not know about. 36 pub fn revents(self) -> Option<PollFlags> { 37 PollFlags::from_bits(self.pollfd.revents) 38 } 39 40 /// Returns if any of the events of interest occured in the last call to `poll` or `ppoll`. Will 41 /// only return `None` if the kernel provides status flags that Nix does not know about. 42 /// 43 /// Equivalent to `x.revents()? != PollFlags::empty()`. 44 /// 45 /// This is marginally more efficient than [`PollFd::all`]. 46 pub fn any(self) -> Option<bool> { 47 Some(self.revents()? != PollFlags::empty()) 48 } 49 50 /// Returns if all the events of interest occured in the last call to `poll` or `ppoll`. Will 51 /// only return `None` if the kernel provides status flags that Nix does not know about. 52 /// 53 /// Equivalent to `x.revents()? & x.events() == x.events()`. 54 /// 55 /// This is marginally less efficient than [`PollFd::any`]. 56 pub fn all(self) -> Option<bool> { 57 Some(self.revents()? & self.events() == self.events()) 58 } 59 60 /// The events of interest for this `PollFd`. 61 pub fn events(self) -> PollFlags { 62 PollFlags::from_bits(self.pollfd.events).unwrap() 63 } 64 65 /// Modify the events of interest for this `PollFd`. 66 pub fn set_events(&mut self, events: PollFlags) { 67 self.pollfd.events = events.bits(); 68 } 69} 70 71impl AsRawFd for PollFd { 72 fn as_raw_fd(&self) -> RawFd { 73 self.pollfd.fd 74 } 75} 76 77libc_bitflags! { 78 /// These flags define the different events that can be monitored by `poll` and `ppoll` 79 pub struct PollFlags: libc::c_short { 80 /// There is data to read. 81 POLLIN; 82 /// There is some exceptional condition on the file descriptor. 83 /// 84 /// Possibilities include: 85 /// 86 /// * There is out-of-band data on a TCP socket (see 87 /// [tcp(7)](https://man7.org/linux/man-pages/man7/tcp.7.html)). 88 /// * A pseudoterminal master in packet mode has seen a state 89 /// change on the slave (see 90 /// [ioctl_tty(2)](https://man7.org/linux/man-pages/man2/ioctl_tty.2.html)). 91 /// * A cgroup.events file has been modified (see 92 /// [cgroups(7)](https://man7.org/linux/man-pages/man7/cgroups.7.html)). 93 POLLPRI; 94 /// Writing is now possible, though a write larger that the 95 /// available space in a socket or pipe will still block (unless 96 /// `O_NONBLOCK` is set). 97 POLLOUT; 98 /// Equivalent to [`POLLIN`](constant.POLLIN.html) 99 #[cfg(not(target_os = "redox"))] 100 #[cfg_attr(docsrs, doc(cfg(all())))] 101 POLLRDNORM; 102 #[cfg(not(target_os = "redox"))] 103 #[cfg_attr(docsrs, doc(cfg(all())))] 104 /// Equivalent to [`POLLOUT`](constant.POLLOUT.html) 105 POLLWRNORM; 106 /// Priority band data can be read (generally unused on Linux). 107 #[cfg(not(target_os = "redox"))] 108 #[cfg_attr(docsrs, doc(cfg(all())))] 109 POLLRDBAND; 110 /// Priority data may be written. 111 #[cfg(not(target_os = "redox"))] 112 #[cfg_attr(docsrs, doc(cfg(all())))] 113 POLLWRBAND; 114 /// Error condition (only returned in 115 /// [`PollFd::revents`](struct.PollFd.html#method.revents); 116 /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)). 117 /// This bit is also set for a file descriptor referring to the 118 /// write end of a pipe when the read end has been closed. 119 POLLERR; 120 /// Hang up (only returned in [`PollFd::revents`](struct.PollFd.html#method.revents); 121 /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)). 122 /// Note that when reading from a channel such as a pipe or a stream 123 /// socket, this event merely indicates that the peer closed its 124 /// end of the channel. Subsequent reads from the channel will 125 /// return 0 (end of file) only after all outstanding data in the 126 /// channel has been consumed. 127 POLLHUP; 128 /// Invalid request: `fd` not open (only returned in 129 /// [`PollFd::revents`](struct.PollFd.html#method.revents); 130 /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)). 131 POLLNVAL; 132 } 133} 134 135/// `poll` waits for one of a set of file descriptors to become ready to perform I/O. 136/// ([`poll(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html)) 137/// 138/// `fds` contains all [`PollFd`](struct.PollFd.html) to poll. 139/// The function will return as soon as any event occur for any of these `PollFd`s. 140/// 141/// The `timeout` argument specifies the number of milliseconds that `poll()` 142/// should block waiting for a file descriptor to become ready. The call 143/// will block until either: 144/// 145/// * a file descriptor becomes ready; 146/// * the call is interrupted by a signal handler; or 147/// * the timeout expires. 148/// 149/// Note that the timeout interval will be rounded up to the system clock 150/// granularity, and kernel scheduling delays mean that the blocking 151/// interval may overrun by a small amount. Specifying a negative value 152/// in timeout means an infinite timeout. Specifying a timeout of zero 153/// causes `poll()` to return immediately, even if no file descriptors are 154/// ready. 155pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int> { 156 let res = unsafe { 157 libc::poll( 158 fds.as_mut_ptr() as *mut libc::pollfd, 159 fds.len() as libc::nfds_t, 160 timeout, 161 ) 162 }; 163 164 Errno::result(res) 165} 166 167feature! { 168#![feature = "signal"] 169/// `ppoll()` allows an application to safely wait until either a file 170/// descriptor becomes ready or until a signal is caught. 171/// ([`poll(2)`](https://man7.org/linux/man-pages/man2/poll.2.html)) 172/// 173/// `ppoll` behaves like `poll`, but let you specify what signals may interrupt it 174/// with the `sigmask` argument. If you want `ppoll` to block indefinitely, 175/// specify `None` as `timeout` (it is like `timeout = -1` for `poll`). 176/// If `sigmask` is `None`, then no signal mask manipulation is performed, 177/// so in that case `ppoll` differs from `poll` only in the precision of the 178/// timeout argument. 179/// 180#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] 181pub fn ppoll( 182 fds: &mut [PollFd], 183 timeout: Option<crate::sys::time::TimeSpec>, 184 sigmask: Option<crate::sys::signal::SigSet> 185 ) -> Result<libc::c_int> 186{ 187 let timeout = timeout.as_ref().map_or(core::ptr::null(), |r| r.as_ref()); 188 let sigmask = sigmask.as_ref().map_or(core::ptr::null(), |r| r.as_ref()); 189 let res = unsafe { 190 libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd, 191 fds.len() as libc::nfds_t, 192 timeout, 193 sigmask) 194 }; 195 Errno::result(res) 196} 197} 198