• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::{AsRawFd, 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 const 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`.  Will only return
39     /// `None` if the kernel provides status flags that Nix does not know about.
revents(self) -> Option<PollFlags>40     pub fn revents(self) -> Option<PollFlags> {
41         PollFlags::from_bits(self.pollfd.revents)
42     }
43 
44     /// The events of interest for this `PollFd`.
events(self) -> PollFlags45     pub fn events(self) -> PollFlags {
46         PollFlags::from_bits(self.pollfd.events).unwrap()
47     }
48 
49     /// Modify the events of interest for this `PollFd`.
set_events(&mut self, events: PollFlags)50     pub fn set_events(&mut self, events: PollFlags) {
51         self.pollfd.events = events.bits();
52     }
53 }
54 
55 impl AsRawFd for PollFd {
as_raw_fd(&self) -> RawFd56     fn as_raw_fd(&self) -> RawFd {
57         self.pollfd.fd
58     }
59 }
60 
61 libc_bitflags! {
62     /// These flags define the different events that can be monitored by `poll` and `ppoll`
63     pub struct PollFlags: libc::c_short {
64         /// There is data to read.
65         POLLIN;
66         /// There is some exceptional condition on the file descriptor.
67         ///
68         /// Possibilities include:
69         ///
70         /// *  There is out-of-band data on a TCP socket (see
71         ///    [tcp(7)](https://man7.org/linux/man-pages/man7/tcp.7.html)).
72         /// *  A pseudoterminal master in packet mode has seen a state
73         ///    change on the slave (see
74         ///    [ioctl_tty(2)](https://man7.org/linux/man-pages/man2/ioctl_tty.2.html)).
75         /// *  A cgroup.events file has been modified (see
76         ///    [cgroups(7)](https://man7.org/linux/man-pages/man7/cgroups.7.html)).
77         POLLPRI;
78         /// Writing is now possible, though a write larger that the
79         /// available space in a socket or pipe will still block (unless
80         /// `O_NONBLOCK` is set).
81         POLLOUT;
82         /// Equivalent to [`POLLIN`](constant.POLLIN.html)
83         #[cfg(not(target_os = "redox"))]
84         POLLRDNORM;
85         #[cfg(not(target_os = "redox"))]
86         /// Equivalent to [`POLLOUT`](constant.POLLOUT.html)
87         POLLWRNORM;
88         /// Priority band data can be read (generally unused on Linux).
89         #[cfg(not(target_os = "redox"))]
90         POLLRDBAND;
91         /// Priority data may be written.
92         #[cfg(not(target_os = "redox"))]
93         POLLWRBAND;
94         /// Error condition (only returned in
95         /// [`PollFd::revents`](struct.PollFd.html#method.revents);
96         /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
97         /// This bit is also set for a file descriptor referring to the
98         /// write end of a pipe when the read end has been closed.
99         POLLERR;
100         /// Hang up (only returned in [`PollFd::revents`](struct.PollFd.html#method.revents);
101         /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
102         /// Note that when reading from a channel such as a pipe or a stream
103         /// socket, this event merely indicates that the peer closed its
104         /// end of the channel.  Subsequent reads from the channel will
105         /// return 0 (end of file) only after all outstanding data in the
106         /// channel has been consumed.
107         POLLHUP;
108         /// Invalid request: `fd` not open (only returned in
109         /// [`PollFd::revents`](struct.PollFd.html#method.revents);
110         /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
111         POLLNVAL;
112     }
113 }
114 
115 /// `poll` waits for one of a set of file descriptors to become ready to perform I/O.
116 /// ([`poll(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html))
117 ///
118 /// `fds` contains all [`PollFd`](struct.PollFd.html) to poll.
119 /// The function will return as soon as any event occur for any of these `PollFd`s.
120 ///
121 /// The `timeout` argument specifies the number of milliseconds that `poll()`
122 /// should block waiting for a file descriptor to become ready.  The call
123 /// will block until either:
124 ///
125 /// *  a file descriptor becomes ready;
126 /// *  the call is interrupted by a signal handler; or
127 /// *  the timeout expires.
128 ///
129 /// Note that the timeout interval will be rounded up to the system clock
130 /// granularity, and kernel scheduling delays mean that the blocking
131 /// interval may overrun by a small amount.  Specifying a negative value
132 /// in timeout means an infinite timeout.  Specifying a timeout of zero
133 /// causes `poll()` to return immediately, even if no file descriptors are
134 /// ready.
poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int>135 pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int> {
136     let res = unsafe {
137         libc::poll(fds.as_mut_ptr() as *mut libc::pollfd,
138                    fds.len() as libc::nfds_t,
139                    timeout)
140     };
141 
142     Errno::result(res)
143 }
144 
145 /// `ppoll()` allows an application to safely wait until either a file
146 /// descriptor becomes ready or until a signal is caught.
147 /// ([`poll(2)`](https://man7.org/linux/man-pages/man2/poll.2.html))
148 ///
149 /// `ppoll` behaves like `poll`, but let you specify what signals may interrupt it
150 /// with the `sigmask` argument. If you want `ppoll` to block indefinitely,
151 /// specify `None` as `timeout` (it is like `timeout = -1` for `poll`).
152 ///
153 #[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>154 pub fn ppoll(fds: &mut [PollFd], timeout: Option<TimeSpec>, sigmask: SigSet) -> Result<libc::c_int> {
155     let timeout = timeout.as_ref().map_or(core::ptr::null(), |r| r.as_ref());
156     let res = unsafe {
157         libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd,
158                     fds.len() as libc::nfds_t,
159                     timeout,
160                     sigmask.as_ref())
161     };
162     Errno::result(res)
163 }
164