Coverage Report

Created: 2024-05-20 06:38

/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
}