summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndreas Fuchs <asf@boinkor.net>2018-04-28 21:08:39 +0200
committerAndreas Fuchs <asf@boinkor.net>2018-04-28 23:54:54 +0200
commit492903ba6c89b3f042cd9336b321020b23b98f5f (patch)
treef3306f88bcd69295e7618b83affda42f62c95ba4 /src
parentc2fb79e2fd6ecc15589f532459db06a506696efa (diff)
downloadnix-492903ba6c89b3f042cd9336b321020b23b98f5f.zip
select: add pselect syscall
This is a straight port of @abbradar's work in #276, with two (somewhat weak) tests and a bit of documentation.
Diffstat (limited to 'src')
-rw-r--r--src/sys/select.rs77
1 files changed, 75 insertions, 2 deletions
diff --git a/src/sys/select.rs b/src/sys/select.rs
index 33d3e638..0b6d2c40 100644
--- a/src/sys/select.rs
+++ b/src/sys/select.rs
@@ -1,10 +1,11 @@
use std::mem;
use std::os::unix::io::RawFd;
-use std::ptr::null_mut;
+use std::ptr::{null, null_mut};
use libc::{self, c_int};
use Result;
use errno::Errno;
-use sys::time::TimeVal;
+use sys::signal::SigSet;
+use sys::time::{TimeSpec, TimeVal};
pub use libc::FD_SETSIZE;
@@ -131,6 +132,78 @@ where
Errno::result(res)
}
+/// Monitors file descriptors for readiness with an altered signal mask.
+///
+/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
+/// file descriptors that are ready for the given operation are set.
+///
+/// When this function returns, the original signal mask is restored.
+///
+/// Unlike [`select`](#fn.select), `pselect` does not mutate the `timeout` value.
+///
+/// # Parameters
+///
+/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this
+/// is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1
+/// to the maximum of that.
+/// * `readfds`: File descriptors to check for read readiness
+/// * `writefds`: File descriptors to check for write readiness
+/// * `errorfds`: File descriptors to check for pending error conditions.
+/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block
+/// indefinitely).
+/// * `sigmask`: Signal mask to activate while waiting for file descriptors to turn
+/// ready (`None` to set no alternative signal mask).
+///
+/// # References
+///
+/// [pselect(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html)
+///
+/// [The new pselect() system call](https://lwn.net/Articles/176911/)
+///
+/// [`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,
+ sigmask: S) -> Result<c_int>
+where
+ N: Into<Option<c_int>>,
+ R: Into<Option<&'a mut FdSet>>,
+ W: Into<Option<&'a mut FdSet>>,
+ E: Into<Option<&'a mut FdSet>>,
+ T: Into<Option<&'a TimeSpec>>,
+ S: Into<Option<&'a SigSet>>,
+{
+ let mut readfds = readfds.into();
+ let mut writefds = writefds.into();
+ let mut errorfds = errorfds.into();
+ let sigmask = sigmask.into();
+ let timeout = timeout.into();
+
+ let nfds = nfds.into().unwrap_or_else(|| {
+ readfds.iter_mut()
+ .chain(writefds.iter_mut())
+ .chain(errorfds.iter_mut())
+ .map(|set| set.highest().unwrap_or(-1))
+ .max()
+ .unwrap_or(-1) + 1
+ });
+
+ let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
+ 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(|ts| ts.as_ref() as *const libc::timespec).unwrap_or(null());
+ let sigmask = sigmask.map(|sm| sm.as_ref() as *const libc::sigset_t).unwrap_or(null());
+
+ let res = unsafe {
+ libc::pselect(nfds, readfds, writefds, errorfds, timeout, sigmask)
+ };
+
+ Errno::result(res)
+}
+
+
#[cfg(test)]
mod tests {
use super::*;