1use crate::errno::Errno;
3use crate::sys::time::{TimeSpec, TimeVal};
4use crate::Result;
5use libc::{self, c_int};
6use std::convert::TryFrom;
7use std::iter::FusedIterator;
8use std::mem;
9use std::ops::Range;
10use std::os::unix::io::{AsRawFd, BorrowedFd, RawFd};
11use std::ptr::{null, null_mut};
12
13pub use libc::FD_SETSIZE;
14
15#[repr(transparent)]
17#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
18pub struct FdSet<'fd> {
19 set: libc::fd_set,
20 _fd: std::marker::PhantomData<BorrowedFd<'fd>>,
21}
22
23fn assert_fd_valid(fd: RawFd) {
24 assert!(
25 usize::try_from(fd).map_or(false, |fd| fd < FD_SETSIZE),
26 "fd must be in the range 0..FD_SETSIZE",
27 );
28}
29
30impl<'fd> FdSet<'fd> {
31 pub fn new() -> FdSet<'fd> {
33 let mut fdset = mem::MaybeUninit::uninit();
34 unsafe {
35 libc::FD_ZERO(fdset.as_mut_ptr());
36 Self {
37 set: fdset.assume_init(),
38 _fd: std::marker::PhantomData,
39 }
40 }
41 }
42
43 pub fn insert(&mut self, fd: BorrowedFd<'fd>) {
45 assert_fd_valid(fd.as_raw_fd());
46 unsafe { libc::FD_SET(fd.as_raw_fd(), &mut self.set) };
47 }
48
49 pub fn remove(&mut self, fd: BorrowedFd<'fd>) {
51 assert_fd_valid(fd.as_raw_fd());
52 unsafe { libc::FD_CLR(fd.as_raw_fd(), &mut self.set) };
53 }
54
55 pub fn contains(&self, fd: BorrowedFd<'fd>) -> bool {
57 assert_fd_valid(fd.as_raw_fd());
58 unsafe { libc::FD_ISSET(fd.as_raw_fd(), &self.set) }
59 }
60
61 pub fn clear(&mut self) {
63 unsafe { libc::FD_ZERO(&mut self.set) };
64 }
65
66 pub fn highest(&self) -> Option<BorrowedFd<'_>> {
87 self.fds(None).next_back()
88 }
89
90 #[inline]
110 pub fn fds(&self, highest: Option<RawFd>) -> Fds {
111 Fds {
112 set: self,
113 range: 0..highest.map(|h| h as usize + 1).unwrap_or(FD_SETSIZE),
114 }
115 }
116}
117
118impl<'fd> Default for FdSet<'fd> {
119 fn default() -> Self {
120 Self::new()
121 }
122}
123
124#[derive(Debug)]
126pub struct Fds<'a, 'fd> {
127 set: &'a FdSet<'fd>,
128 range: Range<usize>,
129}
130
131impl<'a, 'fd> Iterator for Fds<'a, 'fd> {
132 type Item = BorrowedFd<'fd>;
133
134 fn next(&mut self) -> Option<Self::Item> {
135 for i in &mut self.range {
136 let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
137 if self.set.contains(borrowed_i) {
138 return Some(borrowed_i);
139 }
140 }
141 None
142 }
143
144 #[inline]
145 fn size_hint(&self) -> (usize, Option<usize>) {
146 let (_, upper) = self.range.size_hint();
147 (0, upper)
148 }
149}
150
151impl<'a, 'fd> DoubleEndedIterator for Fds<'a, 'fd> {
152 #[inline]
153 fn next_back(&mut self) -> Option<BorrowedFd<'fd>> {
154 while let Some(i) = self.range.next_back() {
155 let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
156 if self.set.contains(borrowed_i) {
157 return Some(borrowed_i);
158 }
159 }
160 None
161 }
162}
163
164impl<'a, 'fd> FusedIterator for Fds<'a, 'fd> {}
165
166pub fn select<'a, 'fd, N, R, W, E, T>(
190 nfds: N,
191 readfds: R,
192 writefds: W,
193 errorfds: E,
194 timeout: T,
195) -> Result<c_int>
196where
197 'fd: 'a,
198 N: Into<Option<c_int>>,
199 R: Into<Option<&'a mut FdSet<'fd>>>,
200 W: Into<Option<&'a mut FdSet<'fd>>>,
201 E: Into<Option<&'a mut FdSet<'fd>>>,
202 T: Into<Option<&'a mut TimeVal>>,
203{
204 let mut readfds = readfds.into();
205 let mut writefds = writefds.into();
206 let mut errorfds = errorfds.into();
207 let timeout = timeout.into();
208
209 let nfds = nfds.into().unwrap_or_else(|| {
210 readfds
211 .iter_mut()
212 .chain(writefds.iter_mut())
213 .chain(errorfds.iter_mut())
214 .map(|set| {
215 set.highest()
216 .map(|borrowed_fd| borrowed_fd.as_raw_fd())
217 .unwrap_or(-1)
218 })
219 .max()
220 .unwrap_or(-1)
221 + 1
222 });
223
224 let readfds = readfds
225 .map(|set| set as *mut _ as *mut libc::fd_set)
226 .unwrap_or(null_mut());
227 let writefds = writefds
228 .map(|set| set as *mut _ as *mut libc::fd_set)
229 .unwrap_or(null_mut());
230 let errorfds = errorfds
231 .map(|set| set as *mut _ as *mut libc::fd_set)
232 .unwrap_or(null_mut());
233 let timeout = timeout
234 .map(|tv| tv as *mut _ as *mut libc::timeval)
235 .unwrap_or(null_mut());
236
237 let res =
238 unsafe { libc::select(nfds, readfds, writefds, errorfds, timeout) };
239
240 Errno::result(res)
241}
242
243feature! {
244#![feature = "signal"]
245
246use crate::sys::signal::SigSet;
247
248pub fn pselect<'a, 'fd, N, R, W, E, T, S>(nfds: N,
278 readfds: R,
279 writefds: W,
280 errorfds: E,
281 timeout: T,
282 sigmask: S) -> Result<c_int>
283where
284 'fd: 'a,
285 N: Into<Option<c_int>>,
286 R: Into<Option<&'a mut FdSet<'fd>>>,
287 W: Into<Option<&'a mut FdSet<'fd>>>,
288 E: Into<Option<&'a mut FdSet<'fd>>>,
289 T: Into<Option<&'a TimeSpec>>,
290 S: Into<Option<&'a SigSet>>,
291{
292 let mut readfds = readfds.into();
293 let mut writefds = writefds.into();
294 let mut errorfds = errorfds.into();
295 let sigmask = sigmask.into();
296 let timeout = timeout.into();
297
298 let nfds = nfds.into().unwrap_or_else(|| {
299 readfds.iter_mut()
300 .chain(writefds.iter_mut())
301 .chain(errorfds.iter_mut())
302 .map(|set| set.highest().map(|borrowed_fd|borrowed_fd.as_raw_fd()).unwrap_or(-1))
303 .max()
304 .unwrap_or(-1) + 1
305 });
306
307 let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
308 let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
309 let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
310 let timeout = timeout.map(|ts| ts.as_ref() as *const libc::timespec).unwrap_or(null());
311 let sigmask = sigmask.map(|sm| sm.as_ref() as *const libc::sigset_t).unwrap_or(null());
312
313 let res = unsafe {
314 libc::pselect(nfds, readfds, writefds, errorfds, timeout, sigmask)
315 };
316
317 Errno::result(res)
318}
319}