1 use crate::{Interest, Token};
2 use log::error;
3 use std::mem::MaybeUninit;
4 use std::ops::{Deref, DerefMut};
5 use std::os::unix::io::{AsRawFd, RawFd};
6 #[cfg(debug_assertions)]
7 use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
8 use std::time::Duration;
9 use std::{cmp, io, ptr, slice};
10 
11 /// Unique id for use as `SelectorId`.
12 #[cfg(debug_assertions)]
13 static NEXT_ID: AtomicUsize = AtomicUsize::new(1);
14 
15 // Type of the `nchanges` and `nevents` parameters in the `kevent` function.
16 #[cfg(not(target_os = "netbsd"))]
17 type Count = libc::c_int;
18 #[cfg(target_os = "netbsd")]
19 type Count = libc::size_t;
20 
21 // Type of the `filter` field in the `kevent` structure.
22 #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
23 type Filter = libc::c_short;
24 #[cfg(any(target_os = "macos", target_os = "ios"))]
25 type Filter = i16;
26 #[cfg(target_os = "netbsd")]
27 type Filter = u32;
28 
29 // Type of the `flags` field in the `kevent` structure.
30 #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
31 type Flags = libc::c_ushort;
32 #[cfg(any(target_os = "macos", target_os = "ios"))]
33 type Flags = u16;
34 #[cfg(target_os = "netbsd")]
35 type Flags = u32;
36 
37 // Type of the `data` field in the `kevent` structure.
38 #[cfg(any(
39     target_os = "dragonfly",
40     target_os = "freebsd",
41     target_os = "ios",
42     target_os = "macos"
43 ))]
44 type Data = libc::intptr_t;
45 #[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
46 type Data = i64;
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             fflags: 0,
61             data: 0,
62             udata: $data as UData,
63         }
64     };
65 }
66 
67 #[derive(Debug)]
68 pub struct Selector {
69     #[cfg(debug_assertions)]
70     id: usize,
71     kq: RawFd,
72     #[cfg(debug_assertions)]
73     has_waker: AtomicBool,
74 }
75 
76 impl Selector {
new() -> io::Result<Selector>77     pub fn new() -> io::Result<Selector> {
78         syscall!(kqueue())
79             .and_then(|kq| syscall!(fcntl(kq, libc::F_SETFD, libc::FD_CLOEXEC)).map(|_| kq))
80             .map(|kq| Selector {
81                 #[cfg(debug_assertions)]
82                 id: NEXT_ID.fetch_add(1, Ordering::Relaxed),
83                 kq,
84                 #[cfg(debug_assertions)]
85                 has_waker: AtomicBool::new(false),
86             })
87     }
88 
try_clone(&self) -> io::Result<Selector>89     pub fn try_clone(&self) -> io::Result<Selector> {
90         syscall!(fcntl(self.kq, libc::F_DUPFD_CLOEXEC, super::LOWEST_FD)).map(|kq| Selector {
91             // It's the same selector, so we use the same id.
92             #[cfg(debug_assertions)]
93             id: self.id,
94             kq,
95             #[cfg(debug_assertions)]
96             has_waker: AtomicBool::new(self.has_waker.load(Ordering::Acquire)),
97         })
98     }
99 
select(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<()>100     pub fn select(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<()> {
101         let timeout = timeout.map(|to| libc::timespec {
102             tv_sec: cmp::min(to.as_secs(), libc::time_t::max_value() as u64) as libc::time_t,
103             // `Duration::subsec_nanos` is guaranteed to be less than one
104             // billion (the number of nanoseconds in a second), making the
105             // cast to i32 safe. The cast itself is needed for platforms
106             // where C's long is only 32 bits.
107             tv_nsec: libc::c_long::from(to.subsec_nanos() as i32),
108         });
109         let timeout = timeout
110             .as_ref()
111             .map(|s| s as *const _)
112             .unwrap_or(ptr::null_mut());
113 
114         events.clear();
115         syscall!(kevent(
116             self.kq,
117             ptr::null(),
118             0,
119             events.as_mut_ptr(),
120             events.capacity() as Count,
121             timeout,
122         ))
123         .map(|n_events| {
124             // This is safe because `kevent` ensures that `n_events` are
125             // assigned.
126             unsafe { events.set_len(n_events as usize) };
127         })
128     }
129 
register(&self, fd: RawFd, token: Token, interests: Interest) -> io::Result<()>130     pub fn register(&self, fd: RawFd, token: Token, interests: Interest) -> io::Result<()> {
131         let flags = libc::EV_CLEAR | libc::EV_RECEIPT | libc::EV_ADD;
132         // At most we need two changes, but maybe we only need 1.
133         let mut changes: [MaybeUninit<libc::kevent>; 2] =
134             [MaybeUninit::uninit(), MaybeUninit::uninit()];
135         let mut n_changes = 0;
136 
137         if interests.is_writable() {
138             let kevent = kevent!(fd, libc::EVFILT_WRITE, flags, token.0);
139             changes[n_changes] = MaybeUninit::new(kevent);
140             n_changes += 1;
141         }
142 
143         if interests.is_readable() {
144             let kevent = kevent!(fd, libc::EVFILT_READ, flags, token.0);
145             changes[n_changes] = MaybeUninit::new(kevent);
146             n_changes += 1;
147         }
148 
149         // Older versions of macOS (OS X 10.11 and 10.10 have been witnessed)
150         // can return EPIPE when registering a pipe file descriptor where the
151         // other end has already disappeared. For example code that creates a
152         // pipe, closes a file descriptor, and then registers the other end will
153         // see an EPIPE returned from `register`.
154         //
155         // It also turns out that kevent will still report events on the file
156         // descriptor, telling us that it's readable/hup at least after we've
157         // done this registration. As a result we just ignore `EPIPE` here
158         // instead of propagating it.
159         //
160         // More info can be found at tokio-rs/mio#582.
161         let changes = unsafe {
162             // This is safe because we ensure that at least `n_changes` are in
163             // the array.
164             slice::from_raw_parts_mut(changes[0].as_mut_ptr(), n_changes)
165         };
166         kevent_register(self.kq, changes, &[libc::EPIPE as Data])
167     }
168 
reregister(&self, fd: RawFd, token: Token, interests: Interest) -> io::Result<()>169     pub fn reregister(&self, fd: RawFd, token: Token, interests: Interest) -> io::Result<()> {
170         let flags = libc::EV_CLEAR | libc::EV_RECEIPT;
171         let write_flags = if interests.is_writable() {
172             flags | libc::EV_ADD
173         } else {
174             flags | libc::EV_DELETE
175         };
176         let read_flags = if interests.is_readable() {
177             flags | libc::EV_ADD
178         } else {
179             flags | libc::EV_DELETE
180         };
181 
182         let mut changes: [libc::kevent; 2] = [
183             kevent!(fd, libc::EVFILT_WRITE, write_flags, token.0),
184             kevent!(fd, libc::EVFILT_READ, read_flags, token.0),
185         ];
186 
187         // Since there is no way to check with which interests the fd was
188         // registered we modify both readable and write, adding it when required
189         // and removing it otherwise, ignoring the ENOENT error when it comes
190         // up. The ENOENT error informs us that a filter we're trying to remove
191         // wasn't there in first place, but we don't really care since our goal
192         // is accomplished.
193         //
194         // For the explanation of ignoring `EPIPE` see `register`.
195         kevent_register(
196             self.kq,
197             &mut changes,
198             &[libc::ENOENT as Data, libc::EPIPE as Data],
199         )
200     }
201 
deregister(&self, fd: RawFd) -> io::Result<()>202     pub fn deregister(&self, fd: RawFd) -> io::Result<()> {
203         let flags = libc::EV_DELETE | libc::EV_RECEIPT;
204         let mut changes: [libc::kevent; 2] = [
205             kevent!(fd, libc::EVFILT_WRITE, flags, 0),
206             kevent!(fd, libc::EVFILT_READ, flags, 0),
207         ];
208 
209         // Since there is no way to check with which interests the fd was
210         // registered we remove both filters (readable and writeable) and ignore
211         // the ENOENT error when it comes up. The ENOENT error informs us that
212         // the filter wasn't there in first place, but we don't really care
213         // about that since our goal is to remove it.
214         kevent_register(self.kq, &mut changes, &[libc::ENOENT as Data])
215     }
216 
217     #[cfg(debug_assertions)]
register_waker(&self) -> bool218     pub fn register_waker(&self) -> bool {
219         self.has_waker.swap(true, Ordering::AcqRel)
220     }
221 
222     // Used by `Waker`.
223     #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))]
setup_waker(&self, token: Token) -> io::Result<()>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         syscall!(kevent(self.kq, &kevent, 1, &mut kevent, 1, ptr::null())).and_then(|_| {
234             if (kevent.flags & libc::EV_ERROR) != 0 && kevent.data != 0 {
235                 Err(io::Error::from_raw_os_error(kevent.data as i32))
236             } else {
237                 Ok(())
238             }
239         })
240     }
241 
242     // Used by `Waker`.
243     #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))]
wake(&self, token: Token) -> io::Result<()>244     pub fn wake(&self, token: Token) -> io::Result<()> {
245         let mut kevent = kevent!(
246             0,
247             libc::EVFILT_USER,
248             libc::EV_ADD | libc::EV_RECEIPT,
249             token.0
250         );
251         kevent.fflags = libc::NOTE_TRIGGER;
252 
253         syscall!(kevent(self.kq, &kevent, 1, &mut kevent, 1, ptr::null())).and_then(|_| {
254             if (kevent.flags & libc::EV_ERROR) != 0 && kevent.data != 0 {
255                 Err(io::Error::from_raw_os_error(kevent.data as i32))
256             } else {
257                 Ok(())
258             }
259         })
260     }
261 }
262 
263 /// Register `changes` with `kq`ueue.
kevent_register( kq: RawFd, changes: &mut [libc::kevent], ignored_errors: &[Data], ) -> io::Result<()>264 fn kevent_register(
265     kq: RawFd,
266     changes: &mut [libc::kevent],
267     ignored_errors: &[Data],
268 ) -> io::Result<()> {
269     syscall!(kevent(
270         kq,
271         changes.as_ptr(),
272         changes.len() as Count,
273         changes.as_mut_ptr(),
274         changes.len() as Count,
275         ptr::null(),
276     ))
277     .map(|_| ())
278     .or_else(|err| {
279         // According to the manual page of FreeBSD: "When kevent() call fails
280         // with EINTR error, all changes in the changelist have been applied",
281         // so we can safely ignore it.
282         if err.raw_os_error() == Some(libc::EINTR) {
283             Ok(())
284         } else {
285             Err(err)
286         }
287     })
288     .and_then(|()| check_errors(&changes, ignored_errors))
289 }
290 
291 /// Check all events for possible errors, it returns the first error found.
check_errors(events: &[libc::kevent], ignored_errors: &[Data]) -> io::Result<()>292 fn check_errors(events: &[libc::kevent], ignored_errors: &[Data]) -> io::Result<()> {
293     for event in events {
294         // We can't use references to packed structures (in checking the ignored
295         // errors), so we need copy the data out before use.
296         let data = event.data;
297         // Check for the error flag, the actual error will be in the `data`
298         // field.
299         if (event.flags & libc::EV_ERROR != 0) && data != 0 && !ignored_errors.contains(&data) {
300             return Err(io::Error::from_raw_os_error(data as i32));
301         }
302     }
303     Ok(())
304 }
305 
306 cfg_io_source! {
307     #[cfg(debug_assertions)]
308     impl Selector {
309         pub fn id(&self) -> usize {
310             self.id
311         }
312     }
313 }
314 
315 impl AsRawFd for Selector {
as_raw_fd(&self) -> RawFd316     fn as_raw_fd(&self) -> RawFd {
317         self.kq
318     }
319 }
320 
321 impl Drop for Selector {
drop(&mut self)322     fn drop(&mut self) {
323         if let Err(err) = syscall!(close(self.kq)) {
324             error!("error closing kqueue: {}", err);
325         }
326     }
327 }
328 
329 pub type Event = libc::kevent;
330 pub struct Events(Vec<libc::kevent>);
331 
332 impl Events {
with_capacity(capacity: usize) -> Events333     pub fn with_capacity(capacity: usize) -> Events {
334         Events(Vec::with_capacity(capacity))
335     }
336 }
337 
338 impl Deref for Events {
339     type Target = Vec<libc::kevent>;
340 
deref(&self) -> &Self::Target341     fn deref(&self) -> &Self::Target {
342         &self.0
343     }
344 }
345 
346 impl DerefMut for Events {
deref_mut(&mut self) -> &mut Self::Target347     fn deref_mut(&mut self) -> &mut Self::Target {
348         &mut self.0
349     }
350 }
351 
352 // `Events` cannot derive `Send` or `Sync` because of the
353 // `udata: *mut ::c_void` field in `libc::kevent`. However, `Events`'s public
354 // API treats the `udata` field as a `uintptr_t` which is `Send`. `Sync` is
355 // safe because with a `events: &Events` value, the only access to the `udata`
356 // field is through `fn token(event: &Event)` which cannot mutate the field.
357 unsafe impl Send for Events {}
358 unsafe impl Sync for Events {}
359 
360 pub mod event {
361     use std::fmt;
362 
363     use crate::sys::Event;
364     use crate::Token;
365 
366     use super::{Filter, Flags};
367 
token(event: &Event) -> Token368     pub fn token(event: &Event) -> Token {
369         Token(event.udata as usize)
370     }
371 
is_readable(event: &Event) -> bool372     pub fn is_readable(event: &Event) -> bool {
373         event.filter == libc::EVFILT_READ || {
374             #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))]
375             // Used by the `Awakener`. On platforms that use `eventfd` or a unix
376             // pipe it will emit a readable event so we'll fake that here as
377             // well.
378             {
379                 event.filter == libc::EVFILT_USER
380             }
381             #[cfg(not(any(target_os = "freebsd", target_os = "ios", target_os = "macos")))]
382             {
383                 false
384             }
385         }
386     }
387 
is_writable(event: &Event) -> bool388     pub fn is_writable(event: &Event) -> bool {
389         event.filter == libc::EVFILT_WRITE
390     }
391 
is_error(event: &Event) -> bool392     pub fn is_error(event: &Event) -> bool {
393         (event.flags & libc::EV_ERROR) != 0 ||
394             // When the read end of the socket is closed, EV_EOF is set on
395             // flags, and fflags contains the error if there is one.
396             (event.flags & libc::EV_EOF) != 0 && event.fflags != 0
397     }
398 
is_read_closed(event: &Event) -> bool399     pub fn is_read_closed(event: &Event) -> bool {
400         event.filter == libc::EVFILT_READ && event.flags & libc::EV_EOF != 0
401     }
402 
is_write_closed(event: &Event) -> bool403     pub fn is_write_closed(event: &Event) -> bool {
404         event.filter == libc::EVFILT_WRITE && event.flags & libc::EV_EOF != 0
405     }
406 
is_priority(_: &Event) -> bool407     pub fn is_priority(_: &Event) -> bool {
408         // kqueue doesn't have priority indicators.
409         false
410     }
411 
412     #[allow(unused_variables)] // `event` is not used on some platforms.
is_aio(event: &Event) -> bool413     pub fn is_aio(event: &Event) -> bool {
414         #[cfg(any(
415             target_os = "dragonfly",
416             target_os = "freebsd",
417             target_os = "ios",
418             target_os = "macos"
419         ))]
420         {
421             event.filter == libc::EVFILT_AIO
422         }
423         #[cfg(not(any(
424             target_os = "dragonfly",
425             target_os = "freebsd",
426             target_os = "ios",
427             target_os = "macos"
428         )))]
429         {
430             false
431         }
432     }
433 
434     #[allow(unused_variables)] // `event` is only used on FreeBSD.
is_lio(event: &Event) -> bool435     pub fn is_lio(event: &Event) -> bool {
436         #[cfg(target_os = "freebsd")]
437         {
438             event.filter == libc::EVFILT_LIO
439         }
440         #[cfg(not(target_os = "freebsd"))]
441         {
442             false
443         }
444     }
445 
debug_details(f: &mut fmt::Formatter<'_>, event: &Event) -> fmt::Result446     pub fn debug_details(f: &mut fmt::Formatter<'_>, event: &Event) -> fmt::Result {
447         debug_detail!(
448             FilterDetails(Filter),
449             PartialEq::eq,
450             libc::EVFILT_READ,
451             libc::EVFILT_WRITE,
452             libc::EVFILT_AIO,
453             libc::EVFILT_VNODE,
454             libc::EVFILT_PROC,
455             libc::EVFILT_SIGNAL,
456             libc::EVFILT_TIMER,
457             #[cfg(target_os = "freebsd")]
458             libc::EVFILT_PROCDESC,
459             #[cfg(any(
460                 target_os = "freebsd",
461                 target_os = "dragonfly",
462                 target_os = "ios",
463                 target_os = "macos"
464             ))]
465             libc::EVFILT_FS,
466             #[cfg(target_os = "freebsd")]
467             libc::EVFILT_LIO,
468             #[cfg(any(
469                 target_os = "freebsd",
470                 target_os = "dragonfly",
471                 target_os = "ios",
472                 target_os = "macos"
473             ))]
474             libc::EVFILT_USER,
475             #[cfg(target_os = "freebsd")]
476             libc::EVFILT_SENDFILE,
477             #[cfg(target_os = "freebsd")]
478             libc::EVFILT_EMPTY,
479             #[cfg(target_os = "dragonfly")]
480             libc::EVFILT_EXCEPT,
481             #[cfg(any(target_os = "ios", target_os = "macos"))]
482             libc::EVFILT_MACHPORT,
483             #[cfg(any(target_os = "ios", target_os = "macos"))]
484             libc::EVFILT_VM,
485         );
486 
487         #[allow(clippy::trivially_copy_pass_by_ref)]
488         fn check_flag(got: &Flags, want: &Flags) -> bool {
489             (got & want) != 0
490         }
491         debug_detail!(
492             FlagsDetails(Flags),
493             check_flag,
494             libc::EV_ADD,
495             libc::EV_DELETE,
496             libc::EV_ENABLE,
497             libc::EV_DISABLE,
498             libc::EV_ONESHOT,
499             libc::EV_CLEAR,
500             libc::EV_RECEIPT,
501             libc::EV_DISPATCH,
502             #[cfg(target_os = "freebsd")]
503             libc::EV_DROP,
504             libc::EV_FLAG1,
505             libc::EV_ERROR,
506             libc::EV_EOF,
507             libc::EV_SYSFLAGS,
508             #[cfg(any(target_os = "ios", target_os = "macos"))]
509             libc::EV_FLAG0,
510             #[cfg(any(target_os = "ios", target_os = "macos"))]
511             libc::EV_POLL,
512             #[cfg(any(target_os = "ios", target_os = "macos"))]
513             libc::EV_OOBAND,
514             #[cfg(target_os = "dragonfly")]
515             libc::EV_NODATA,
516         );
517 
518         #[allow(clippy::trivially_copy_pass_by_ref)]
519         fn check_fflag(got: &u32, want: &u32) -> bool {
520             (got & want) != 0
521         }
522         debug_detail!(
523             FflagsDetails(u32),
524             check_fflag,
525             #[cfg(any(
526                 target_os = "dragonfly",
527                 target_os = "freebsd",
528                 target_os = "ios",
529                 target_os = "macos"
530             ))]
531             libc::NOTE_TRIGGER,
532             #[cfg(any(
533                 target_os = "dragonfly",
534                 target_os = "freebsd",
535                 target_os = "ios",
536                 target_os = "macos"
537             ))]
538             libc::NOTE_FFNOP,
539             #[cfg(any(
540                 target_os = "dragonfly",
541                 target_os = "freebsd",
542                 target_os = "ios",
543                 target_os = "macos"
544             ))]
545             libc::NOTE_FFAND,
546             #[cfg(any(
547                 target_os = "dragonfly",
548                 target_os = "freebsd",
549                 target_os = "ios",
550                 target_os = "macos"
551             ))]
552             libc::NOTE_FFOR,
553             #[cfg(any(
554                 target_os = "dragonfly",
555                 target_os = "freebsd",
556                 target_os = "ios",
557                 target_os = "macos"
558             ))]
559             libc::NOTE_FFCOPY,
560             #[cfg(any(
561                 target_os = "dragonfly",
562                 target_os = "freebsd",
563                 target_os = "ios",
564                 target_os = "macos"
565             ))]
566             libc::NOTE_FFCTRLMASK,
567             #[cfg(any(
568                 target_os = "dragonfly",
569                 target_os = "freebsd",
570                 target_os = "ios",
571                 target_os = "macos"
572             ))]
573             libc::NOTE_FFLAGSMASK,
574             libc::NOTE_LOWAT,
575             libc::NOTE_DELETE,
576             libc::NOTE_WRITE,
577             #[cfg(target_os = "dragonfly")]
578             libc::NOTE_OOB,
579             #[cfg(target_os = "openbsd")]
580             libc::NOTE_EOF,
581             #[cfg(any(target_os = "ios", target_os = "macos"))]
582             libc::NOTE_EXTEND,
583             libc::NOTE_ATTRIB,
584             libc::NOTE_LINK,
585             libc::NOTE_RENAME,
586             libc::NOTE_REVOKE,
587             #[cfg(any(target_os = "ios", target_os = "macos"))]
588             libc::NOTE_NONE,
589             #[cfg(any(target_os = "openbsd"))]
590             libc::NOTE_TRUNCATE,
591             libc::NOTE_EXIT,
592             libc::NOTE_FORK,
593             libc::NOTE_EXEC,
594             #[cfg(any(target_os = "ios", target_os = "macos"))]
595             libc::NOTE_SIGNAL,
596             #[cfg(any(target_os = "ios", target_os = "macos"))]
597             libc::NOTE_EXITSTATUS,
598             #[cfg(any(target_os = "ios", target_os = "macos"))]
599             libc::NOTE_EXIT_DETAIL,
600             libc::NOTE_PDATAMASK,
601             libc::NOTE_PCTRLMASK,
602             #[cfg(any(
603                 target_os = "dragonfly",
604                 target_os = "freebsd",
605                 target_os = "netbsd",
606                 target_os = "openbsd"
607             ))]
608             libc::NOTE_TRACK,
609             #[cfg(any(
610                 target_os = "dragonfly",
611                 target_os = "freebsd",
612                 target_os = "netbsd",
613                 target_os = "openbsd"
614             ))]
615             libc::NOTE_TRACKERR,
616             #[cfg(any(
617                 target_os = "dragonfly",
618                 target_os = "freebsd",
619                 target_os = "netbsd",
620                 target_os = "openbsd"
621             ))]
622             libc::NOTE_CHILD,
623             #[cfg(any(target_os = "ios", target_os = "macos"))]
624             libc::NOTE_EXIT_DETAIL_MASK,
625             #[cfg(any(target_os = "ios", target_os = "macos"))]
626             libc::NOTE_EXIT_DECRYPTFAIL,
627             #[cfg(any(target_os = "ios", target_os = "macos"))]
628             libc::NOTE_EXIT_MEMORY,
629             #[cfg(any(target_os = "ios", target_os = "macos"))]
630             libc::NOTE_EXIT_CSERROR,
631             #[cfg(any(target_os = "ios", target_os = "macos"))]
632             libc::NOTE_VM_PRESSURE,
633             #[cfg(any(target_os = "ios", target_os = "macos"))]
634             libc::NOTE_VM_PRESSURE_TERMINATE,
635             #[cfg(any(target_os = "ios", target_os = "macos"))]
636             libc::NOTE_VM_PRESSURE_SUDDEN_TERMINATE,
637             #[cfg(any(target_os = "ios", target_os = "macos"))]
638             libc::NOTE_VM_ERROR,
639             #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))]
640             libc::NOTE_SECONDS,
641             #[cfg(any(target_os = "freebsd"))]
642             libc::NOTE_MSECONDS,
643             #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))]
644             libc::NOTE_USECONDS,
645             #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))]
646             libc::NOTE_NSECONDS,
647             #[cfg(any(target_os = "ios", target_os = "macos"))]
648             #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))]
649             libc::NOTE_ABSOLUTE,
650             #[cfg(any(target_os = "ios", target_os = "macos"))]
651             libc::NOTE_LEEWAY,
652             #[cfg(any(target_os = "ios", target_os = "macos"))]
653             libc::NOTE_CRITICAL,
654             #[cfg(any(target_os = "ios", target_os = "macos"))]
655             libc::NOTE_BACKGROUND,
656         );
657 
658         // Can't reference fields in packed structures.
659         let ident = event.ident;
660         let data = event.data;
661         let udata = event.udata;
662         f.debug_struct("kevent")
663             .field("ident", &ident)
664             .field("filter", &FilterDetails(event.filter))
665             .field("flags", &FlagsDetails(event.flags))
666             .field("fflags", &FflagsDetails(event.fflags))
667             .field("data", &data)
668             .field("udata", &udata)
669             .finish()
670     }
671 }
672 
673 #[test]
674 #[cfg(feature = "os-ext")]
does_not_register_rw()675 fn does_not_register_rw() {
676     use crate::unix::SourceFd;
677     use crate::{Poll, Token};
678 
679     let kq = unsafe { libc::kqueue() };
680     let mut kqf = SourceFd(&kq);
681     let poll = Poll::new().unwrap();
682 
683     // Registering kqueue fd will fail if write is requested (On anything but
684     // some versions of macOS).
685     poll.registry()
686         .register(&mut kqf, Token(1234), Interest::READABLE)
687         .unwrap();
688 }
689