/rust/registry/src/index.crates.io-6f17d22bba15001f/nix-0.26.2/src/poll.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! Wait for events to trigger on specific file descriptors |
2 | | use std::os::unix::io::{AsRawFd, RawFd}; |
3 | | |
4 | | use crate::errno::Errno; |
5 | | use 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 | 0 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] |
17 | | pub struct PollFd { |
18 | | pollfd: libc::pollfd, |
19 | | } |
20 | | |
21 | | impl PollFd { |
22 | | /// Creates a new `PollFd` specifying the events of interest |
23 | | /// for a given file descriptor. |
24 | 0 | pub const fn new(fd: RawFd, events: PollFlags) -> PollFd { |
25 | 0 | PollFd { |
26 | 0 | pollfd: libc::pollfd { |
27 | 0 | fd, |
28 | 0 | events: events.bits(), |
29 | 0 | revents: PollFlags::empty().bits(), |
30 | 0 | }, |
31 | 0 | } |
32 | 0 | } |
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 | 0 | pub fn revents(self) -> Option<PollFlags> { |
37 | 0 | PollFlags::from_bits(self.pollfd.revents) |
38 | 0 | } |
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 | 0 | pub fn any(self) -> Option<bool> { |
47 | 0 | Some(self.revents()? != PollFlags::empty()) |
48 | 0 | } |
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 | 0 | pub fn all(self) -> Option<bool> { |
57 | 0 | Some(self.revents()? & self.events() == self.events()) |
58 | 0 | } |
59 | | |
60 | | /// The events of interest for this `PollFd`. |
61 | 0 | pub fn events(self) -> PollFlags { |
62 | 0 | PollFlags::from_bits(self.pollfd.events).unwrap() |
63 | 0 | } |
64 | | |
65 | | /// Modify the events of interest for this `PollFd`. |
66 | 0 | pub fn set_events(&mut self, events: PollFlags) { |
67 | 0 | self.pollfd.events = events.bits(); |
68 | 0 | } |
69 | | } |
70 | | |
71 | | impl AsRawFd for PollFd { |
72 | 0 | fn as_raw_fd(&self) -> RawFd { |
73 | 0 | self.pollfd.fd |
74 | 0 | } |
75 | | } |
76 | | |
77 | | libc_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. |
155 | 0 | pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int> { |
156 | 0 | let res = unsafe { |
157 | 0 | libc::poll( |
158 | 0 | fds.as_mut_ptr() as *mut libc::pollfd, |
159 | 0 | fds.len() as libc::nfds_t, |
160 | 0 | timeout, |
161 | 0 | ) |
162 | 0 | }; |
163 | 0 |
|
164 | 0 | Errno::result(res) |
165 | 0 | } |
166 | | |
167 | | feature! { |
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"))] |
181 | 0 | pub fn ppoll( |
182 | 0 | fds: &mut [PollFd], |
183 | 0 | timeout: Option<crate::sys::time::TimeSpec>, |
184 | 0 | sigmask: Option<crate::sys::signal::SigSet> |
185 | 0 | ) -> Result<libc::c_int> |
186 | 0 | { |
187 | 0 | let timeout = timeout.as_ref().map_or(core::ptr::null(), |r| r.as_ref()); |
188 | 0 | let sigmask = sigmask.as_ref().map_or(core::ptr::null(), |r| r.as_ref()); |
189 | 0 | let res = unsafe { |
190 | 0 | libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd, |
191 | 0 | fds.len() as libc::nfds_t, |
192 | 0 | timeout, |
193 | 0 | sigmask) |
194 | 0 | }; |
195 | 0 | Errno::result(res) |
196 | 0 | } |
197 | | } |