Skip to main content

mio/sys/unix/selector/
kqueue.rs

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