1#![allow(unsafe_code)]
7
8#[cfg(any(linux_like, target_os = "wasi"))]
9use crate::backend::c;
10use crate::event::Timespec;
11use crate::fd::RawFd;
12use crate::{backend, io};
13#[cfg(any(windows, target_os = "wasi"))]
14use core::mem::align_of;
15use core::mem::size_of;
16
17#[cfg(target_os = "wasi")]
21#[repr(C)]
22struct FD_SET {
23 fd_count: usize,
25 fd_array: [i32; c::FD_SETSIZE],
27}
28
29#[cfg(windows)]
30use windows_sys::Win32::Networking::WinSock::FD_SET;
31
32#[cfg(all(
34 target_pointer_width = "64",
35 any(windows, target_os = "freebsd", target_os = "dragonfly")
36))]
37#[repr(transparent)]
38#[derive(Copy, Clone, Default)]
39pub struct FdSetElement(pub(crate) u64);
40
41#[cfg(linux_like)]
43#[repr(transparent)]
44#[derive(Copy, Clone, Default)]
45pub struct FdSetElement(pub(crate) c::c_ulong);
46
47#[cfg(not(any(
49 linux_like,
50 target_os = "wasi",
51 all(
52 target_pointer_width = "64",
53 any(windows, target_os = "freebsd", target_os = "dragonfly")
54 )
55)))]
56#[repr(transparent)]
57#[derive(Copy, Clone, Default)]
58pub struct FdSetElement(pub(crate) u32);
59
60#[cfg(target_os = "wasi")]
62#[repr(transparent)]
63#[derive(Copy, Clone, Default)]
64pub struct FdSetElement(pub(crate) usize);
65
66pub unsafe fn select(
119 nfds: i32,
120 readfds: Option<&mut [FdSetElement]>,
121 writefds: Option<&mut [FdSetElement]>,
122 exceptfds: Option<&mut [FdSetElement]>,
123 timeout: Option<&Timespec>,
124) -> io::Result<i32> {
125 backend::event::syscalls::select(nfds, readfds, writefds, exceptfds, timeout)
126}
127
128#[cfg(not(any(windows, target_os = "wasi")))]
129const BITS: usize = size_of::<FdSetElement>() * 8;
130
131#[doc(alias = "FD_SET")]
133#[inline]
134pub fn fd_set_insert(fds: &mut [FdSetElement], fd: RawFd) {
135 #[cfg(not(any(windows, target_os = "wasi")))]
136 {
137 let fd = fd as usize;
138 fds[fd / BITS].0 |= 1 << (fd % BITS);
139 }
140
141 #[cfg(any(windows, target_os = "wasi"))]
142 {
143 let set = unsafe { &mut *fds.as_mut_ptr().cast::<FD_SET>() };
144 let fd_count = set.fd_count;
145 let fd_array = &set.fd_array[..fd_count as usize];
146
147 if !fd_array.contains(&(fd as _)) {
148 let fd_array = &mut set.fd_array[..fd_count as usize + 1];
149 set.fd_count = fd_count + 1;
150 fd_array[fd_count as usize] = fd as _;
151 }
152 }
153}
154
155#[doc(alias = "FD_CLR")]
157#[inline]
158pub fn fd_set_remove(fds: &mut [FdSetElement], fd: RawFd) {
159 #[cfg(not(any(windows, target_os = "wasi")))]
160 {
161 let fd = fd as usize;
162 fds[fd / BITS].0 &= !(1 << (fd % BITS));
163 }
164
165 #[cfg(any(windows, target_os = "wasi"))]
166 {
167 let set = unsafe { &mut *fds.as_mut_ptr().cast::<FD_SET>() };
168 let fd_count = set.fd_count;
169 let fd_array = &set.fd_array[..fd_count as usize];
170
171 if let Some(pos) = fd_array.iter().position(|p| *p as RawFd == fd) {
172 set.fd_count = fd_count - 1;
173 set.fd_array[pos] = *set.fd_array.last().unwrap();
174 }
175 }
176}
177
178#[inline]
180pub fn fd_set_bound(fds: &[FdSetElement]) -> RawFd {
181 #[cfg(not(any(windows, target_os = "wasi")))]
182 {
183 if let Some(position) = fds.iter().rposition(|element| element.0 != 0) {
184 let element = fds[position].0;
185 (position * BITS + (BITS - element.leading_zeros() as usize)) as RawFd
186 } else {
187 0
188 }
189 }
190
191 #[cfg(any(windows, target_os = "wasi"))]
192 {
193 let set = unsafe { &*fds.as_ptr().cast::<FD_SET>() };
194 let fd_count = set.fd_count;
195 let fd_array = &set.fd_array[..fd_count as usize];
196 let mut max = 0;
197 for fd in fd_array {
198 if *fd >= max {
199 max = *fd + 1;
200 }
201 }
202 max as RawFd
203 }
204}
205
206#[inline]
209pub fn fd_set_num_elements(set_count: usize, nfds: RawFd) -> usize {
210 #[cfg(any(windows, target_os = "wasi"))]
211 {
212 let _ = nfds;
213
214 fd_set_num_elements_for_fd_array(set_count)
215 }
216
217 #[cfg(not(any(windows, target_os = "wasi")))]
218 {
219 let _ = set_count;
220
221 fd_set_num_elements_for_bitvector(nfds)
222 }
223}
224
225#[cfg(any(windows, target_os = "wasi"))]
228#[inline]
229pub(crate) fn fd_set_num_elements_for_fd_array(set_count: usize) -> usize {
230 core::cmp::max(
232 fd_set_num_elements_for_fd_array_raw(set_count),
233 div_ceil(size_of::<FD_SET>(), size_of::<FdSetElement>()),
234 )
235}
236
237#[cfg(any(windows, target_os = "wasi"))]
240#[inline]
241fn fd_set_num_elements_for_fd_array_raw(set_count: usize) -> usize {
242 div_ceil(
245 core::cmp::max(align_of::<FD_SET>(), align_of::<RawFd>()) + set_count * size_of::<RawFd>(),
246 size_of::<FdSetElement>(),
247 )
248}
249
250#[cfg(not(any(windows, target_os = "wasi")))]
253#[inline]
254pub(crate) fn fd_set_num_elements_for_bitvector(nfds: RawFd) -> usize {
255 let nfds = nfds as usize;
257 div_ceil(nfds, BITS)
258}
259
260fn div_ceil(lhs: usize, rhs: usize) -> usize {
261 let d = lhs / rhs;
262 let r = lhs % rhs;
263 if r > 0 {
264 d + 1
265 } else {
266 d
267 }
268}
269
270#[doc(alias = "FD_ISSET")]
272#[cfg(not(any(windows, target_os = "wasi")))]
273pub struct FdSetIter<'a> {
274 current: RawFd,
275 fds: &'a [FdSetElement],
276}
277
278#[doc(alias = "FD_ISSET")]
280#[cfg(any(windows, target_os = "wasi"))]
281pub struct FdSetIter<'a> {
282 current: usize,
283 fds: &'a [FdSetElement],
284}
285
286impl<'a> FdSetIter<'a> {
287 pub fn new(fds: &'a [FdSetElement]) -> Self {
289 Self { current: 0, fds }
290 }
291}
292
293#[cfg(not(any(windows, target_os = "wasi")))]
294impl<'a> Iterator for FdSetIter<'a> {
295 type Item = RawFd;
296
297 fn next(&mut self) -> Option<Self::Item> {
298 if let Some(element) = self.fds.get(self.current as usize / BITS) {
299 let shifted = element.0 >> ((self.current as usize % BITS) as u32);
301 if shifted != 0 {
302 let fd = self.current + shifted.trailing_zeros() as RawFd;
303 self.current = fd + 1;
304 return Some(fd);
305 }
306
307 if let Some(index) = self.fds[(self.current as usize / BITS) + 1..]
309 .iter()
310 .position(|element| element.0 != 0)
311 {
312 let index = index + (self.current as usize / BITS) + 1;
313 let element = self.fds[index].0;
314 let fd = (index * BITS) as RawFd + element.trailing_zeros() as RawFd;
315 self.current = fd + 1;
316 return Some(fd);
317 }
318 }
319 None
320 }
321}
322
323#[cfg(any(windows, target_os = "wasi"))]
324impl<'a> Iterator for FdSetIter<'a> {
325 type Item = RawFd;
326
327 fn next(&mut self) -> Option<Self::Item> {
328 let current = self.current;
329
330 let set = unsafe { &*self.fds.as_ptr().cast::<FD_SET>() };
331 let fd_count = set.fd_count;
332 let fd_array = &set.fd_array[..fd_count as usize];
333
334 if current == fd_count as usize {
335 return None;
336 }
337 let fd = fd_array[current as usize];
338 self.current = current + 1;
339 Some(fd as RawFd)
340 }
341}
342
343#[cfg(test)]
344mod tests {
345 use super::*;
346 use core::mem::{align_of, size_of};
347
348 #[test]
349 #[cfg(any(windows, target_os = "wasi"))]
350 fn layouts() {
351 assert_eq!(align_of::<FdSetElement>(), align_of::<FD_SET>());
353
354 assert_eq!(
357 fd_set_num_elements_for_fd_array_raw(
358 memoffset::span_of!(FD_SET, fd_array).len() / size_of::<RawFd>()
359 ) * size_of::<FdSetElement>(),
360 size_of::<FD_SET>()
361 );
362 assert_eq!(
363 fd_set_num_elements_for_fd_array(
364 memoffset::span_of!(FD_SET, fd_array).len() / size_of::<RawFd>()
365 ) * size_of::<FdSetElement>(),
366 size_of::<FD_SET>()
367 );
368
369 assert_eq!(
371 fd_set_num_elements_for_fd_array(0) * size_of::<FdSetElement>(),
372 size_of::<FD_SET>()
373 );
374 }
375
376 #[test]
377 #[cfg(any(bsd, linux_kernel))]
378 fn layouts() {
379 use crate::backend::c;
380
381 assert_eq!(align_of::<FdSetElement>(), align_of::<c::fd_set>());
383
384 assert_eq!(
387 fd_set_num_elements_for_bitvector(c::FD_SETSIZE as RawFd) * size_of::<FdSetElement>(),
388 size_of::<c::fd_set>()
389 );
390 }
391}