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 = timeout.to_timeval()?;
251 &timeout_data
252 }
253 None => null(),
254 };
255
256 #[cfg(apple)]
259 {
260 extern "C" {
261 #[link_name = "select$DARWIN_EXTSN$NOCANCEL"]
262 fn select(
263 nfds: c::c_int,
264 readfds: *mut FdSetElement,
265 writefds: *mut FdSetElement,
266 errorfds: *mut FdSetElement,
267 timeout: *const c::timeval,
268 ) -> c::c_int;
269 }
270
271 ret_c_int(select(nfds, readfds, writefds, exceptfds, timeout_ptr))
272 }
273
274 #[cfg(not(apple))]
276 {
277 ret_c_int(c::select(
278 nfds,
279 readfds.cast(),
280 writefds.cast(),
281 exceptfds.cast(),
282 timeout_ptr as *mut c::timeval,
283 ))
284 }
285}
286
287#[cfg(target_os = "wasi")]
289pub(crate) unsafe fn select(
290 nfds: i32,
291 readfds: Option<&mut [FdSetElement]>,
292 writefds: Option<&mut [FdSetElement]>,
293 exceptfds: Option<&mut [FdSetElement]>,
294 timeout: Option<&Timespec>,
295) -> io::Result<i32> {
296 let len = crate::event::fd_set_num_elements_for_fd_array(nfds as usize);
297
298 let readfds = match readfds {
299 Some(readfds) => {
300 assert!(readfds.len() >= len);
301 readfds.as_mut_ptr()
302 }
303 None => null_mut(),
304 };
305 let writefds = match writefds {
306 Some(writefds) => {
307 assert!(writefds.len() >= len);
308 writefds.as_mut_ptr()
309 }
310 None => null_mut(),
311 };
312 let exceptfds = match exceptfds {
313 Some(exceptfds) => {
314 assert!(exceptfds.len() >= len);
315 exceptfds.as_mut_ptr()
316 }
317 None => null_mut(),
318 };
319
320 let timeout_data;
321 let timeout_ptr = match timeout {
322 Some(timeout) => {
323 timeout_data = timeout.to_timeval()?;
324 &timeout_data
325 }
326 None => null(),
327 };
328
329 ret_c_int(c::select(
330 nfds,
331 readfds.cast(),
332 writefds.cast(),
333 exceptfds.cast(),
334 timeout_ptr as *mut c::timeval,
335 ))
336}
337
338#[cfg(solarish)]
339pub(crate) fn port_create() -> io::Result<OwnedFd> {
340 unsafe { ret_owned_fd(c::port_create()) }
341}
342
343#[cfg(solarish)]
344pub(crate) unsafe fn port_associate(
345 port: BorrowedFd<'_>,
346 source: c::c_int,
347 object: c::uintptr_t,
348 events: c::c_int,
349 user: *mut c::c_void,
350) -> io::Result<()> {
351 ret(c::port_associate(
352 borrowed_fd(port),
353 source,
354 object,
355 events,
356 user,
357 ))
358}
359
360#[cfg(solarish)]
361pub(crate) unsafe fn port_dissociate(
362 port: BorrowedFd<'_>,
363 source: c::c_int,
364 object: c::uintptr_t,
365) -> io::Result<()> {
366 ret(c::port_dissociate(borrowed_fd(port), source, object))
367}
368
369#[cfg(solarish)]
370pub(crate) fn port_get(port: BorrowedFd<'_>, timeout: Option<&Timespec>) -> io::Result<Event> {
371 #[cfg(not(fix_y2038))]
374 let timeout = crate::timespec::option_as_libc_timespec_ptr(timeout);
375
376 #[cfg(fix_y2038)]
379 let converted_timeout;
380 #[cfg(fix_y2038)]
381 let timeout = match timeout {
382 None => null(),
383 Some(timeout) => {
384 converted_timeout = c::timespec {
385 tv_sec: timeout.tv_sec.try_into().map_err(|_| io::Errno::OVERFLOW)?,
386 tv_nsec: timeout.tv_nsec as _,
387 };
388 &converted_timeout
389 }
390 };
391
392 let mut event = MaybeUninit::<c::port_event>::uninit();
393
394 unsafe {
396 ret(c::port_get(
397 borrowed_fd(port),
398 event.as_mut_ptr(),
399 timeout as _,
400 ))?;
401 }
402
403 Ok(Event(unsafe { event.assume_init() }))
405}
406
407#[cfg(solarish)]
408pub(crate) unsafe fn port_getn(
409 port: BorrowedFd<'_>,
410 events: (*mut Event, usize),
411 mut nget: u32,
412 timeout: Option<&Timespec>,
413) -> io::Result<usize> {
414 #[cfg(not(fix_y2038))]
417 let timeout = crate::timespec::option_as_libc_timespec_ptr(timeout);
418
419 #[cfg(fix_y2038)]
422 let converted_timeout;
423 #[cfg(fix_y2038)]
424 let timeout = match timeout {
425 None => null(),
426 Some(timeout) => {
427 converted_timeout = c::timespec {
428 tv_sec: timeout.tv_sec.try_into().map_err(|_| io::Errno::OVERFLOW)?,
429 tv_nsec: timeout.tv_nsec as _,
430 };
431 &converted_timeout
432 }
433 };
434
435 if events.1 == 0 {
438 return Ok(0);
439 }
440
441 ret(c::port_getn(
443 borrowed_fd(port),
444 events.0.cast(),
445 events.1.try_into().unwrap_or(u32::MAX),
446 &mut nget,
447 timeout as _,
448 ))?;
449
450 Ok(nget as usize)
451}
452
453#[cfg(solarish)]
454pub(crate) fn port_getn_query(port: BorrowedFd<'_>) -> io::Result<u32> {
455 let mut nget: u32 = 0;
456
457 unsafe {
459 ret(c::port_getn(
460 borrowed_fd(port),
461 null_mut(),
462 0,
463 &mut nget,
464 null_mut(),
465 ))?;
466 }
467
468 Ok(nget)
469}
470
471#[cfg(solarish)]
472pub(crate) fn port_send(
473 port: BorrowedFd<'_>,
474 events: c::c_int,
475 userdata: *mut c::c_void,
476) -> io::Result<()> {
477 unsafe { ret(c::port_send(borrowed_fd(port), events, userdata)) }
478}
479
480#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
481pub(crate) fn pause() {
482 let r = unsafe { c::pause() };
483 let errno = libc_errno::errno().0;
484 debug_assert_eq!(r, -1);
485 debug_assert_eq!(errno, c::EINTR);
486}
487
488#[inline]
489#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
490pub(crate) fn epoll_create(flags: super::epoll::CreateFlags) -> io::Result<OwnedFd> {
491 unsafe { ret_owned_fd(c::epoll_create1(bitflags_bits!(flags))) }
492}
493
494#[inline]
495#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
496pub(crate) fn epoll_add(
497 epoll: BorrowedFd<'_>,
498 source: BorrowedFd<'_>,
499 event: &crate::event::epoll::Event,
500) -> io::Result<()> {
501 unsafe {
505 ret(c::epoll_ctl(
506 borrowed_fd(epoll),
507 c::EPOLL_CTL_ADD,
508 borrowed_fd(source),
509 as_ptr(event) as *mut c::epoll_event,
511 ))
512 }
513}
514
515#[inline]
516#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
517pub(crate) fn epoll_mod(
518 epoll: BorrowedFd<'_>,
519 source: BorrowedFd<'_>,
520 event: &crate::event::epoll::Event,
521) -> io::Result<()> {
522 unsafe {
523 ret(c::epoll_ctl(
524 borrowed_fd(epoll),
525 c::EPOLL_CTL_MOD,
526 borrowed_fd(source),
527 as_ptr(event) as *mut c::epoll_event,
529 ))
530 }
531}
532
533#[inline]
534#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
535pub(crate) fn epoll_del(epoll: BorrowedFd<'_>, source: BorrowedFd<'_>) -> io::Result<()> {
536 unsafe {
537 ret(c::epoll_ctl(
538 borrowed_fd(epoll),
539 c::EPOLL_CTL_DEL,
540 borrowed_fd(source),
541 null_mut(),
542 ))
543 }
544}
545
546#[inline]
547#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
548pub(crate) unsafe fn epoll_wait(
549 epoll: BorrowedFd<'_>,
550 events: (*mut crate::event::epoll::Event, usize),
551 timeout: Option<&Timespec>,
552) -> io::Result<usize> {
553 #[cfg(all(
556 linux_kernel,
557 feature = "linux_5_11",
558 target_env = "gnu",
559 not(fix_y2038)
560 ))]
561 {
562 weak! {
563 fn epoll_pwait2(
564 c::c_int,
565 *mut c::epoll_event,
566 c::c_int,
567 *const c::timespec,
568 *const c::sigset_t
569 ) -> c::c_int
570 }
571
572 if let Some(epoll_pwait2_func) = epoll_pwait2.get() {
573 return ret_u32(epoll_pwait2_func(
574 borrowed_fd(epoll),
575 events.0.cast::<c::epoll_event>(),
576 events.1.try_into().unwrap_or(i32::MAX),
577 crate::utils::option_as_ptr(timeout).cast(),
578 null(),
579 ))
580 .map(|i| i as usize);
581 }
582 }
583
584 #[cfg(all(linux_kernel, feature = "linux_5_11"))]
586 {
587 syscall! {
588 fn epoll_pwait2(
589 epfd: c::c_int,
590 events: *mut c::epoll_event,
591 maxevents: c::c_int,
592 timeout: *const Timespec,
593 sigmask: *const c::sigset_t
594 ) via SYS_epoll_pwait2 -> c::c_int
595 }
596
597 ret_u32(epoll_pwait2(
598 borrowed_fd(epoll),
599 events.0.cast::<c::epoll_event>(),
600 events.1.try_into().unwrap_or(i32::MAX),
601 crate::utils::option_as_ptr(timeout).cast(),
602 null(),
603 ))
604 .map(|i| i as usize)
605 }
606
607 #[cfg(not(all(linux_kernel, feature = "linux_5_11")))]
609 {
610 let timeout = match timeout {
611 None => -1,
612 Some(timeout) => timeout.as_c_int_millis().ok_or(io::Errno::INVAL)?,
613 };
614
615 ret_u32(c::epoll_wait(
616 borrowed_fd(epoll),
617 events.0.cast::<c::epoll_event>(),
618 events.1.try_into().unwrap_or(i32::MAX),
619 timeout,
620 ))
621 .map(|i| i as usize)
622 }
623}