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