From 1b5ea70a6cea1df3efc91b6a7fb6acf20fc7f99f Mon Sep 17 00:00:00 2001 From: Ross Light Date: Tue, 7 Apr 2020 18:32:55 -0700 Subject: [PATCH 1/8] Add select::FdSet::fds() method --- CHANGELOG.md | 3 ++ src/sys/select.rs | 108 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 87 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f76bfaa24..964b749b37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,11 +15,14 @@ This project adheres to [Semantic Versioning](http://semver.org/). identity for filesystem checks per-thread. (#[1163](https://github.com/nix-rust/nix/pull/1163)) - Derived `Ord`, `PartialOrd` for `unistd::Pid` (#[1189](https://github.com/nix-rust/nix/pull/1189)) +- Added `select::FdSet::fds` method to iterate over file descriptors in a set. ### Changed - Changed `fallocate` return type from `c_int` to `()` (#[1201](https://github.com/nix-rust/nix/pull/1201)) - Enabled `sys::ptrace::setregs` and `sys::ptrace::getregs` on x86_64-unknown-linux-musl target (#[1198](https://github.com/nix-rust/nix/pull/1198)) +- `select::FdSet::contains` and `select::FdSet::highest` now operate on `&FdSet` + instead of `&mut FdSet`. ### Fixed diff --git a/src/sys/select.rs b/src/sys/select.rs index 32569acc70..bfc0e80e91 100644 --- a/src/sys/select.rs +++ b/src/sys/select.rs @@ -1,4 +1,6 @@ +use std::iter::FusedIterator; use std::mem; +use std::ops::Range; use std::os::unix::io::RawFd; use std::ptr::{null, null_mut}; use libc::{self, c_int}; @@ -30,8 +32,9 @@ impl FdSet { unsafe { libc::FD_CLR(fd, &mut self.0) }; } - pub fn contains(&mut self, fd: RawFd) -> bool { - unsafe { libc::FD_ISSET(fd, &mut self.0) } + pub fn contains(&self, fd: RawFd) -> bool { + let mut copy = self.0; + unsafe { libc::FD_ISSET(fd, &mut copy) } } pub fn clear(&mut self) { @@ -58,15 +61,32 @@ impl FdSet { /// ``` /// /// [`select`]: fn.select.html - pub fn highest(&mut self) -> Option { - for i in (0..FD_SETSIZE).rev() { - let i = i as RawFd; - if unsafe { libc::FD_ISSET(i, self as *mut _ as *mut libc::fd_set) } { - return Some(i) - } - } + pub fn highest(&self) -> Option { + self.fds().next_back() + } - None + /// Returns an iterator over the file descriptors in the set. + /// + /// # Examples + /// + /// ``` + /// # extern crate nix; + /// # use nix::sys::select::FdSet; + /// # use std::os::unix::io::RawFd; + /// # fn main() { + /// let mut set = FdSet::new(); + /// set.insert(4); + /// set.insert(9); + /// let fds: Vec = set.fds().collect(); + /// assert_eq!(fds, vec![4, 9]); + /// # } + /// ``` + #[inline] + pub fn fds(&self) -> Fds { + Fds { + set: self, + range: 0..FD_SETSIZE, + } } } @@ -76,6 +96,46 @@ impl Default for FdSet { } } +/// Iterator over `FdSet`. +#[derive(Clone, Debug)] +pub struct Fds<'a> { + set: &'a FdSet, + range: Range, +} + +impl<'a> Iterator for Fds<'a> { + type Item = RawFd; + + fn next(&mut self) -> Option { + while let Some(i) = self.range.next() { + if self.set.contains(i as RawFd) { + return Some(i as RawFd); + } + } + None + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.range.size_hint(); + (0, upper) + } +} + +impl<'a> DoubleEndedIterator for Fds<'a> { + #[inline] + fn next_back(&mut self) -> Option { + while let Some(i) = self.range.next_back() { + if self.set.contains(i as RawFd) { + return Some(i as RawFd); + } + } + None + } +} + +impl<'a> FusedIterator for Fds<'a> {} + /// Monitors file descriptors for readiness /// /// Returns the total number of ready file descriptors in all sets. The sets are changed so that all @@ -100,9 +160,9 @@ impl Default for FdSet { /// /// [`FdSet::highest`]: struct.FdSet.html#method.highest pub fn select<'a, N, R, W, E, T>(nfds: N, - readfds: R, - writefds: W, - errorfds: E, + readfds: R, + writefds: W, + errorfds: E, timeout: T) -> Result where N: Into>, @@ -129,7 +189,7 @@ where let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); let timeout = timeout.map(|tv| tv as *mut _ as *mut libc::timeval) - .unwrap_or(null_mut()); + .unwrap_or(null_mut()); let res = unsafe { libc::select(nfds, readfds, writefds, errorfds, timeout) @@ -168,10 +228,10 @@ where /// /// [`FdSet::highest`]: struct.FdSet.html#method.highest pub fn pselect<'a, N, R, W, E, T, S>(nfds: N, - readfds: R, - writefds: W, - errorfds: E, - timeout: T, + readfds: R, + writefds: W, + errorfds: E, + timeout: T, sigmask: S) -> Result where N: Into>, @@ -311,9 +371,9 @@ mod tests { let mut timeout = TimeVal::seconds(10); assert_eq!(1, select(Some(fd_set.highest().unwrap() + 1), - &mut fd_set, - None, - None, + &mut fd_set, + None, + None, &mut timeout).unwrap()); assert!(fd_set.contains(r1)); assert!(!fd_set.contains(r2)); @@ -331,9 +391,9 @@ mod tests { let mut timeout = TimeVal::seconds(10); assert_eq!(1, select(::std::cmp::max(r1, r2) + 1, - &mut fd_set, - None, - None, + &mut fd_set, + None, + None, &mut timeout).unwrap()); assert!(fd_set.contains(r1)); assert!(!fd_set.contains(r2)); From 41db1bf213cf5a15423380d031ad6009004443ba Mon Sep 17 00:00:00 2001 From: Ross Light Date: Sat, 11 Apr 2020 08:35:09 -0700 Subject: [PATCH 2/8] Remove unnecessary fn main wrapper in example --- src/sys/select.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sys/select.rs b/src/sys/select.rs index bfc0e80e91..b914ffae1b 100644 --- a/src/sys/select.rs +++ b/src/sys/select.rs @@ -73,13 +73,11 @@ impl FdSet { /// # extern crate nix; /// # use nix::sys::select::FdSet; /// # use std::os::unix::io::RawFd; - /// # fn main() { /// let mut set = FdSet::new(); /// set.insert(4); /// set.insert(9); /// let fds: Vec = set.fds().collect(); /// assert_eq!(fds, vec![4, 9]); - /// # } /// ``` #[inline] pub fn fds(&self) -> Fds { From 8b4a43386f8d0c6f68c21f113cb7b52909457f04 Mon Sep 17 00:00:00 2001 From: Ross Light Date: Mon, 13 Apr 2020 09:26:22 -0700 Subject: [PATCH 3/8] Operate on &mut --- src/sys/select.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/sys/select.rs b/src/sys/select.rs index b914ffae1b..8591dd85e1 100644 --- a/src/sys/select.rs +++ b/src/sys/select.rs @@ -32,9 +32,8 @@ impl FdSet { unsafe { libc::FD_CLR(fd, &mut self.0) }; } - pub fn contains(&self, fd: RawFd) -> bool { - let mut copy = self.0; - unsafe { libc::FD_ISSET(fd, &mut copy) } + pub fn contains(&mut self, fd: RawFd) -> bool { + unsafe { libc::FD_ISSET(fd, &mut self.0) } } pub fn clear(&mut self) { @@ -61,11 +60,13 @@ impl FdSet { /// ``` /// /// [`select`]: fn.select.html - pub fn highest(&self) -> Option { - self.fds().next_back() + pub fn highest(&mut self) -> Option { + self.fds(None).next_back() } - /// Returns an iterator over the file descriptors in the set. + /// Returns an iterator over the file descriptors in the set. For + /// performance, it takes an optional higher bound: the iterator will not + /// return any elements of the set greater than the given file descriptor. /// /// # Examples /// @@ -76,14 +77,14 @@ impl FdSet { /// let mut set = FdSet::new(); /// set.insert(4); /// set.insert(9); - /// let fds: Vec = set.fds().collect(); + /// let fds: Vec = set.fds(None).collect(); /// assert_eq!(fds, vec![4, 9]); /// ``` #[inline] - pub fn fds(&self) -> Fds { + pub fn fds(&mut self, highest: Option) -> Fds { Fds { set: self, - range: 0..FD_SETSIZE, + range: 0..highest.map(|h| h as usize + 1).unwrap_or(FD_SETSIZE), } } } @@ -95,9 +96,9 @@ impl Default for FdSet { } /// Iterator over `FdSet`. -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct Fds<'a> { - set: &'a FdSet, + set: &'a mut FdSet, range: Range, } From 4a101ae9be49cdf71aed995467501c18b152feb8 Mon Sep 17 00:00:00 2001 From: Ross Light Date: Mon, 13 Apr 2020 09:41:21 -0700 Subject: [PATCH 4/8] Remove immutable borrow note from CHANGELOG --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 964b749b37..fd70a67023 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,8 +21,6 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Changed `fallocate` return type from `c_int` to `()` (#[1201](https://github.com/nix-rust/nix/pull/1201)) - Enabled `sys::ptrace::setregs` and `sys::ptrace::getregs` on x86_64-unknown-linux-musl target (#[1198](https://github.com/nix-rust/nix/pull/1198)) -- `select::FdSet::contains` and `select::FdSet::highest` now operate on `&FdSet` - instead of `&mut FdSet`. ### Fixed From bcfcf823c4aa930101b5274b877f1ac166a43584 Mon Sep 17 00:00:00 2001 From: Ross Light Date: Tue, 14 Apr 2020 10:04:10 -0700 Subject: [PATCH 5/8] Add PR reference to CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd70a67023..d0889bda95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). (#[1163](https://github.com/nix-rust/nix/pull/1163)) - Derived `Ord`, `PartialOrd` for `unistd::Pid` (#[1189](https://github.com/nix-rust/nix/pull/1189)) - Added `select::FdSet::fds` method to iterate over file descriptors in a set. + (#[#1207](https://github.com/nix-rust/nix/pull/1207)) ### Changed - Changed `fallocate` return type from `c_int` to `()` (#[1201](https://github.com/nix-rust/nix/pull/1201)) From eb5f28949cafd142362a693d2ddd750074f7c2af Mon Sep 17 00:00:00 2001 From: Ross Light Date: Tue, 14 Apr 2020 10:04:30 -0700 Subject: [PATCH 6/8] Add space to doc comment of fds --- src/sys/select.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sys/select.rs b/src/sys/select.rs index 8591dd85e1..9359cc5981 100644 --- a/src/sys/select.rs +++ b/src/sys/select.rs @@ -64,9 +64,11 @@ impl FdSet { self.fds(None).next_back() } - /// Returns an iterator over the file descriptors in the set. For - /// performance, it takes an optional higher bound: the iterator will not - /// return any elements of the set greater than the given file descriptor. + /// Returns an iterator over the file descriptors in the set. + /// + /// For performance, it takes an optional higher bound: the iterator will + /// not return any elements of the set greater than the given file + /// descriptor. /// /// # Examples /// From 1171817fc4707b065597c88b630a6d61801805d7 Mon Sep 17 00:00:00 2001 From: Ross Light Date: Tue, 14 Apr 2020 10:10:00 -0700 Subject: [PATCH 7/8] Added fds test --- src/sys/select.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/sys/select.rs b/src/sys/select.rs index 9359cc5981..a46985bc4c 100644 --- a/src/sys/select.rs +++ b/src/sys/select.rs @@ -340,6 +340,20 @@ mod tests { assert_eq!(set.highest(), Some(7)); } + #[test] + fn fdset_fds() { + let mut set = FdSet::new(); + assert_eq!(set.fds(None).collect::>(), vec![]); + set.insert(0); + assert_eq!(set.fds(None).collect::>(), vec![0]); + set.insert(90); + assert_eq!(set.fds(None).collect::>(), vec![0, 90]); + + // highest limit + assert_eq!(set.fds(Some(89)).collect::>(), vec![0]); + assert_eq!(set.fds(Some(90)).collect::>(), vec![0, 90]); + } + #[test] fn test_select() { let (r1, w1) = pipe().unwrap(); From e8c796154a8231d61c68d51eaf07b5db95d70087 Mon Sep 17 00:00:00 2001 From: Ross Light Date: Tue, 14 Apr 2020 10:11:22 -0700 Subject: [PATCH 8/8] Remove stray # in CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0889bda95..fab232a635 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). (#[1163](https://github.com/nix-rust/nix/pull/1163)) - Derived `Ord`, `PartialOrd` for `unistd::Pid` (#[1189](https://github.com/nix-rust/nix/pull/1189)) - Added `select::FdSet::fds` method to iterate over file descriptors in a set. - (#[#1207](https://github.com/nix-rust/nix/pull/1207)) + ([#1207](https://github.com/nix-rust/nix/pull/1207)) ### Changed - Changed `fallocate` return type from `c_int` to `()` (#[1201](https://github.com/nix-rust/nix/pull/1201))