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