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