1use std::convert::TryFrom;
3use std::iter::FusedIterator;
4use std::mem;
5use std::ops::Range;
6use std::os::unix::io::RawFd;
7use std::ptr::{null, null_mut};
8use libc::{self, c_int};
9use crate::Result;
10use crate::errno::Errno;
11use crate::sys::time::{TimeSpec, TimeVal};
12
13pub use libc::FD_SETSIZE;
14
15#[repr(transparent)]
17#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
18pub struct FdSet(libc::fd_set);
19
20fn assert_fd_valid(fd: RawFd) {
21 assert!(
22 usize::try_from(fd).map_or(false, |fd| fd < FD_SETSIZE),
23 "fd must be in the range 0..FD_SETSIZE",
24 );
25}
26
27impl FdSet {
28 pub fn new() -> FdSet {
30 let mut fdset = mem::MaybeUninit::uninit();
31 unsafe {
32 libc::FD_ZERO(fdset.as_mut_ptr());
33 FdSet(fdset.assume_init())
34 }
35 }
36
37 pub fn insert(&mut self, fd: RawFd) {
39 assert_fd_valid(fd);
40 unsafe { libc::FD_SET(fd, &mut self.0) };
41 }
42
43 pub fn remove(&mut self, fd: RawFd) {
45 assert_fd_valid(fd);
46 unsafe { libc::FD_CLR(fd, &mut self.0) };
47 }
48
49 pub fn contains(&self, fd: RawFd) -> bool {
51 assert_fd_valid(fd);
52 unsafe { libc::FD_ISSET(fd, &self.0) }
53 }
54
55 pub fn clear(&mut self) {
57 unsafe { libc::FD_ZERO(&mut self.0) };
58 }
59
60 pub fn highest(&self) -> Option<RawFd> {
78 self.fds(None).next_back()
79 }
80
81 #[inline]
99 pub fn fds(&self, highest: Option<RawFd>) -> Fds {
100 Fds {
101 set: self,
102 range: 0..highest.map(|h| h as usize + 1).unwrap_or(FD_SETSIZE),
103 }
104 }
105}
106
107impl Default for FdSet {
108 fn default() -> Self {
109 Self::new()
110 }
111}
112
113#[derive(Debug)]
115pub struct Fds<'a> {
116 set: &'a FdSet,
117 range: Range<usize>,
118}
119
120impl<'a> Iterator for Fds<'a> {
121 type Item = RawFd;
122
123 fn next(&mut self) -> Option<RawFd> {
124 for i in &mut self.range {
125 if self.set.contains(i as RawFd) {
126 return Some(i as RawFd);
127 }
128 }
129 None
130 }
131
132 #[inline]
133 fn size_hint(&self) -> (usize, Option<usize>) {
134 let (_, upper) = self.range.size_hint();
135 (0, upper)
136 }
137}
138
139impl<'a> DoubleEndedIterator for Fds<'a> {
140 #[inline]
141 fn next_back(&mut self) -> Option<RawFd> {
142 while let Some(i) = self.range.next_back() {
143 if self.set.contains(i as RawFd) {
144 return Some(i as RawFd);
145 }
146 }
147 None
148 }
149}
150
151impl<'a> FusedIterator for Fds<'a> {}
152
153pub fn select<'a, N, R, W, E, T>(nfds: N,
177 readfds: R,
178 writefds: W,
179 errorfds: E,
180 timeout: T) -> Result<c_int>
181where
182 N: Into<Option<c_int>>,
183 R: Into<Option<&'a mut FdSet>>,
184 W: Into<Option<&'a mut FdSet>>,
185 E: Into<Option<&'a mut FdSet>>,
186 T: Into<Option<&'a mut TimeVal>>,
187{
188 let mut readfds = readfds.into();
189 let mut writefds = writefds.into();
190 let mut errorfds = errorfds.into();
191 let timeout = timeout.into();
192
193 let nfds = nfds.into().unwrap_or_else(|| {
194 readfds.iter_mut()
195 .chain(writefds.iter_mut())
196 .chain(errorfds.iter_mut())
197 .map(|set| set.highest().unwrap_or(-1))
198 .max()
199 .unwrap_or(-1) + 1
200 });
201
202 let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
203 let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
204 let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
205 let timeout = timeout.map(|tv| tv as *mut _ as *mut libc::timeval)
206 .unwrap_or(null_mut());
207
208 let res = unsafe {
209 libc::select(nfds, readfds, writefds, errorfds, timeout)
210 };
211
212 Errno::result(res)
213}
214
215feature! {
216#![feature = "signal"]
217
218use crate::sys::signal::SigSet;
219
220pub fn pselect<'a, N, R, W, E, T, S>(nfds: N,
250 readfds: R,
251 writefds: W,
252 errorfds: E,
253 timeout: T,
254 sigmask: S) -> Result<c_int>
255where
256 N: Into<Option<c_int>>,
257 R: Into<Option<&'a mut FdSet>>,
258 W: Into<Option<&'a mut FdSet>>,
259 E: Into<Option<&'a mut FdSet>>,
260 T: Into<Option<&'a TimeSpec>>,
261 S: Into<Option<&'a SigSet>>,
262{
263 let mut readfds = readfds.into();
264 let mut writefds = writefds.into();
265 let mut errorfds = errorfds.into();
266 let sigmask = sigmask.into();
267 let timeout = timeout.into();
268
269 let nfds = nfds.into().unwrap_or_else(|| {
270 readfds.iter_mut()
271 .chain(writefds.iter_mut())
272 .chain(errorfds.iter_mut())
273 .map(|set| set.highest().unwrap_or(-1))
274 .max()
275 .unwrap_or(-1) + 1
276 });
277
278 let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
279 let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
280 let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
281 let timeout = timeout.map(|ts| ts.as_ref() as *const libc::timespec).unwrap_or(null());
282 let sigmask = sigmask.map(|sm| sm.as_ref() as *const libc::sigset_t).unwrap_or(null());
283
284 let res = unsafe {
285 libc::pselect(nfds, readfds, writefds, errorfds, timeout, sigmask)
286 };
287
288 Errno::result(res)
289}
290}
291
292#[cfg(test)]
293mod tests {
294 use super::*;
295 use std::os::unix::io::RawFd;
296 use crate::sys::time::{TimeVal, TimeValLike};
297 use crate::unistd::{write, pipe};
298
299 #[test]
300 fn fdset_insert() {
301 let mut fd_set = FdSet::new();
302
303 for i in 0..FD_SETSIZE {
304 assert!(!fd_set.contains(i as RawFd));
305 }
306
307 fd_set.insert(7);
308
309 assert!(fd_set.contains(7));
310 }
311
312 #[test]
313 fn fdset_remove() {
314 let mut fd_set = FdSet::new();
315
316 for i in 0..FD_SETSIZE {
317 assert!(!fd_set.contains(i as RawFd));
318 }
319
320 fd_set.insert(7);
321 fd_set.remove(7);
322
323 for i in 0..FD_SETSIZE {
324 assert!(!fd_set.contains(i as RawFd));
325 }
326 }
327
328 #[test]
329 fn fdset_clear() {
330 let mut fd_set = FdSet::new();
331 fd_set.insert(1);
332 fd_set.insert((FD_SETSIZE / 2) as RawFd);
333 fd_set.insert((FD_SETSIZE - 1) as RawFd);
334
335 fd_set.clear();
336
337 for i in 0..FD_SETSIZE {
338 assert!(!fd_set.contains(i as RawFd));
339 }
340 }
341
342 #[test]
343 fn fdset_highest() {
344 let mut set = FdSet::new();
345 assert_eq!(set.highest(), None);
346 set.insert(0);
347 assert_eq!(set.highest(), Some(0));
348 set.insert(90);
349 assert_eq!(set.highest(), Some(90));
350 set.remove(0);
351 assert_eq!(set.highest(), Some(90));
352 set.remove(90);
353 assert_eq!(set.highest(), None);
354
355 set.insert(4);
356 set.insert(5);
357 set.insert(7);
358 assert_eq!(set.highest(), Some(7));
359 }
360
361 #[test]
362 fn fdset_fds() {
363 let mut set = FdSet::new();
364 assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![]);
365 set.insert(0);
366 assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0]);
367 set.insert(90);
368 assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0, 90]);
369
370 assert_eq!(set.fds(Some(89)).collect::<Vec<_>>(), vec![0]);
372 assert_eq!(set.fds(Some(90)).collect::<Vec<_>>(), vec![0, 90]);
373 }
374
375 #[test]
376 fn test_select() {
377 let (r1, w1) = pipe().unwrap();
378 write(w1, b"hi!").unwrap();
379 let (r2, _w2) = pipe().unwrap();
380
381 let mut fd_set = FdSet::new();
382 fd_set.insert(r1);
383 fd_set.insert(r2);
384
385 let mut timeout = TimeVal::seconds(10);
386 assert_eq!(1, select(None,
387 &mut fd_set,
388 None,
389 None,
390 &mut timeout).unwrap());
391 assert!(fd_set.contains(r1));
392 assert!(!fd_set.contains(r2));
393 }
394
395 #[test]
396 fn test_select_nfds() {
397 let (r1, w1) = pipe().unwrap();
398 write(w1, b"hi!").unwrap();
399 let (r2, _w2) = pipe().unwrap();
400
401 let mut fd_set = FdSet::new();
402 fd_set.insert(r1);
403 fd_set.insert(r2);
404
405 let mut timeout = TimeVal::seconds(10);
406 assert_eq!(1, select(Some(fd_set.highest().unwrap() + 1),
407 &mut fd_set,
408 None,
409 None,
410 &mut timeout).unwrap());
411 assert!(fd_set.contains(r1));
412 assert!(!fd_set.contains(r2));
413 }
414
415 #[test]
416 fn test_select_nfds2() {
417 let (r1, w1) = pipe().unwrap();
418 write(w1, b"hi!").unwrap();
419 let (r2, _w2) = pipe().unwrap();
420
421 let mut fd_set = FdSet::new();
422 fd_set.insert(r1);
423 fd_set.insert(r2);
424
425 let mut timeout = TimeVal::seconds(10);
426 assert_eq!(1, select(::std::cmp::max(r1, r2) + 1,
427 &mut fd_set,
428 None,
429 None,
430 &mut timeout).unwrap());
431 assert!(fd_set.contains(r1));
432 assert!(!fd_set.contains(r2));
433 }
434}