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