• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Wait for events to trigger on specific file descriptors
2 use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd};
3 
4 use crate::errno::Errno;
5 pub use crate::poll_timeout::PollTimeout;
6 use crate::Result;
7 
8 /// This is a wrapper around `libc::pollfd`.
9 ///
10 /// It's meant to be used as an argument to the [`poll`](fn.poll.html) and
11 /// [`ppoll`](fn.ppoll.html) functions to specify the events of interest
12 /// for a specific file descriptor.
13 ///
14 /// After a call to `poll` or `ppoll`, the events that occurred can be
15 /// retrieved by calling [`revents()`](#method.revents) on the `PollFd`.
16 #[repr(transparent)]
17 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
18 pub struct PollFd<'fd> {
19     pollfd: libc::pollfd,
20     _fd: std::marker::PhantomData<BorrowedFd<'fd>>,
21 }
22 
23 impl<'fd> PollFd<'fd> {
24     /// Creates a new `PollFd` specifying the events of interest
25     /// for a given file descriptor.
26     ///
27     /// # Examples
28     /// ```no_run
29     /// # use std::os::unix::io::{AsFd, AsRawFd, FromRawFd};
30     /// # use nix::{
31     /// #     poll::{PollTimeout, PollFd, PollFlags, poll},
32     /// #     unistd::{pipe, read}
33     /// # };
34     /// let (r, w) = pipe().unwrap();
35     /// let pfd = PollFd::new(r.as_fd(), PollFlags::POLLIN);
36     /// let mut fds = [pfd];
37     /// poll(&mut fds, PollTimeout::NONE).unwrap();
38     /// let mut buf = [0u8; 80];
39     /// read(r.as_raw_fd(), &mut buf[..]);
40     /// ```
41     // Unlike I/O functions, constructors like this must take `BorrowedFd`
42     // instead of AsFd or &AsFd.  Otherwise, an `OwnedFd` argument would be
43     // dropped at the end of the method, leaving the structure referencing a
44     // closed file descriptor.  For example:
45     //
46     // ```rust
47     // let (r, _) = pipe().unwrap();
48     // let pollfd = PollFd::new(r, flag);  // Drops the OwnedFd
49     // // Do something with `pollfd`, which uses the CLOSED fd.
50     // ```
new(fd: BorrowedFd<'fd>, events: PollFlags) -> PollFd<'fd>51     pub fn new(fd: BorrowedFd<'fd>, events: PollFlags) -> PollFd<'fd> {
52         PollFd {
53             pollfd: libc::pollfd {
54                 fd: fd.as_raw_fd(),
55                 events: events.bits(),
56                 revents: PollFlags::empty().bits(),
57             },
58             _fd: std::marker::PhantomData,
59         }
60     }
61 
62     /// Returns the events that occurred in the last call to `poll` or `ppoll`.  Will only return
63     /// `None` if the kernel provides status flags that Nix does not know about.
revents(self) -> Option<PollFlags>64     pub fn revents(self) -> Option<PollFlags> {
65         PollFlags::from_bits(self.pollfd.revents)
66     }
67 
68     /// Returns if any of the events of interest occured in the last call to `poll` or `ppoll`. Will
69     /// only return `None` if the kernel provides status flags that Nix does not know about.
70     ///
71     /// Equivalent to `x.revents()? != PollFlags::empty()`.
72     ///
73     /// This is marginally more efficient than [`PollFd::all`].
any(self) -> Option<bool>74     pub fn any(self) -> Option<bool> {
75         Some(self.revents()? != PollFlags::empty())
76     }
77 
78     /// Returns if all the events of interest occured in the last call to `poll` or `ppoll`. Will
79     /// only return `None` if the kernel provides status flags that Nix does not know about.
80     ///
81     /// Equivalent to `x.revents()? & x.events() == x.events()`.
82     ///
83     /// This is marginally less efficient than [`PollFd::any`].
all(self) -> Option<bool>84     pub fn all(self) -> Option<bool> {
85         Some(self.revents()? & self.events() == self.events())
86     }
87 
88     /// The events of interest for this `PollFd`.
events(self) -> PollFlags89     pub fn events(self) -> PollFlags {
90         PollFlags::from_bits(self.pollfd.events).unwrap()
91     }
92 
93     /// Modify the events of interest for this `PollFd`.
set_events(&mut self, events: PollFlags)94     pub fn set_events(&mut self, events: PollFlags) {
95         self.pollfd.events = events.bits();
96     }
97 }
98 
99 impl<'fd> AsFd for PollFd<'fd> {
as_fd(&self) -> BorrowedFd<'_>100     fn as_fd(&self) -> BorrowedFd<'_> {
101         // Safety:
102         //
103         // BorrowedFd::borrow_raw(RawFd) requires that the raw fd being passed
104         // must remain open for the duration of the returned BorrowedFd, this is
105         // guaranteed as the returned BorrowedFd has the lifetime parameter same
106         // as `self`:
107         // "fn as_fd<'self>(&'self self) -> BorrowedFd<'self>"
108         // which means that `self` (PollFd) is guaranteed to outlive the returned
109         // BorrowedFd. (Lifetime: PollFd > BorrowedFd)
110         //
111         // And the lifetime parameter of PollFd::new(fd, ...) ensures that `fd`
112         // (an owned file descriptor) must outlive the returned PollFd:
113         // "pub fn new<Fd: AsFd>(fd: &'fd Fd, events: PollFlags) -> PollFd<'fd>"
114         // (Lifetime: Owned fd > PollFd)
115         //
116         // With two above relationships, we can conclude that the `Owned file
117         // descriptor` will outlive the returned BorrowedFd,
118         // (Lifetime: Owned fd > BorrowedFd)
119         // i.e., the raw fd being passed will remain valid for the lifetime of
120         // the returned BorrowedFd.
121         unsafe { BorrowedFd::borrow_raw(self.pollfd.fd) }
122     }
123 }
124 
125 libc_bitflags! {
126     /// These flags define the different events that can be monitored by `poll` and `ppoll`
127     pub struct PollFlags: libc::c_short {
128         /// There is data to read.
129         POLLIN;
130         /// There is some exceptional condition on the file descriptor.
131         ///
132         /// Possibilities include:
133         ///
134         /// *  There is out-of-band data on a TCP socket (see
135         ///    [tcp(7)](https://man7.org/linux/man-pages/man7/tcp.7.html)).
136         /// *  A pseudoterminal master in packet mode has seen a state
137         ///    change on the slave (see
138         ///    [ioctl_tty(2)](https://man7.org/linux/man-pages/man2/ioctl_tty.2.html)).
139         /// *  A cgroup.events file has been modified (see
140         ///    [cgroups(7)](https://man7.org/linux/man-pages/man7/cgroups.7.html)).
141         POLLPRI;
142         /// Writing is now possible, though a write larger that the
143         /// available space in a socket or pipe will still block (unless
144         /// `O_NONBLOCK` is set).
145         POLLOUT;
146         /// Equivalent to [`POLLIN`](constant.POLLIN.html)
147         #[cfg(not(target_os = "redox"))]
148         POLLRDNORM;
149         #[cfg(not(target_os = "redox"))]
150         /// Equivalent to [`POLLOUT`](constant.POLLOUT.html)
151         POLLWRNORM;
152         /// Priority band data can be read (generally unused on Linux).
153         #[cfg(not(target_os = "redox"))]
154         POLLRDBAND;
155         /// Priority data may be written.
156         #[cfg(not(target_os = "redox"))]
157         POLLWRBAND;
158         /// Error condition (only returned in
159         /// [`PollFd::revents`](struct.PollFd.html#method.revents);
160         /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
161         /// This bit is also set for a file descriptor referring to the
162         /// write end of a pipe when the read end has been closed.
163         POLLERR;
164         /// Hang up (only returned in [`PollFd::revents`](struct.PollFd.html#method.revents);
165         /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
166         /// Note that when reading from a channel such as a pipe or a stream
167         /// socket, this event merely indicates that the peer closed its
168         /// end of the channel.  Subsequent reads from the channel will
169         /// return 0 (end of file) only after all outstanding data in the
170         /// channel has been consumed.
171         POLLHUP;
172         /// Invalid request: `fd` not open (only returned in
173         /// [`PollFd::revents`](struct.PollFd.html#method.revents);
174         /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
175         POLLNVAL;
176     }
177 }
178 
179 /// `poll` waits for one of a set of file descriptors to become ready to perform I/O.
180 /// ([`poll(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html))
181 ///
182 /// `fds` contains all [`PollFd`](struct.PollFd.html) to poll.
183 /// The function will return as soon as any event occur for any of these `PollFd`s.
184 ///
185 /// The `timeout` argument specifies the number of milliseconds that `poll()`
186 /// should block waiting for a file descriptor to become ready.  The call
187 /// will block until either:
188 ///
189 /// *  a file descriptor becomes ready;
190 /// *  the call is interrupted by a signal handler; or
191 /// *  the timeout expires.
192 ///
193 /// Note that the timeout interval will be rounded up to the system clock
194 /// granularity, and kernel scheduling delays mean that the blocking
195 /// interval may overrun by a small amount.  Specifying a [`PollTimeout::NONE`]
196 /// in timeout means an infinite timeout.  Specifying a timeout of
197 /// [`PollTimeout::ZERO`] causes `poll()` to return immediately, even if no file
198 /// descriptors are ready.
poll<T: Into<PollTimeout>>( fds: &mut [PollFd], timeout: T, ) -> Result<libc::c_int>199 pub fn poll<T: Into<PollTimeout>>(
200     fds: &mut [PollFd],
201     timeout: T,
202 ) -> Result<libc::c_int> {
203     let res = unsafe {
204         libc::poll(
205             fds.as_mut_ptr().cast(),
206             fds.len() as libc::nfds_t,
207             i32::from(timeout.into()),
208         )
209     };
210 
211     Errno::result(res)
212 }
213 
214 feature! {
215 #![feature = "signal"]
216 /// `ppoll()` allows an application to safely wait until either a file
217 /// descriptor becomes ready or until a signal is caught.
218 /// ([`poll(2)`](https://man7.org/linux/man-pages/man2/poll.2.html))
219 ///
220 /// `ppoll` behaves like `poll`, but let you specify what signals may interrupt it
221 /// with the `sigmask` argument. If you want `ppoll` to block indefinitely,
222 /// specify `None` as `timeout` (it is like `timeout = -1` for `poll`).
223 /// If `sigmask` is `None`, then no signal mask manipulation is performed,
224 /// so in that case `ppoll` differs from `poll` only in the precision of the
225 /// timeout argument.
226 ///
227 #[cfg(any(linux_android, freebsdlike))]
228 pub fn ppoll(
229     fds: &mut [PollFd],
230     timeout: Option<crate::sys::time::TimeSpec>,
231     sigmask: Option<crate::sys::signal::SigSet>
232     ) -> Result<libc::c_int>
233 {
234     let timeout = timeout.as_ref().map_or(core::ptr::null(), |r| r.as_ref());
235     let sigmask = sigmask.as_ref().map_or(core::ptr::null(), |r| r.as_ref());
236     let res = unsafe {
237         libc::ppoll(fds.as_mut_ptr().cast(),
238                     fds.len() as libc::nfds_t,
239                     timeout,
240                     sigmask)
241     };
242     Errno::result(res)
243 }
244 }
245