1use crate::backend::c;
4#[cfg(any(linux_kernel, solarish, target_os = "redox"))]
5use crate::backend::conv::ret;
6use crate::backend::conv::ret_c_int;
7#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
8use crate::backend::conv::ret_u32;
9#[cfg(bsd)]
10use crate::event::kqueue::Event;
11#[cfg(solarish)]
12use crate::event::port::Event;
13#[cfg(any(
14 linux_kernel,
15 target_os = "freebsd",
16 target_os = "illumos",
17 target_os = "espidf"
18))]
19use crate::event::EventfdFlags;
20#[cfg(any(bsd, linux_kernel, target_os = "wasi"))]
21use crate::event::FdSetElement;
22use crate::event::{PollFd, Timespec};
23use crate::io;
24#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
25use crate::utils::as_ptr;
26#[cfg(solarish)]
27use core::mem::MaybeUninit;
28#[cfg(any(
29 bsd,
30 linux_kernel,
31 target_os = "fuchsia",
32 target_os = "haiku",
33 target_os = "hurd",
34 target_os = "netbsd",
35 target_os = "wasi"
36))]
37use core::ptr::null;
38#[cfg(any(bsd, linux_kernel, solarish, target_os = "redox", target_os = "wasi"))]
39use core::ptr::null_mut;
40#[cfg(any(bsd, linux_kernel, solarish, target_os = "redox"))]
41use {crate::backend::conv::borrowed_fd, crate::fd::BorrowedFd};
42#[cfg(any(
43 bsd,
44 linux_kernel,
45 solarish,
46 target_os = "freebsd",
47 target_os = "illumos",
48 target_os = "espidf",
49 target_os = "redox"
50))]
51use {crate::backend::conv::ret_owned_fd, crate::fd::OwnedFd};
52
53#[cfg(any(
54 linux_kernel,
55 target_os = "freebsd",
56 target_os = "illumos",
57 target_os = "espidf"
58))]
59pub(crate) fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result<OwnedFd> {
60 #[cfg(linux_kernel)]
61 unsafe {
62 syscall! {
63 fn eventfd2(
64 initval: c::c_uint,
65 flags: c::c_int
66 ) via SYS_eventfd2 -> c::c_int
67 }
68 ret_owned_fd(eventfd2(initval, bitflags_bits!(flags)))
69 }
70
71 #[cfg(target_os = "freebsd")]
73 unsafe {
74 weakcall! {
75 fn eventfd(
76 initval: c::c_uint,
77 flags: c::c_int
78 ) -> c::c_int
79 }
80 ret_owned_fd(eventfd(initval, bitflags_bits!(flags)))
81 }
82
83 #[cfg(any(target_os = "illumos", target_os = "espidf"))]
84 unsafe {
85 ret_owned_fd(c::eventfd(initval, bitflags_bits!(flags)))
86 }
87}
88
89#[cfg(bsd)]
90pub(crate) fn kqueue() -> io::Result<OwnedFd> {
91 unsafe { ret_owned_fd(c::kqueue()) }
92}
93
94#[cfg(bsd)]
95pub(crate) unsafe fn kevent(
96 kq: BorrowedFd<'_>,
97 changelist: &[Event],
98 eventlist: (*mut Event, usize),
99 timeout: Option<&Timespec>,
100) -> io::Result<c::c_int> {
101 #[cfg(not(fix_y2038))]
104 let timeout = crate::timespec::option_as_libc_timespec_ptr(timeout);
105
106 #[cfg(fix_y2038)]
108 let converted_timeout;
109 #[cfg(fix_y2038)]
110 let timeout = match timeout {
111 None => null(),
112 Some(timeout) => {
113 converted_timeout = c::timespec {
114 tv_sec: timeout.tv_sec.try_into().map_err(|_| io::Errno::OVERFLOW)?,
115 tv_nsec: timeout.tv_nsec as _,
116 };
117 &converted_timeout
118 }
119 };
120
121 ret_c_int(c::kevent(
122 borrowed_fd(kq),
123 changelist.as_ptr().cast(),
124 changelist
125 .len()
126 .try_into()
127 .map_err(|_| io::Errno::OVERFLOW)?,
128 eventlist.0.cast(),
129 eventlist.1.try_into().map_err(|_| io::Errno::OVERFLOW)?,
130 timeout,
131 ))
132}
133
134#[inline]
135pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: Option<&Timespec>) -> io::Result<usize> {
136 let nfds = fds
137 .len()
138 .try_into()
139 .map_err(|_convert_err| io::Errno::INVAL)?;
140
141 #[cfg(any(
143 linux_kernel,
144 freebsdlike,
145 target_os = "fuchsia",
146 target_os = "haiku",
147 target_os = "hurd",
148 target_os = "netbsd"
149 ))]
150 {
151 #[cfg(not(fix_y2038))]
154 let timeout = crate::timespec::option_as_libc_timespec_ptr(timeout);
155
156 #[cfg(fix_y2038)]
159 let converted_timeout;
160 #[cfg(fix_y2038)]
161 let timeout = match timeout {
162 None => null(),
163 Some(timeout) => {
164 converted_timeout = c::timespec {
165 tv_sec: timeout.tv_sec.try_into().map_err(|_| io::Errno::OVERFLOW)?,
166 tv_nsec: timeout.tv_nsec as _,
167 };
168 &converted_timeout
169 }
170 };
171
172 #[cfg(not(target_os = "netbsd"))]
173 {
174 ret_c_int(unsafe { c::ppoll(fds.as_mut_ptr().cast(), nfds, timeout, null()) })
175 .map(|nready| nready as usize)
176 }
177
178 #[cfg(target_os = "netbsd")]
181 {
182 weak! {
183 fn ppoll(
184 *mut c::pollfd,
185 c::nfds_t,
186 *const c::timespec,
187 *const c::sigset_t
188 ) -> c::c_int
189 }
190 if let Some(func) = ppoll.get() {
191 return ret_c_int(unsafe { func(fds.as_mut_ptr().cast(), nfds, timeout, null()) })
192 .map(|nready| nready as usize);
193 }
194 }
195 }
196
197 #[cfg(not(any(
199 linux_kernel,
200 freebsdlike,
201 target_os = "fuchsia",
202 target_os = "haiku",
203 target_os = "hurd"
204 )))]
205 {
206 let timeout = match timeout {
207 None => -1,
208 Some(timeout) => timeout.as_c_int_millis().ok_or(io::Errno::INVAL)?,
209 };
210 ret_c_int(unsafe { c::poll(fds.as_mut_ptr().cast(), nfds, timeout) })
211 .map(|nready| nready as usize)
212 }
213}
214
215#[cfg(any(bsd, linux_kernel))]
216pub(crate) unsafe fn select(
217 nfds: i32,
218 readfds: Option<&mut [FdSetElement]>,
219 writefds: Option<&mut [FdSetElement]>,
220 exceptfds: Option<&mut [FdSetElement]>,
221 timeout: Option<&Timespec>,
222) -> io::Result<i32> {
223 let len = crate::event::fd_set_num_elements_for_bitvector(nfds);
224
225 let readfds = match readfds {
226 Some(readfds) => {
227 assert!(readfds.len() >= len);
228 readfds.as_mut_ptr()
229 }
230 None => null_mut(),
231 };
232 let writefds = match writefds {
233 Some(writefds) => {
234 assert!(writefds.len() >= len);
235 writefds.as_mut_ptr()
236 }
237 None => null_mut(),
238 };
239 let exceptfds = match exceptfds {
240 Some(exceptfds) => {
241 assert!(exceptfds.len() >= len);
242 exceptfds.as_mut_ptr()
243 }
244 None => null_mut(),
245 };
246
247 let timeout_data;
248 let timeout_ptr = match timeout {
249 Some(timeout) => {
250 timeout_data = c::timeval {
252 tv_sec: timeout.tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
253 tv_usec: ((timeout.tv_nsec + 999) / 1000) as _,
254 };
255 &timeout_data
256 }
257 None => null(),
258 };
259
260 #[cfg(apple)]
263 {
264 extern "C" {
265 #[link_name = "select$DARWIN_EXTSN$NOCANCEL"]
266 fn select(
267 nfds: c::c_int,
268 readfds: *mut FdSetElement,
269 writefds: *mut FdSetElement,
270 errorfds: *mut FdSetElement,
271 timeout: *const c::timeval,
272 ) -> c::c_int;
273 }
274
275 ret_c_int(select(nfds, readfds, writefds, exceptfds, timeout_ptr))
276 }
277
278 #[cfg(not(apple))]
280 {
281 ret_c_int(c::select(
282 nfds,
283 readfds.cast(),
284 writefds.cast(),
285 exceptfds.cast(),
286 timeout_ptr as *mut c::timeval,
287 ))
288 }
289}
290
291#[cfg(target_os = "wasi")]
293pub(crate) unsafe fn select(
294 nfds: i32,
295 readfds: Option<&mut [FdSetElement]>,
296 writefds: Option<&mut [FdSetElement]>,
297 exceptfds: Option<&mut [FdSetElement]>,
298 timeout: Option<&Timespec>,
299) -> io::Result<i32> {
300 let len = crate::event::fd_set_num_elements_for_fd_array(nfds as usize);
301
302 let readfds = match readfds {
303 Some(readfds) => {
304 assert!(readfds.len() >= len);
305 readfds.as_mut_ptr()
306 }
307 None => null_mut(),
308 };
309 let writefds = match writefds {
310 Some(writefds) => {
311 assert!(writefds.len() >= len);
312 writefds.as_mut_ptr()
313 }
314 None => null_mut(),
315 };
316 let exceptfds = match exceptfds {
317 Some(exceptfds) => {
318 assert!(exceptfds.len() >= len);
319 exceptfds.as_mut_ptr()
320 }
321 None => null_mut(),
322 };
323
324 let timeout_data;
325 let timeout_ptr = match timeout {
326 Some(timeout) => {
327 timeout_data = c::timeval {
329 tv_sec: timeout.tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
330 tv_usec: ((timeout.tv_nsec + 999) / 1000) as _,
331 };
332 &timeout_data
333 }
334 None => null(),
335 };
336
337 ret_c_int(c::select(
338 nfds,
339 readfds.cast(),
340 writefds.cast(),
341 exceptfds.cast(),
342 timeout_ptr as *mut c::timeval,
343 ))
344}
345
346#[cfg(solarish)]
347pub(crate) fn port_create() -> io::Result<OwnedFd> {
348 unsafe { ret_owned_fd(c::port_create()) }
349}
350
351#[cfg(solarish)]
352pub(crate) unsafe fn port_associate(
353 port: BorrowedFd<'_>,
354 source: c::c_int,
355 object: c::uintptr_t,
356 events: c::c_int,
357 user: *mut c::c_void,
358) -> io::Result<()> {
359 ret(c::port_associate(
360 borrowed_fd(port),
361 source,
362 object,
363 events,
364 user,
365 ))
366}
367
368#[cfg(solarish)]
369pub(crate) unsafe fn port_dissociate(
370 port: BorrowedFd<'_>,
371 source: c::c_int,
372 object: c::uintptr_t,
373) -> io::Result<()> {
374 ret(c::port_dissociate(borrowed_fd(port), source, object))
375}
376
377#[cfg(solarish)]
378pub(crate) fn port_get(port: BorrowedFd<'_>, timeout: Option<&Timespec>) -> io::Result<Event> {
379 #[cfg(not(fix_y2038))]
382 let timeout = crate::timespec::option_as_libc_timespec_ptr(timeout);
383
384 #[cfg(fix_y2038)]
387 let converted_timeout;
388 #[cfg(fix_y2038)]
389 let timeout = match timeout {
390 None => null(),
391 Some(timeout) => {
392 converted_timeout = c::timespec {
393 tv_sec: timeout.tv_sec.try_into().map_err(|_| io::Errno::OVERFLOW)?,
394 tv_nsec: timeout.tv_nsec as _,
395 };
396 &converted_timeout
397 }
398 };
399
400 let mut event = MaybeUninit::<c::port_event>::uninit();
401
402 unsafe {
404 ret(c::port_get(
405 borrowed_fd(port),
406 event.as_mut_ptr(),
407 timeout as _,
408 ))?;
409 }
410
411 Ok(Event(unsafe { event.assume_init() }))
413}
414
415#[cfg(solarish)]
416pub(crate) unsafe fn port_getn(
417 port: BorrowedFd<'_>,
418 events: (*mut Event, usize),
419 mut nget: u32,
420 timeout: Option<&Timespec>,
421) -> io::Result<usize> {
422 #[cfg(not(fix_y2038))]
425 let timeout = crate::timespec::option_as_libc_timespec_ptr(timeout);
426
427 #[cfg(fix_y2038)]
430 let converted_timeout;
431 #[cfg(fix_y2038)]
432 let timeout = match timeout {
433 None => null(),
434 Some(timeout) => {
435 converted_timeout = c::timespec {
436 tv_sec: timeout.tv_sec.try_into().map_err(|_| io::Errno::OVERFLOW)?,
437 tv_nsec: timeout.tv_nsec as _,
438 };
439 &converted_timeout
440 }
441 };
442
443 if events.1 == 0 {
446 return Ok(0);
447 }
448
449 ret(c::port_getn(
451 borrowed_fd(port),
452 events.0.cast(),
453 events.1.try_into().unwrap_or(u32::MAX),
454 &mut nget,
455 timeout as _,
456 ))?;
457
458 Ok(nget as usize)
459}
460
461#[cfg(solarish)]
462pub(crate) fn port_getn_query(port: BorrowedFd<'_>) -> io::Result<u32> {
463 let mut nget: u32 = 0;
464
465 unsafe {
467 ret(c::port_getn(
468 borrowed_fd(port),
469 null_mut(),
470 0,
471 &mut nget,
472 null_mut(),
473 ))?;
474 }
475
476 Ok(nget)
477}
478
479#[cfg(solarish)]
480pub(crate) fn port_send(
481 port: BorrowedFd<'_>,
482 events: c::c_int,
483 userdata: *mut c::c_void,
484) -> io::Result<()> {
485 unsafe { ret(c::port_send(borrowed_fd(port), events, userdata)) }
486}
487
488#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
489pub(crate) fn pause() {
490 let r = unsafe { c::pause() };
491 let errno = libc_errno::errno().0;
492 debug_assert_eq!(r, -1);
493 debug_assert_eq!(errno, c::EINTR);
494}
495
496#[inline]
497#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
498pub(crate) fn epoll_create(flags: super::epoll::CreateFlags) -> io::Result<OwnedFd> {
499 unsafe { ret_owned_fd(c::epoll_create1(bitflags_bits!(flags))) }
500}
501
502#[inline]
503#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
504pub(crate) fn epoll_add(
505 epoll: BorrowedFd<'_>,
506 source: BorrowedFd<'_>,
507 event: &crate::event::epoll::Event,
508) -> io::Result<()> {
509 unsafe {
513 ret(c::epoll_ctl(
514 borrowed_fd(epoll),
515 c::EPOLL_CTL_ADD,
516 borrowed_fd(source),
517 as_ptr(event) as *mut c::epoll_event,
519 ))
520 }
521}
522
523#[inline]
524#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
525pub(crate) fn epoll_mod(
526 epoll: BorrowedFd<'_>,
527 source: BorrowedFd<'_>,
528 event: &crate::event::epoll::Event,
529) -> io::Result<()> {
530 unsafe {
531 ret(c::epoll_ctl(
532 borrowed_fd(epoll),
533 c::EPOLL_CTL_MOD,
534 borrowed_fd(source),
535 as_ptr(event) as *mut c::epoll_event,
537 ))
538 }
539}
540
541#[inline]
542#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
543pub(crate) fn epoll_del(epoll: BorrowedFd<'_>, source: BorrowedFd<'_>) -> io::Result<()> {
544 unsafe {
545 ret(c::epoll_ctl(
546 borrowed_fd(epoll),
547 c::EPOLL_CTL_DEL,
548 borrowed_fd(source),
549 null_mut(),
550 ))
551 }
552}
553
554#[inline]
555#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
556pub(crate) unsafe fn epoll_wait(
557 epoll: BorrowedFd<'_>,
558 events: (*mut crate::event::epoll::Event, usize),
559 timeout: Option<&Timespec>,
560) -> io::Result<usize> {
561 #[cfg(all(
564 linux_kernel,
565 feature = "linux_5_11",
566 target_env = "gnu",
567 not(fix_y2038)
568 ))]
569 {
570 weak! {
571 fn epoll_pwait2(
572 c::c_int,
573 *mut c::epoll_event,
574 c::c_int,
575 *const c::timespec,
576 *const c::sigset_t
577 ) -> c::c_int
578 }
579
580 if let Some(epoll_pwait2_func) = epoll_pwait2.get() {
581 return ret_u32(epoll_pwait2_func(
582 borrowed_fd(epoll),
583 events.0.cast::<c::epoll_event>(),
584 events.1.try_into().unwrap_or(i32::MAX),
585 crate::utils::option_as_ptr(timeout).cast(),
586 null(),
587 ))
588 .map(|i| i as usize);
589 }
590 }
591
592 #[cfg(all(linux_kernel, feature = "linux_5_11"))]
594 {
595 syscall! {
596 fn epoll_pwait2(
597 epfd: c::c_int,
598 events: *mut c::epoll_event,
599 maxevents: c::c_int,
600 timeout: *const Timespec,
601 sigmask: *const c::sigset_t
602 ) via SYS_epoll_pwait2 -> c::c_int
603 }
604
605 ret_u32(epoll_pwait2(
606 borrowed_fd(epoll),
607 events.0.cast::<c::epoll_event>(),
608 events.1.try_into().unwrap_or(i32::MAX),
609 crate::utils::option_as_ptr(timeout).cast(),
610 null(),
611 ))
612 .map(|i| i as usize)
613 }
614
615 #[cfg(not(all(linux_kernel, feature = "linux_5_11")))]
617 {
618 let timeout = match timeout {
619 None => -1,
620 Some(timeout) => timeout.as_c_int_millis().ok_or(io::Errno::INVAL)?,
621 };
622
623 ret_u32(c::epoll_wait(
624 borrowed_fd(epoll),
625 events.0.cast::<c::epoll_event>(),
626 events.1.try_into().unwrap_or(i32::MAX),
627 timeout,
628 ))
629 .map(|i| i as usize)
630 }
631}