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