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