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