|
1 | 1 | use std::mem;
|
2 | 2 | use std::os::unix::io::RawFd;
|
3 |
| -use std::ptr::null_mut; |
| 3 | +use std::ptr::{null, null_mut}; |
4 | 4 | use libc::{self, c_int};
|
5 | 5 | use Result;
|
6 | 6 | use errno::Errno;
|
7 |
| -use sys::time::TimeVal; |
| 7 | +use sys::signal::SigSet; |
| 8 | +use sys::time::{TimeSpec, TimeVal}; |
8 | 9 |
|
9 | 10 | pub use libc::FD_SETSIZE;
|
10 | 11 |
|
@@ -131,6 +132,78 @@ where
|
131 | 132 | Errno::result(res)
|
132 | 133 | }
|
133 | 134 |
|
| 135 | +/// Monitors file descriptors for readiness with an altered signal mask. |
| 136 | +/// |
| 137 | +/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all |
| 138 | +/// file descriptors that are ready for the given operation are set. |
| 139 | +/// |
| 140 | +/// When this function returns, the original signal mask is restored. |
| 141 | +/// |
| 142 | +/// Unlike [`select`](#fn.select), `pselect` does not mutate the `timeout` value. |
| 143 | +/// |
| 144 | +/// # Parameters |
| 145 | +/// |
| 146 | +/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this |
| 147 | +/// is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1 |
| 148 | +/// to the maximum of that. |
| 149 | +/// * `readfds`: File descriptors to check for read readiness |
| 150 | +/// * `writefds`: File descriptors to check for write readiness |
| 151 | +/// * `errorfds`: File descriptors to check for pending error conditions. |
| 152 | +/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block |
| 153 | +/// indefinitely). |
| 154 | +/// * `sigmask`: Signal mask to activate while waiting for file descriptors to turn |
| 155 | +/// ready (`None` to set no alternative signal mask). |
| 156 | +/// |
| 157 | +/// # References |
| 158 | +/// |
| 159 | +/// [pselect(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html) |
| 160 | +/// |
| 161 | +/// [The new pselect() system call](https://lwn.net/Articles/176911/) |
| 162 | +/// |
| 163 | +/// [`FdSet::highest`]: struct.FdSet.html#method.highest |
| 164 | +pub fn pselect<'a, N, R, W, E, T, S>(nfds: N, |
| 165 | + readfds: R, |
| 166 | + writefds: W, |
| 167 | + errorfds: E, |
| 168 | + timeout: T, |
| 169 | + sigmask: S) -> Result<c_int> |
| 170 | +where |
| 171 | + N: Into<Option<c_int>>, |
| 172 | + R: Into<Option<&'a mut FdSet>>, |
| 173 | + W: Into<Option<&'a mut FdSet>>, |
| 174 | + E: Into<Option<&'a mut FdSet>>, |
| 175 | + T: Into<Option<&'a TimeSpec>>, |
| 176 | + S: Into<Option<&'a SigSet>>, |
| 177 | +{ |
| 178 | + let mut readfds = readfds.into(); |
| 179 | + let mut writefds = writefds.into(); |
| 180 | + let mut errorfds = errorfds.into(); |
| 181 | + let sigmask = sigmask.into(); |
| 182 | + let timeout = timeout.into(); |
| 183 | + |
| 184 | + let nfds = nfds.into().unwrap_or_else(|| { |
| 185 | + readfds.iter_mut() |
| 186 | + .chain(writefds.iter_mut()) |
| 187 | + .chain(errorfds.iter_mut()) |
| 188 | + .map(|set| set.highest().unwrap_or(-1)) |
| 189 | + .max() |
| 190 | + .unwrap_or(-1) + 1 |
| 191 | + }); |
| 192 | + |
| 193 | + let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); |
| 194 | + let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); |
| 195 | + let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); |
| 196 | + let timeout = timeout.map(|ts| ts.as_ref() as *const libc::timespec).unwrap_or(null()); |
| 197 | + let sigmask = sigmask.map(|sm| sm.as_ref() as *const libc::sigset_t).unwrap_or(null()); |
| 198 | + |
| 199 | + let res = unsafe { |
| 200 | + libc::pselect(nfds, readfds, writefds, errorfds, timeout, sigmask) |
| 201 | + }; |
| 202 | + |
| 203 | + Errno::result(res) |
| 204 | +} |
| 205 | + |
| 206 | + |
134 | 207 | #[cfg(test)]
|
135 | 208 | mod tests {
|
136 | 209 | use super::*;
|
|
0 commit comments