Skip to content

Commit cbc0dcd

Browse files
Remove Copy from PollFd
PollFd implementing Copy makes it easy to accidentally refer to the wrong object after putting one into an array. Remove Copy to force move semantics. This also updates some related docs to improve overall clarity. This fixes #2630
1 parent eba0f41 commit cbc0dcd

File tree

2 files changed

+38
-12
lines changed

2 files changed

+38
-12
lines changed

changelog/2631.removed.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Removed the `Copy` trait from `PollFd`

src/poll.rs

+37-12
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ use crate::Result;
1111
/// [`ppoll`](fn.ppoll.html) functions to specify the events of interest
1212
/// for a specific file descriptor.
1313
///
14-
/// After a call to `poll` or `ppoll`, the events that occurred can be
15-
/// retrieved by calling [`revents()`](#method.revents) on the `PollFd`.
14+
/// After a call to `poll` or `ppoll`, the events that occurred can be retrieved by calling
15+
/// [`revents()`](#method.revents) on the `PollFd` object from the array passed to `poll`.
1616
#[repr(transparent)]
17-
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
17+
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1818
pub struct PollFd<'fd> {
1919
pollfd: libc::pollfd,
2020
_fd: std::marker::PhantomData<BorrowedFd<'fd>>,
@@ -33,11 +33,8 @@ impl<'fd> PollFd<'fd> {
3333
/// # };
3434
/// let (r, w) = pipe().unwrap();
3535
/// 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, &mut buf[..]);
4036
/// ```
37+
/// These are placed in an array and passed to [`poll`] or [`ppoll`](fn.ppoll.html).
4138
// Unlike I/O functions, constructors like this must take `BorrowedFd`
4239
// instead of AsFd or &AsFd. Otherwise, an `OwnedFd` argument would be
4340
// dropped at the end of the method, leaving the structure referencing a
@@ -61,7 +58,7 @@ impl<'fd> PollFd<'fd> {
6158

6259
/// Returns the events that occurred in the last call to `poll` or `ppoll`. Will only return
6360
/// `None` if the kernel provides status flags that Nix does not know about.
64-
pub fn revents(self) -> Option<PollFlags> {
61+
pub fn revents(&self) -> Option<PollFlags> {
6562
PollFlags::from_bits(self.pollfd.revents)
6663
}
6764

@@ -71,7 +68,7 @@ impl<'fd> PollFd<'fd> {
7168
/// Equivalent to `x.revents()? != PollFlags::empty()`.
7269
///
7370
/// This is marginally more efficient than [`PollFd::all`].
74-
pub fn any(self) -> Option<bool> {
71+
pub fn any(&self) -> Option<bool> {
7572
Some(self.revents()? != PollFlags::empty())
7673
}
7774

@@ -81,12 +78,12 @@ impl<'fd> PollFd<'fd> {
8178
/// Equivalent to `x.revents()? & x.events() == x.events()`.
8279
///
8380
/// This is marginally less efficient than [`PollFd::any`].
84-
pub fn all(self) -> Option<bool> {
81+
pub fn all(&self) -> Option<bool> {
8582
Some(self.revents()? & self.events() == self.events())
8683
}
8784

8885
/// The events of interest for this `PollFd`.
89-
pub fn events(self) -> PollFlags {
86+
pub fn events(&self) -> PollFlags {
9087
PollFlags::from_bits(self.pollfd.events).unwrap()
9188
}
9289

@@ -196,6 +193,34 @@ libc_bitflags! {
196193
/// in timeout means an infinite timeout. Specifying a timeout of
197194
/// [`PollTimeout::ZERO`] causes `poll()` to return immediately, even if no file
198195
/// descriptors are ready.
196+
///
197+
/// The return value contains the number of `fds` which have selected events ([`PollFd::revents`]).
198+
///
199+
/// # Examples
200+
/// ```no_run
201+
/// # use std::os::unix::io::{AsFd, AsRawFd, FromRawFd};
202+
/// # use nix::{
203+
/// # poll::{PollTimeout, PollFd, PollFlags, poll},
204+
/// # unistd::{pipe, read}
205+
/// # };
206+
/// let (r0, w0) = pipe().unwrap();
207+
/// let (r1, w1) = pipe().unwrap();
208+
///
209+
/// let mut pollfds = [
210+
/// PollFd::new(r0.as_fd(), PollFlags::POLLIN),
211+
/// PollFd::new(r1.as_fd(), PollFlags::POLLIN),
212+
/// ];
213+
///
214+
/// let nready = poll(&mut pollfds, PollTimeout::NONE).unwrap();
215+
/// assert!(nready >= 1); // Since there is no timeout
216+
///
217+
/// let mut buf = [0u8; 80];
218+
/// if pollfds[0].any().unwrap_or_default() {
219+
/// read(&r0, &mut buf[..]);
220+
/// } else if pollfds[1].any().unwrap_or_default() {
221+
/// read(&r1, &mut buf[..]);
222+
/// }
223+
/// ```
199224
pub fn poll<T: Into<PollTimeout>>(
200225
fds: &mut [PollFd],
201226
timeout: T,
@@ -217,7 +242,7 @@ feature! {
217242
/// descriptor becomes ready or until a signal is caught.
218243
/// ([`poll(2)`](https://man7.org/linux/man-pages/man2/poll.2.html))
219244
///
220-
/// `ppoll` behaves like `poll`, but let you specify what signals may interrupt it
245+
/// `ppoll` behaves like [`poll`], but let you specify what signals may interrupt it
221246
/// with the `sigmask` argument. If you want `ppoll` to block indefinitely,
222247
/// specify `None` as `timeout` (it is like `timeout = -1` for `poll`).
223248
/// If `sigmask` is `None`, then no signal mask manipulation is performed,

0 commit comments

Comments
 (0)