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