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