1 use crate::{Interest, Token};
2 use std::mem::{self, MaybeUninit};
3 use std::ops::{Deref, DerefMut};
4 use std::os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd};
5 #[cfg(debug_assertions)]
6 use std::sync::atomic::{AtomicUsize, Ordering};
7 use std::time::Duration;
8 use std::{cmp, io, ptr, slice};
9
10 /// Unique id for use as `SelectorId`.
11 #[cfg(debug_assertions)]
12 static NEXT_ID: AtomicUsize = AtomicUsize::new(1);
13
14 // Type of the `nchanges` and `nevents` parameters in the `kevent` function.
15 #[cfg(not(target_os = "netbsd"))]
16 type Count = libc::c_int;
17 #[cfg(target_os = "netbsd")]
18 type Count = libc::size_t;
19
20 // Type of the `filter` field in the `kevent` structure.
21 #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
22 type Filter = libc::c_short;
23 #[cfg(any(
24 target_os = "ios",
25 target_os = "macos",
26 target_os = "tvos",
27 target_os = "visionos",
28 target_os = "watchos"
29 ))]
30 type Filter = i16;
31 #[cfg(target_os = "netbsd")]
32 type Filter = u32;
33
34 // Type of the `flags` field in the `kevent` structure.
35 #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
36 type Flags = libc::c_ushort;
37 #[cfg(any(
38 target_os = "ios",
39 target_os = "macos",
40 target_os = "tvos",
41 target_os = "visionos",
42 target_os = "watchos"
43 ))]
44 type Flags = u16;
45 #[cfg(target_os = "netbsd")]
46 type Flags = u32;
47
48 // Type of the `udata` field in the `kevent` structure.
49 #[cfg(not(target_os = "netbsd"))]
50 type UData = *mut libc::c_void;
51 #[cfg(target_os = "netbsd")]
52 type UData = libc::intptr_t;
53
54 macro_rules! kevent {
55 ($id: expr, $filter: expr, $flags: expr, $data: expr) => {
56 libc::kevent {
57 ident: $id as libc::uintptr_t,
58 filter: $filter as Filter,
59 flags: $flags,
60 udata: $data as UData,
61 ..unsafe { mem::zeroed() }
62 }
63 };
64 }
65
66 #[derive(Debug)]
67 pub struct Selector {
68 #[cfg(debug_assertions)]
69 id: usize,
70 kq: OwnedFd,
71 }
72
73 impl Selector {
new() -> io::Result<Selector>74 pub fn new() -> io::Result<Selector> {
75 // SAFETY: `kqueue(2)` ensures the fd is valid.
76 let kq = unsafe { OwnedFd::from_raw_fd(syscall!(kqueue())?) };
77 syscall!(fcntl(kq.as_raw_fd(), libc::F_SETFD, libc::FD_CLOEXEC))?;
78 Ok(Selector {
79 #[cfg(debug_assertions)]
80 id: NEXT_ID.fetch_add(1, Ordering::Relaxed),
81 kq,
82 })
83 }
84
try_clone(&self) -> io::Result<Selector>85 pub fn try_clone(&self) -> io::Result<Selector> {
86 self.kq.try_clone().map(|kq| Selector {
87 // It's the same selector, so we use the same id.
88 #[cfg(debug_assertions)]
89 id: self.id,
90 kq,
91 })
92 }
93
select(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<()>94 pub fn select(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<()> {
95 let timeout = timeout.map(|to| libc::timespec {
96 tv_sec: cmp::min(to.as_secs(), libc::time_t::MAX as u64) as libc::time_t,
97 // `Duration::subsec_nanos` is guaranteed to be less than one
98 // billion (the number of nanoseconds in a second), making the
99 // cast to i32 safe. The cast itself is needed for platforms
100 // where C's long is only 32 bits.
101 tv_nsec: libc::c_long::from(to.subsec_nanos() as i32),
102 });
103 let timeout = timeout
104 .as_ref()
105 .map(|s| s as *const _)
106 .unwrap_or(ptr::null_mut());
107
108 events.clear();
109 syscall!(kevent(
110 self.kq.as_raw_fd(),
111 ptr::null(),
112 0,
113 events.as_mut_ptr(),
114 events.capacity() as Count,
115 timeout,
116 ))
117 .map(|n_events| {
118 // This is safe because `kevent` ensures that `n_events` are
119 // assigned.
120 unsafe { events.set_len(n_events as usize) };
121 })
122 }
123
register(&self, fd: RawFd, token: Token, interests: Interest) -> io::Result<()>124 pub fn register(&self, fd: RawFd, token: Token, interests: Interest) -> io::Result<()> {
125 let flags = libc::EV_CLEAR | libc::EV_RECEIPT | libc::EV_ADD;
126 // At most we need two changes, but maybe we only need 1.
127 let mut changes: [MaybeUninit<libc::kevent>; 2] =
128 [MaybeUninit::uninit(), MaybeUninit::uninit()];
129 let mut n_changes = 0;
130
131 if interests.is_writable() {
132 let kevent = kevent!(fd, libc::EVFILT_WRITE, flags, token.0);
133 changes[n_changes] = MaybeUninit::new(kevent);
134 n_changes += 1;
135 }
136
137 if interests.is_readable() {
138 let kevent = kevent!(fd, libc::EVFILT_READ, flags, token.0);
139 changes[n_changes] = MaybeUninit::new(kevent);
140 n_changes += 1;
141 }
142
143 // Older versions of macOS (OS X 10.11 and 10.10 have been witnessed)
144 // can return EPIPE when registering a pipe file descriptor where the
145 // other end has already disappeared. For example code that creates a
146 // pipe, closes a file descriptor, and then registers the other end will
147 // see an EPIPE returned from `register`.
148 //
149 // It also turns out that kevent will still report events on the file
150 // descriptor, telling us that it's readable/hup at least after we've
151 // done this registration. As a result we just ignore `EPIPE` here
152 // instead of propagating it.
153 //
154 // More info can be found at tokio-rs/mio#582.
155 let changes = unsafe {
156 // This is safe because we ensure that at least `n_changes` are in
157 // the array.
158 slice::from_raw_parts_mut(changes[0].as_mut_ptr(), n_changes)
159 };
160 kevent_register(self.kq.as_raw_fd(), changes, &[libc::EPIPE as i64])
161 }
162
reregister(&self, fd: RawFd, token: Token, interests: Interest) -> io::Result<()>163 pub fn reregister(&self, fd: RawFd, token: Token, interests: Interest) -> io::Result<()> {
164 let flags = libc::EV_CLEAR | libc::EV_RECEIPT;
165 let write_flags = if interests.is_writable() {
166 flags | libc::EV_ADD
167 } else {
168 flags | libc::EV_DELETE
169 };
170 let read_flags = if interests.is_readable() {
171 flags | libc::EV_ADD
172 } else {
173 flags | libc::EV_DELETE
174 };
175
176 let mut changes: [libc::kevent; 2] = [
177 kevent!(fd, libc::EVFILT_WRITE, write_flags, token.0),
178 kevent!(fd, libc::EVFILT_READ, read_flags, token.0),
179 ];
180
181 // Since there is no way to check with which interests the fd was
182 // registered we modify both readable and write, adding it when required
183 // and removing it otherwise, ignoring the ENOENT error when it comes
184 // up. The ENOENT error informs us that a filter we're trying to remove
185 // wasn't there in first place, but we don't really care since our goal
186 // is accomplished.
187 //
188 // For the explanation of ignoring `EPIPE` see `register`.
189 kevent_register(
190 self.kq.as_raw_fd(),
191 &mut changes,
192 &[libc::ENOENT as i64, libc::EPIPE as i64],
193 )
194 }
195
deregister(&self, fd: RawFd) -> io::Result<()>196 pub fn deregister(&self, fd: RawFd) -> io::Result<()> {
197 let flags = libc::EV_DELETE | libc::EV_RECEIPT;
198 let mut changes: [libc::kevent; 2] = [
199 kevent!(fd, libc::EVFILT_WRITE, flags, 0),
200 kevent!(fd, libc::EVFILT_READ, flags, 0),
201 ];
202
203 // Since there is no way to check with which interests the fd was
204 // registered we remove both filters (readable and writeable) and ignore
205 // the ENOENT error when it comes up. The ENOENT error informs us that
206 // the filter wasn't there in first place, but we don't really care
207 // about that since our goal is to remove it.
208 kevent_register(self.kq.as_raw_fd(), &mut changes, &[libc::ENOENT as i64])
209 }
210
211 // Used by `Waker`.
212 #[cfg(any(
213 target_os = "freebsd",
214 target_os = "ios",
215 target_os = "macos",
216 target_os = "tvos",
217 target_os = "visionos",
218 target_os = "watchos"
219 ))]
setup_waker(&self, token: Token) -> io::Result<()>220 pub fn setup_waker(&self, token: Token) -> io::Result<()> {
221 // First attempt to accept user space notifications.
222 let mut kevent = kevent!(
223 0,
224 libc::EVFILT_USER,
225 libc::EV_ADD | libc::EV_CLEAR | libc::EV_RECEIPT,
226 token.0
227 );
228
229 let kq = self.kq.as_raw_fd();
230 syscall!(kevent(kq, &kevent, 1, &mut kevent, 1, ptr::null())).and_then(|_| {
231 if (kevent.flags & libc::EV_ERROR) != 0 && kevent.data != 0 {
232 Err(io::Error::from_raw_os_error(kevent.data as i32))
233 } else {
234 Ok(())
235 }
236 })
237 }
238
239 // Used by `Waker`.
240 #[cfg(any(
241 target_os = "freebsd",
242 target_os = "ios",
243 target_os = "macos",
244 target_os = "tvos",
245 target_os = "visionos",
246 target_os = "watchos"
247 ))]
wake(&self, token: Token) -> io::Result<()>248 pub fn wake(&self, token: Token) -> io::Result<()> {
249 let mut kevent = kevent!(
250 0,
251 libc::EVFILT_USER,
252 libc::EV_ADD | libc::EV_RECEIPT,
253 token.0
254 );
255 kevent.fflags = libc::NOTE_TRIGGER;
256
257 let kq = self.kq.as_raw_fd();
258 syscall!(kevent(kq, &kevent, 1, &mut kevent, 1, ptr::null())).and_then(|_| {
259 if (kevent.flags & libc::EV_ERROR) != 0 && kevent.data != 0 {
260 Err(io::Error::from_raw_os_error(kevent.data as i32))
261 } else {
262 Ok(())
263 }
264 })
265 }
266 }
267
268 /// Register `changes` with `kq`ueue.
kevent_register( kq: RawFd, changes: &mut [libc::kevent], ignored_errors: &[i64], ) -> io::Result<()>269 fn kevent_register(
270 kq: RawFd,
271 changes: &mut [libc::kevent],
272 ignored_errors: &[i64],
273 ) -> io::Result<()> {
274 syscall!(kevent(
275 kq,
276 changes.as_ptr(),
277 changes.len() as Count,
278 changes.as_mut_ptr(),
279 changes.len() as Count,
280 ptr::null(),
281 ))
282 .map(|_| ())
283 .or_else(|err| {
284 // According to the manual page of FreeBSD: "When kevent() call fails
285 // with EINTR error, all changes in the changelist have been applied",
286 // so we can safely ignore it.
287 if err.raw_os_error() == Some(libc::EINTR) {
288 Ok(())
289 } else {
290 Err(err)
291 }
292 })
293 .and_then(|()| check_errors(changes, ignored_errors))
294 }
295
296 /// Check all events for possible errors, it returns the first error found.
check_errors(events: &[libc::kevent], ignored_errors: &[i64]) -> io::Result<()>297 fn check_errors(events: &[libc::kevent], ignored_errors: &[i64]) -> io::Result<()> {
298 for event in events {
299 // We can't use references to packed structures (in checking the ignored
300 // errors), so we need copy the data out before use.
301 let data = event.data as _;
302 // Check for the error flag, the actual error will be in the `data`
303 // field.
304 if (event.flags & libc::EV_ERROR != 0) && data != 0 && !ignored_errors.contains(&data) {
305 return Err(io::Error::from_raw_os_error(data as i32));
306 }
307 }
308 Ok(())
309 }
310
311 cfg_io_source! {
312 #[cfg(debug_assertions)]
313 impl Selector {
314 pub fn id(&self) -> usize {
315 self.id
316 }
317 }
318 }
319
320 impl AsRawFd for Selector {
as_raw_fd(&self) -> RawFd321 fn as_raw_fd(&self) -> RawFd {
322 self.kq.as_raw_fd()
323 }
324 }
325
326 pub type Event = libc::kevent;
327 pub struct Events(Vec<libc::kevent>);
328
329 impl Events {
with_capacity(capacity: usize) -> Events330 pub fn with_capacity(capacity: usize) -> Events {
331 Events(Vec::with_capacity(capacity))
332 }
333 }
334
335 impl Deref for Events {
336 type Target = Vec<libc::kevent>;
337
deref(&self) -> &Self::Target338 fn deref(&self) -> &Self::Target {
339 &self.0
340 }
341 }
342
343 impl DerefMut for Events {
deref_mut(&mut self) -> &mut Self::Target344 fn deref_mut(&mut self) -> &mut Self::Target {
345 &mut self.0
346 }
347 }
348
349 // `Events` cannot derive `Send` or `Sync` because of the
350 // `udata: *mut ::c_void` field in `libc::kevent`. However, `Events`'s public
351 // API treats the `udata` field as a `uintptr_t` which is `Send`. `Sync` is
352 // safe because with a `events: &Events` value, the only access to the `udata`
353 // field is through `fn token(event: &Event)` which cannot mutate the field.
354 unsafe impl Send for Events {}
355 unsafe impl Sync for Events {}
356
357 pub mod event {
358 use std::fmt;
359
360 use crate::sys::Event;
361 use crate::Token;
362
363 use super::{Filter, Flags};
364
token(event: &Event) -> Token365 pub fn token(event: &Event) -> Token {
366 Token(event.udata as usize)
367 }
368
is_readable(event: &Event) -> bool369 pub fn is_readable(event: &Event) -> bool {
370 event.filter == libc::EVFILT_READ || {
371 #[cfg(any(
372 target_os = "freebsd",
373 target_os = "ios",
374 target_os = "macos",
375 target_os = "tvos",
376 target_os = "visionos",
377 target_os = "watchos"
378 ))]
379 // Used by the `Awakener`. On platforms that use `eventfd` or a unix
380 // pipe it will emit a readable event so we'll fake that here as
381 // well.
382 {
383 event.filter == libc::EVFILT_USER
384 }
385 #[cfg(not(any(
386 target_os = "freebsd",
387 target_os = "ios",
388 target_os = "macos",
389 target_os = "tvos",
390 target_os = "visionos",
391 target_os = "watchos"
392 )))]
393 {
394 false
395 }
396 }
397 }
398
is_writable(event: &Event) -> bool399 pub fn is_writable(event: &Event) -> bool {
400 event.filter == libc::EVFILT_WRITE
401 }
402
is_error(event: &Event) -> bool403 pub fn is_error(event: &Event) -> bool {
404 (event.flags & libc::EV_ERROR) != 0 ||
405 // When the read end of the socket is closed, EV_EOF is set on
406 // flags, and fflags contains the error if there is one.
407 (event.flags & libc::EV_EOF) != 0 && event.fflags != 0
408 }
409
is_read_closed(event: &Event) -> bool410 pub fn is_read_closed(event: &Event) -> bool {
411 event.filter == libc::EVFILT_READ && event.flags & libc::EV_EOF != 0
412 }
413
is_write_closed(event: &Event) -> bool414 pub fn is_write_closed(event: &Event) -> bool {
415 event.filter == libc::EVFILT_WRITE && event.flags & libc::EV_EOF != 0
416 }
417
is_priority(_: &Event) -> bool418 pub fn is_priority(_: &Event) -> bool {
419 // kqueue doesn't have priority indicators.
420 false
421 }
422
423 #[allow(unused_variables)] // `event` is not used on some platforms.
is_aio(event: &Event) -> bool424 pub fn is_aio(event: &Event) -> bool {
425 #[cfg(any(
426 target_os = "dragonfly",
427 target_os = "freebsd",
428 target_os = "ios",
429 target_os = "macos",
430 target_os = "tvos",
431 target_os = "visionos",
432 target_os = "watchos",
433 ))]
434 {
435 event.filter == libc::EVFILT_AIO
436 }
437 #[cfg(not(any(
438 target_os = "dragonfly",
439 target_os = "freebsd",
440 target_os = "ios",
441 target_os = "macos",
442 target_os = "tvos",
443 target_os = "visionos",
444 target_os = "watchos",
445 )))]
446 {
447 false
448 }
449 }
450
451 #[allow(unused_variables)] // `event` is only used on FreeBSD.
is_lio(event: &Event) -> bool452 pub fn is_lio(event: &Event) -> bool {
453 #[cfg(target_os = "freebsd")]
454 {
455 event.filter == libc::EVFILT_LIO
456 }
457 #[cfg(not(target_os = "freebsd"))]
458 {
459 false
460 }
461 }
462
debug_details(f: &mut fmt::Formatter<'_>, event: &Event) -> fmt::Result463 pub fn debug_details(f: &mut fmt::Formatter<'_>, event: &Event) -> fmt::Result {
464 debug_detail!(
465 FilterDetails(Filter),
466 PartialEq::eq,
467 libc::EVFILT_READ,
468 libc::EVFILT_WRITE,
469 libc::EVFILT_AIO,
470 libc::EVFILT_VNODE,
471 libc::EVFILT_PROC,
472 libc::EVFILT_SIGNAL,
473 libc::EVFILT_TIMER,
474 #[cfg(target_os = "freebsd")]
475 libc::EVFILT_PROCDESC,
476 #[cfg(any(
477 target_os = "freebsd",
478 target_os = "dragonfly",
479 target_os = "ios",
480 target_os = "macos",
481 target_os = "tvos",
482 target_os = "visionos",
483 target_os = "watchos",
484 ))]
485 libc::EVFILT_FS,
486 #[cfg(target_os = "freebsd")]
487 libc::EVFILT_LIO,
488 #[cfg(any(
489 target_os = "freebsd",
490 target_os = "dragonfly",
491 target_os = "ios",
492 target_os = "macos",
493 target_os = "tvos",
494 target_os = "visionos",
495 target_os = "watchos",
496 ))]
497 libc::EVFILT_USER,
498 #[cfg(target_os = "freebsd")]
499 libc::EVFILT_SENDFILE,
500 #[cfg(target_os = "freebsd")]
501 libc::EVFILT_EMPTY,
502 #[cfg(target_os = "dragonfly")]
503 libc::EVFILT_EXCEPT,
504 #[cfg(any(
505 target_os = "ios",
506 target_os = "macos",
507 target_os = "tvos",
508 target_os = "visionos",
509 target_os = "watchos"
510 ))]
511 libc::EVFILT_MACHPORT,
512 #[cfg(any(
513 target_os = "ios",
514 target_os = "macos",
515 target_os = "tvos",
516 target_os = "visionos",
517 target_os = "watchos"
518 ))]
519 libc::EVFILT_VM,
520 );
521
522 #[allow(clippy::trivially_copy_pass_by_ref)]
523 fn check_flag(got: &Flags, want: &Flags) -> bool {
524 (got & want) != 0
525 }
526 debug_detail!(
527 FlagsDetails(Flags),
528 check_flag,
529 libc::EV_ADD,
530 libc::EV_DELETE,
531 libc::EV_ENABLE,
532 libc::EV_DISABLE,
533 libc::EV_ONESHOT,
534 libc::EV_CLEAR,
535 libc::EV_RECEIPT,
536 libc::EV_DISPATCH,
537 #[cfg(target_os = "freebsd")]
538 libc::EV_DROP,
539 libc::EV_FLAG1,
540 libc::EV_ERROR,
541 libc::EV_EOF,
542 // Not stable across OS versions on OpenBSD.
543 #[cfg(not(target_os = "openbsd"))]
544 libc::EV_SYSFLAGS,
545 #[cfg(any(
546 target_os = "ios",
547 target_os = "macos",
548 target_os = "tvos",
549 target_os = "visionos",
550 target_os = "watchos"
551 ))]
552 libc::EV_FLAG0,
553 #[cfg(any(
554 target_os = "ios",
555 target_os = "macos",
556 target_os = "tvos",
557 target_os = "visionos",
558 target_os = "watchos"
559 ))]
560 libc::EV_POLL,
561 #[cfg(any(
562 target_os = "ios",
563 target_os = "macos",
564 target_os = "tvos",
565 target_os = "visionos",
566 target_os = "watchos"
567 ))]
568 libc::EV_OOBAND,
569 #[cfg(target_os = "dragonfly")]
570 libc::EV_NODATA,
571 );
572
573 #[allow(clippy::trivially_copy_pass_by_ref)]
574 fn check_fflag(got: &u32, want: &u32) -> bool {
575 (got & want) != 0
576 }
577 debug_detail!(
578 FflagsDetails(u32),
579 check_fflag,
580 #[cfg(any(
581 target_os = "dragonfly",
582 target_os = "freebsd",
583 target_os = "ios",
584 target_os = "macos",
585 target_os = "tvos",
586 target_os = "visionos",
587 target_os = "watchos",
588 ))]
589 libc::NOTE_TRIGGER,
590 #[cfg(any(
591 target_os = "dragonfly",
592 target_os = "freebsd",
593 target_os = "ios",
594 target_os = "macos",
595 target_os = "tvos",
596 target_os = "visionos",
597 target_os = "watchos",
598 ))]
599 libc::NOTE_FFNOP,
600 #[cfg(any(
601 target_os = "dragonfly",
602 target_os = "freebsd",
603 target_os = "ios",
604 target_os = "macos",
605 target_os = "tvos",
606 target_os = "visionos",
607 target_os = "watchos",
608 ))]
609 libc::NOTE_FFAND,
610 #[cfg(any(
611 target_os = "dragonfly",
612 target_os = "freebsd",
613 target_os = "ios",
614 target_os = "macos",
615 target_os = "tvos",
616 target_os = "visionos",
617 target_os = "watchos",
618 ))]
619 libc::NOTE_FFOR,
620 #[cfg(any(
621 target_os = "dragonfly",
622 target_os = "freebsd",
623 target_os = "ios",
624 target_os = "macos",
625 target_os = "tvos",
626 target_os = "visionos",
627 target_os = "watchos",
628 ))]
629 libc::NOTE_FFCOPY,
630 #[cfg(any(
631 target_os = "dragonfly",
632 target_os = "freebsd",
633 target_os = "ios",
634 target_os = "macos",
635 target_os = "tvos",
636 target_os = "visionos",
637 target_os = "watchos",
638 ))]
639 libc::NOTE_FFCTRLMASK,
640 #[cfg(any(
641 target_os = "dragonfly",
642 target_os = "freebsd",
643 target_os = "ios",
644 target_os = "macos",
645 target_os = "tvos",
646 target_os = "visionos",
647 target_os = "watchos",
648 ))]
649 libc::NOTE_FFLAGSMASK,
650 libc::NOTE_LOWAT,
651 libc::NOTE_DELETE,
652 libc::NOTE_WRITE,
653 #[cfg(target_os = "dragonfly")]
654 libc::NOTE_OOB,
655 #[cfg(target_os = "openbsd")]
656 libc::NOTE_EOF,
657 #[cfg(any(
658 target_os = "ios",
659 target_os = "macos",
660 target_os = "tvos",
661 target_os = "visionos",
662 target_os = "watchos"
663 ))]
664 libc::NOTE_EXTEND,
665 libc::NOTE_ATTRIB,
666 libc::NOTE_LINK,
667 libc::NOTE_RENAME,
668 libc::NOTE_REVOKE,
669 #[cfg(any(
670 target_os = "ios",
671 target_os = "macos",
672 target_os = "tvos",
673 target_os = "visionos",
674 target_os = "watchos"
675 ))]
676 libc::NOTE_NONE,
677 #[cfg(any(target_os = "openbsd"))]
678 libc::NOTE_TRUNCATE,
679 libc::NOTE_EXIT,
680 libc::NOTE_FORK,
681 libc::NOTE_EXEC,
682 #[cfg(any(
683 target_os = "ios",
684 target_os = "macos",
685 target_os = "tvos",
686 target_os = "visionos",
687 target_os = "watchos"
688 ))]
689 libc::NOTE_SIGNAL,
690 #[cfg(any(
691 target_os = "ios",
692 target_os = "macos",
693 target_os = "tvos",
694 target_os = "visionos",
695 target_os = "watchos"
696 ))]
697 libc::NOTE_EXITSTATUS,
698 #[cfg(any(
699 target_os = "ios",
700 target_os = "macos",
701 target_os = "tvos",
702 target_os = "visionos",
703 target_os = "watchos"
704 ))]
705 libc::NOTE_EXIT_DETAIL,
706 libc::NOTE_PDATAMASK,
707 libc::NOTE_PCTRLMASK,
708 #[cfg(any(
709 target_os = "dragonfly",
710 target_os = "freebsd",
711 target_os = "netbsd",
712 target_os = "openbsd",
713 ))]
714 libc::NOTE_TRACK,
715 #[cfg(any(
716 target_os = "dragonfly",
717 target_os = "freebsd",
718 target_os = "netbsd",
719 target_os = "openbsd",
720 ))]
721 libc::NOTE_TRACKERR,
722 #[cfg(any(
723 target_os = "dragonfly",
724 target_os = "freebsd",
725 target_os = "netbsd",
726 target_os = "openbsd",
727 ))]
728 libc::NOTE_CHILD,
729 #[cfg(any(
730 target_os = "ios",
731 target_os = "macos",
732 target_os = "tvos",
733 target_os = "visionos",
734 target_os = "watchos"
735 ))]
736 libc::NOTE_EXIT_DETAIL_MASK,
737 #[cfg(any(
738 target_os = "ios",
739 target_os = "macos",
740 target_os = "tvos",
741 target_os = "visionos",
742 target_os = "watchos"
743 ))]
744 libc::NOTE_EXIT_DECRYPTFAIL,
745 #[cfg(any(
746 target_os = "ios",
747 target_os = "macos",
748 target_os = "tvos",
749 target_os = "visionos",
750 target_os = "watchos"
751 ))]
752 libc::NOTE_EXIT_MEMORY,
753 #[cfg(any(
754 target_os = "ios",
755 target_os = "macos",
756 target_os = "tvos",
757 target_os = "visionos",
758 target_os = "watchos"
759 ))]
760 libc::NOTE_EXIT_CSERROR,
761 #[cfg(any(
762 target_os = "ios",
763 target_os = "macos",
764 target_os = "tvos",
765 target_os = "visionos",
766 target_os = "watchos"
767 ))]
768 libc::NOTE_VM_PRESSURE,
769 #[cfg(any(
770 target_os = "ios",
771 target_os = "macos",
772 target_os = "tvos",
773 target_os = "visionos",
774 target_os = "watchos"
775 ))]
776 libc::NOTE_VM_PRESSURE_TERMINATE,
777 #[cfg(any(
778 target_os = "ios",
779 target_os = "macos",
780 target_os = "tvos",
781 target_os = "visionos",
782 target_os = "watchos"
783 ))]
784 libc::NOTE_VM_PRESSURE_SUDDEN_TERMINATE,
785 #[cfg(any(
786 target_os = "ios",
787 target_os = "macos",
788 target_os = "tvos",
789 target_os = "visionos",
790 target_os = "watchos"
791 ))]
792 libc::NOTE_VM_ERROR,
793 #[cfg(any(
794 target_os = "freebsd",
795 target_os = "ios",
796 target_os = "macos",
797 target_os = "tvos",
798 target_os = "visionos",
799 target_os = "watchos"
800 ))]
801 libc::NOTE_SECONDS,
802 #[cfg(any(target_os = "freebsd"))]
803 libc::NOTE_MSECONDS,
804 #[cfg(any(
805 target_os = "freebsd",
806 target_os = "ios",
807 target_os = "macos",
808 target_os = "tvos",
809 target_os = "visionos",
810 target_os = "watchos"
811 ))]
812 libc::NOTE_USECONDS,
813 #[cfg(any(
814 target_os = "freebsd",
815 target_os = "ios",
816 target_os = "macos",
817 target_os = "tvos",
818 target_os = "visionos",
819 target_os = "watchos"
820 ))]
821 libc::NOTE_NSECONDS,
822 #[cfg(any(
823 target_os = "ios",
824 target_os = "macos",
825 target_os = "tvos",
826 target_os = "visionos",
827 target_os = "watchos"
828 ))]
829 libc::NOTE_ABSOLUTE,
830 #[cfg(any(
831 target_os = "ios",
832 target_os = "macos",
833 target_os = "tvos",
834 target_os = "visionos",
835 target_os = "watchos"
836 ))]
837 libc::NOTE_LEEWAY,
838 #[cfg(any(
839 target_os = "ios",
840 target_os = "macos",
841 target_os = "tvos",
842 target_os = "visionos",
843 target_os = "watchos"
844 ))]
845 libc::NOTE_CRITICAL,
846 #[cfg(any(
847 target_os = "ios",
848 target_os = "macos",
849 target_os = "tvos",
850 target_os = "visionos",
851 target_os = "watchos"
852 ))]
853 libc::NOTE_BACKGROUND,
854 );
855
856 // Can't reference fields in packed structures.
857 let ident = event.ident;
858 let data = event.data;
859 let udata = event.udata;
860 f.debug_struct("kevent")
861 .field("ident", &ident)
862 .field("filter", &FilterDetails(event.filter))
863 .field("flags", &FlagsDetails(event.flags))
864 .field("fflags", &FflagsDetails(event.fflags))
865 .field("data", &data)
866 .field("udata", &udata)
867 .finish()
868 }
869 }
870
871 // No special requirement from the implementation around waking.
872 pub(crate) use crate::sys::unix::waker::Waker;
873
874 cfg_io_source! {
875 mod stateless_io_source;
876 pub(crate) use stateless_io_source::IoSourceState;
877 }
878
879 #[test]
880 #[cfg(feature = "os-ext")]
does_not_register_rw()881 fn does_not_register_rw() {
882 use crate::unix::SourceFd;
883 use crate::{Poll, Token};
884
885 let kq = unsafe { libc::kqueue() };
886 let mut kqf = SourceFd(&kq);
887 let poll = Poll::new().unwrap();
888
889 // Registering kqueue fd will fail if write is requested (On anything but
890 // some versions of macOS).
891 poll.registry()
892 .register(&mut kqf, Token(1234), Interest::READABLE)
893 .unwrap();
894 }
895