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(feature = "alloc")]
8#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
9use crate::backend::conv::ret_u32;
10#[cfg(solarish)]
11use crate::event::port::Event;
12#[cfg(any(
13 linux_kernel,
14 target_os = "freebsd",
15 target_os = "illumos",
16 target_os = "espidf"
17))]
18use crate::event::EventfdFlags;
19#[cfg(any(bsd, linux_kernel, target_os = "wasi"))]
20use crate::event::FdSetElement;
21use crate::event::PollFd;
22use crate::io;
23#[cfg(solarish)]
24use crate::utils::as_mut_ptr;
25#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
26use crate::utils::as_ptr;
27#[cfg(any(
28 all(feature = "alloc", bsd),
29 solarish,
30 all(feature = "alloc", any(linux_kernel, target_os = "redox")),
31))]
32use core::mem::MaybeUninit;
33#[cfg(any(bsd, linux_kernel, target_os = "wasi"))]
34use core::ptr::null;
35#[cfg(any(bsd, linux_kernel, solarish, target_os = "redox", target_os = "wasi"))]
36use core::ptr::null_mut;
37#[cfg(any(
38 linux_kernel,
39 solarish,
40 target_os = "redox",
41 all(feature = "alloc", bsd)
42))]
43use {crate::backend::conv::borrowed_fd, crate::fd::BorrowedFd};
44#[cfg(any(
45 linux_kernel,
46 solarish,
47 target_os = "freebsd",
48 target_os = "illumos",
49 target_os = "espidf",
50 target_os = "redox",
51 all(feature = "alloc", bsd)
52))]
53use {crate::backend::conv::ret_owned_fd, crate::fd::OwnedFd};
54#[cfg(all(feature = "alloc", bsd))]
55use {crate::event::kqueue::Event, crate::utils::as_ptr};
56
57#[cfg(any(
58 linux_kernel,
59 target_os = "freebsd",
60 target_os = "illumos",
61 target_os = "espidf"
62))]
63pub(crate) fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result<OwnedFd> {
64 #[cfg(linux_kernel)]
65 unsafe {
66 syscall! {
67 fn eventfd2(
68 initval: c::c_uint,
69 flags: c::c_int
70 ) via SYS_eventfd2 -> c::c_int
71 }
72 ret_owned_fd(eventfd2(initval, bitflags_bits!(flags)))
73 }
74
75 #[cfg(target_os = "freebsd")]
77 unsafe {
78 weakcall! {
79 fn eventfd(
80 initval: c::c_uint,
81 flags: c::c_int
82 ) -> c::c_int
83 }
84 ret_owned_fd(eventfd(initval, bitflags_bits!(flags)))
85 }
86
87 #[cfg(any(target_os = "illumos", target_os = "espidf"))]
88 unsafe {
89 ret_owned_fd(c::eventfd(initval, bitflags_bits!(flags)))
90 }
91}
92
93#[cfg(all(feature = "alloc", bsd))]
94pub(crate) fn kqueue() -> io::Result<OwnedFd> {
95 unsafe { ret_owned_fd(c::kqueue()) }
96}
97
98#[cfg(all(feature = "alloc", bsd))]
99pub(crate) unsafe fn kevent(
100 kq: BorrowedFd<'_>,
101 changelist: &[Event],
102 eventlist: &mut [MaybeUninit<Event>],
103 timeout: Option<&c::timespec>,
104) -> io::Result<c::c_int> {
105 ret_c_int(c::kevent(
106 borrowed_fd(kq),
107 changelist.as_ptr().cast(),
108 changelist
109 .len()
110 .try_into()
111 .map_err(|_| io::Errno::OVERFLOW)?,
112 eventlist.as_mut_ptr().cast(),
113 eventlist
114 .len()
115 .try_into()
116 .map_err(|_| io::Errno::OVERFLOW)?,
117 timeout.map_or(null(), as_ptr),
118 ))
119}
120
121#[inline]
122pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: c::c_int) -> io::Result<usize> {
123 let nfds = fds
124 .len()
125 .try_into()
126 .map_err(|_convert_err| io::Errno::INVAL)?;
127
128 ret_c_int(unsafe { c::poll(fds.as_mut_ptr().cast(), nfds, timeout) })
129 .map(|nready| nready as usize)
130}
131
132#[cfg(any(bsd, linux_kernel))]
133pub(crate) unsafe fn select(
134 nfds: i32,
135 readfds: Option<&mut [FdSetElement]>,
136 writefds: Option<&mut [FdSetElement]>,
137 exceptfds: Option<&mut [FdSetElement]>,
138 timeout: Option<&crate::timespec::Timespec>,
139) -> io::Result<i32> {
140 let len = crate::event::fd_set_num_elements_for_bitvector(nfds);
141
142 let readfds = match readfds {
143 Some(readfds) => {
144 assert!(readfds.len() >= len);
145 readfds.as_mut_ptr()
146 }
147 None => null_mut(),
148 };
149 let writefds = match writefds {
150 Some(writefds) => {
151 assert!(writefds.len() >= len);
152 writefds.as_mut_ptr()
153 }
154 None => null_mut(),
155 };
156 let exceptfds = match exceptfds {
157 Some(exceptfds) => {
158 assert!(exceptfds.len() >= len);
159 exceptfds.as_mut_ptr()
160 }
161 None => null_mut(),
162 };
163
164 let timeout_data;
165 let timeout_ptr = match timeout {
166 Some(timeout) => {
167 timeout_data = c::timeval {
169 tv_sec: timeout.tv_sec.try_into().map_err(|_| io::Errno::OVERFLOW)?,
170 tv_usec: ((timeout.tv_nsec + 999) / 1000) as _,
171 };
172 &timeout_data
173 }
174 None => null(),
175 };
176
177 #[cfg(apple)]
180 {
181 extern "C" {
182 #[link_name = "select$DARWIN_EXTSN$NOCANCEL"]
183 fn select(
184 nfds: c::c_int,
185 readfds: *mut FdSetElement,
186 writefds: *mut FdSetElement,
187 errorfds: *mut FdSetElement,
188 timeout: *const c::timeval,
189 ) -> c::c_int;
190 }
191
192 ret_c_int(select(nfds, readfds, writefds, exceptfds, timeout_ptr))
193 }
194
195 #[cfg(not(apple))]
197 {
198 ret_c_int(c::select(
199 nfds,
200 readfds.cast(),
201 writefds.cast(),
202 exceptfds.cast(),
203 timeout_ptr as *mut c::timeval,
204 ))
205 }
206}
207
208#[cfg(target_os = "wasi")]
210pub(crate) unsafe fn select(
211 nfds: i32,
212 readfds: Option<&mut [FdSetElement]>,
213 writefds: Option<&mut [FdSetElement]>,
214 exceptfds: Option<&mut [FdSetElement]>,
215 timeout: Option<&crate::timespec::Timespec>,
216) -> io::Result<i32> {
217 let len = crate::event::fd_set_num_elements_for_fd_array(nfds as usize);
218
219 let readfds = match readfds {
220 Some(readfds) => {
221 assert!(readfds.len() >= len);
222 readfds.as_mut_ptr()
223 }
224 None => null_mut(),
225 };
226 let writefds = match writefds {
227 Some(writefds) => {
228 assert!(writefds.len() >= len);
229 writefds.as_mut_ptr()
230 }
231 None => null_mut(),
232 };
233 let exceptfds = match exceptfds {
234 Some(exceptfds) => {
235 assert!(exceptfds.len() >= len);
236 exceptfds.as_mut_ptr()
237 }
238 None => null_mut(),
239 };
240
241 let timeout_data;
242 let timeout_ptr = match timeout {
243 Some(timeout) => {
244 timeout_data = c::timeval {
246 tv_sec: timeout.tv_sec.try_into().map_err(|_| io::Errno::OVERFLOW)?,
247 tv_usec: ((timeout.tv_nsec + 999) / 1000) as _,
248 };
249 &timeout_data
250 }
251 None => null(),
252 };
253
254 ret_c_int(c::select(
255 nfds,
256 readfds.cast(),
257 writefds.cast(),
258 exceptfds.cast(),
259 timeout_ptr as *mut c::timeval,
260 ))
261}
262
263#[cfg(solarish)]
264pub(crate) fn port_create() -> io::Result<OwnedFd> {
265 unsafe { ret_owned_fd(c::port_create()) }
266}
267
268#[cfg(solarish)]
269pub(crate) unsafe fn port_associate(
270 port: BorrowedFd<'_>,
271 source: c::c_int,
272 object: c::uintptr_t,
273 events: c::c_int,
274 user: *mut c::c_void,
275) -> io::Result<()> {
276 ret(c::port_associate(
277 borrowed_fd(port),
278 source,
279 object,
280 events,
281 user,
282 ))
283}
284
285#[cfg(solarish)]
286pub(crate) unsafe fn port_dissociate(
287 port: BorrowedFd<'_>,
288 source: c::c_int,
289 object: c::uintptr_t,
290) -> io::Result<()> {
291 ret(c::port_dissociate(borrowed_fd(port), source, object))
292}
293
294#[cfg(solarish)]
295pub(crate) fn port_get(
296 port: BorrowedFd<'_>,
297 timeout: Option<&mut c::timespec>,
298) -> io::Result<Event> {
299 let mut event = MaybeUninit::<c::port_event>::uninit();
300 let timeout = timeout.map_or(null_mut(), as_mut_ptr);
301
302 unsafe {
303 ret(c::port_get(borrowed_fd(port), event.as_mut_ptr(), timeout))?;
304 }
305
306 Ok(Event(unsafe { event.assume_init() }))
308}
309
310#[cfg(all(feature = "alloc", solarish))]
311pub(crate) fn port_getn(
312 port: BorrowedFd<'_>,
313 timeout: Option<&mut c::timespec>,
314 events: &mut Vec<Event>,
315 mut nget: u32,
316) -> io::Result<()> {
317 if events.capacity() == 0 {
321 return Ok(());
322 }
323
324 let timeout = timeout.map_or(null_mut(), as_mut_ptr);
325 unsafe {
326 ret(c::port_getn(
327 borrowed_fd(port),
328 events.as_mut_ptr().cast(),
329 events.capacity().try_into().unwrap(),
330 &mut nget,
331 timeout,
332 ))?;
333 }
334
335 unsafe {
337 events.set_len(nget.try_into().unwrap());
338 }
339
340 Ok(())
341}
342
343#[cfg(solarish)]
344pub(crate) fn port_getn_query(port: BorrowedFd<'_>) -> io::Result<u32> {
345 let mut nget: u32 = 0;
346
347 unsafe {
349 ret(c::port_getn(
350 borrowed_fd(port),
351 null_mut(),
352 0,
353 &mut nget,
354 null_mut(),
355 ))?;
356 }
357
358 Ok(nget)
359}
360
361#[cfg(solarish)]
362pub(crate) fn port_send(
363 port: BorrowedFd<'_>,
364 events: c::c_int,
365 userdata: *mut c::c_void,
366) -> io::Result<()> {
367 unsafe { ret(c::port_send(borrowed_fd(port), events, userdata)) }
368}
369
370#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
371pub(crate) fn pause() {
372 let r = unsafe { c::pause() };
373 let errno = libc_errno::errno().0;
374 debug_assert_eq!(r, -1);
375 debug_assert_eq!(errno, c::EINTR);
376}
377
378#[inline]
379#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
380pub(crate) fn epoll_create(flags: super::epoll::CreateFlags) -> io::Result<OwnedFd> {
381 unsafe { ret_owned_fd(c::epoll_create1(bitflags_bits!(flags))) }
382}
383
384#[inline]
385#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
386pub(crate) fn epoll_add(
387 epoll: BorrowedFd<'_>,
388 source: BorrowedFd<'_>,
389 event: &crate::event::epoll::Event,
390) -> io::Result<()> {
391 unsafe {
395 ret(c::epoll_ctl(
396 borrowed_fd(epoll),
397 c::EPOLL_CTL_ADD,
398 borrowed_fd(source),
399 as_ptr(event) as *mut c::epoll_event,
401 ))
402 }
403}
404
405#[inline]
406#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
407pub(crate) fn epoll_mod(
408 epoll: BorrowedFd<'_>,
409 source: BorrowedFd<'_>,
410 event: &crate::event::epoll::Event,
411) -> io::Result<()> {
412 unsafe {
413 ret(c::epoll_ctl(
414 borrowed_fd(epoll),
415 c::EPOLL_CTL_MOD,
416 borrowed_fd(source),
417 as_ptr(event) as *mut c::epoll_event,
419 ))
420 }
421}
422
423#[inline]
424#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
425pub(crate) fn epoll_del(epoll: BorrowedFd<'_>, source: BorrowedFd<'_>) -> io::Result<()> {
426 unsafe {
427 ret(c::epoll_ctl(
428 borrowed_fd(epoll),
429 c::EPOLL_CTL_DEL,
430 borrowed_fd(source),
431 null_mut(),
432 ))
433 }
434}
435
436#[inline]
437#[cfg(feature = "alloc")]
438#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
439pub(crate) fn epoll_wait(
440 epoll: BorrowedFd<'_>,
441 events: &mut [MaybeUninit<crate::event::epoll::Event>],
442 timeout: c::c_int,
443) -> io::Result<usize> {
444 unsafe {
445 ret_u32(c::epoll_wait(
446 borrowed_fd(epoll),
447 events.as_mut_ptr().cast::<c::epoll_event>(),
448 events.len().try_into().unwrap_or(i32::MAX),
449 timeout,
450 ))
451 .map(|i| i.try_into().unwrap_or(usize::MAX))
452 }
453}