| /* TOOD: Implement for other kqueue based systems | 
 |  */ | 
 |  | 
 | use crate::{Errno, Result}; | 
 | #[cfg(not(target_os = "netbsd"))] | 
 | use libc::{timespec, time_t, c_int, c_long, intptr_t, uintptr_t}; | 
 | #[cfg(target_os = "netbsd")] | 
 | use libc::{timespec, time_t, c_long, intptr_t, uintptr_t, size_t}; | 
 | use std::os::unix::io::RawFd; | 
 | use std::ptr; | 
 | use std::mem; | 
 |  | 
 | // Redefine kevent in terms of programmer-friendly enums and bitfields. | 
 | #[repr(C)] | 
 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] | 
 | pub struct KEvent { | 
 |     kevent: libc::kevent, | 
 | } | 
 |  | 
 | #[cfg(any(target_os = "dragonfly", target_os = "freebsd", | 
 |           target_os = "ios", target_os = "macos", | 
 |           target_os = "openbsd"))] | 
 | type type_of_udata = *mut libc::c_void; | 
 | #[cfg(any(target_os = "dragonfly", target_os = "freebsd", | 
 |           target_os = "ios", target_os = "macos"))] | 
 | type type_of_data = intptr_t; | 
 | #[cfg(any(target_os = "netbsd"))] | 
 | type type_of_udata = intptr_t; | 
 | #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] | 
 | type type_of_data = i64; | 
 |  | 
 | #[cfg(target_os = "netbsd")] | 
 | type type_of_event_filter = u32; | 
 | #[cfg(not(target_os = "netbsd"))] | 
 | type type_of_event_filter = i16; | 
 | libc_enum! { | 
 |     #[cfg_attr(target_os = "netbsd", repr(u32))] | 
 |     #[cfg_attr(not(target_os = "netbsd"), repr(i16))] | 
 |     pub enum EventFilter { | 
 |         EVFILT_AIO, | 
 |         /// Returns whenever there is no remaining data in the write buffer | 
 |         #[cfg(target_os = "freebsd")] | 
 |         EVFILT_EMPTY, | 
 |         #[cfg(target_os = "dragonfly")] | 
 |         EVFILT_EXCEPT, | 
 |         #[cfg(any(target_os = "dragonfly", | 
 |                   target_os = "freebsd", | 
 |                   target_os = "ios", | 
 |                   target_os = "macos"))] | 
 |         EVFILT_FS, | 
 |         #[cfg(target_os = "freebsd")] | 
 |         EVFILT_LIO, | 
 |         #[cfg(any(target_os = "ios", target_os = "macos"))] | 
 |         EVFILT_MACHPORT, | 
 |         EVFILT_PROC, | 
 |         /// Returns events associated with the process referenced by a given | 
 |         /// process descriptor, created by `pdfork()`. The events to monitor are: | 
 |         /// | 
 |         /// - NOTE_EXIT: the process has exited. The exit status will be stored in data. | 
 |         #[cfg(target_os = "freebsd")] | 
 |         EVFILT_PROCDESC, | 
 |         EVFILT_READ, | 
 |         /// Returns whenever an asynchronous `sendfile()` call completes. | 
 |         #[cfg(target_os = "freebsd")] | 
 |         EVFILT_SENDFILE, | 
 |         EVFILT_SIGNAL, | 
 |         EVFILT_TIMER, | 
 |         #[cfg(any(target_os = "dragonfly", | 
 |                   target_os = "freebsd", | 
 |                   target_os = "ios", | 
 |                   target_os = "macos"))] | 
 |         EVFILT_USER, | 
 |         #[cfg(any(target_os = "ios", target_os = "macos"))] | 
 |         EVFILT_VM, | 
 |         EVFILT_VNODE, | 
 |         EVFILT_WRITE, | 
 |     } | 
 | } | 
 |  | 
 | #[cfg(any(target_os = "dragonfly", target_os = "freebsd", | 
 |           target_os = "ios", target_os = "macos", | 
 |           target_os = "openbsd"))] | 
 | pub type type_of_event_flag = u16; | 
 | #[cfg(any(target_os = "netbsd"))] | 
 | pub type type_of_event_flag = u32; | 
 | libc_bitflags!{ | 
 |     pub struct EventFlag: type_of_event_flag { | 
 |         EV_ADD; | 
 |         EV_CLEAR; | 
 |         EV_DELETE; | 
 |         EV_DISABLE; | 
 |         #[cfg(any(target_os = "dragonfly", target_os = "freebsd", | 
 |                   target_os = "ios", target_os = "macos", | 
 |                   target_os = "netbsd", target_os = "openbsd"))] | 
 |         EV_DISPATCH; | 
 |         #[cfg(target_os = "freebsd")] | 
 |         EV_DROP; | 
 |         EV_ENABLE; | 
 |         EV_EOF; | 
 |         EV_ERROR; | 
 |         #[cfg(any(target_os = "macos", target_os = "ios"))] | 
 |         EV_FLAG0; | 
 |         EV_FLAG1; | 
 |         #[cfg(target_os = "dragonfly")] | 
 |         EV_NODATA; | 
 |         EV_ONESHOT; | 
 |         #[cfg(any(target_os = "macos", target_os = "ios"))] | 
 |         EV_OOBAND; | 
 |         #[cfg(any(target_os = "macos", target_os = "ios"))] | 
 |         EV_POLL; | 
 |         #[cfg(any(target_os = "dragonfly", target_os = "freebsd", | 
 |                   target_os = "ios", target_os = "macos", | 
 |                   target_os = "netbsd", target_os = "openbsd"))] | 
 |         EV_RECEIPT; | 
 |         EV_SYSFLAGS; | 
 |     } | 
 | } | 
 |  | 
 | libc_bitflags!( | 
 |     pub struct FilterFlag: u32 { | 
 |         #[cfg(any(target_os = "macos", target_os = "ios"))] | 
 |         NOTE_ABSOLUTE; | 
 |         NOTE_ATTRIB; | 
 |         NOTE_CHILD; | 
 |         NOTE_DELETE; | 
 |         #[cfg(target_os = "openbsd")] | 
 |         NOTE_EOF; | 
 |         NOTE_EXEC; | 
 |         NOTE_EXIT; | 
 |         #[cfg(any(target_os = "macos", target_os = "ios"))] | 
 |         NOTE_EXITSTATUS; | 
 |         NOTE_EXTEND; | 
 |         #[cfg(any(target_os = "macos", | 
 |                   target_os = "ios", | 
 |                   target_os = "freebsd", | 
 |                   target_os = "dragonfly"))] | 
 |         NOTE_FFAND; | 
 |         #[cfg(any(target_os = "macos", | 
 |                   target_os = "ios", | 
 |                   target_os = "freebsd", | 
 |                   target_os = "dragonfly"))] | 
 |         NOTE_FFCOPY; | 
 |         #[cfg(any(target_os = "macos", | 
 |                   target_os = "ios", | 
 |                   target_os = "freebsd", | 
 |                   target_os = "dragonfly"))] | 
 |         NOTE_FFCTRLMASK; | 
 |         #[cfg(any(target_os = "macos", | 
 |                   target_os = "ios", | 
 |                   target_os = "freebsd", | 
 |                   target_os = "dragonfly"))] | 
 |         NOTE_FFLAGSMASK; | 
 |         #[cfg(any(target_os = "macos", | 
 |                   target_os = "ios", | 
 |                   target_os = "freebsd", | 
 |                   target_os = "dragonfly"))] | 
 |         NOTE_FFNOP; | 
 |         #[cfg(any(target_os = "macos", | 
 |                   target_os = "ios", | 
 |                   target_os = "freebsd", | 
 |                   target_os = "dragonfly"))] | 
 |         NOTE_FFOR; | 
 |         NOTE_FORK; | 
 |         NOTE_LINK; | 
 |         NOTE_LOWAT; | 
 |         #[cfg(target_os = "freebsd")] | 
 |         NOTE_MSECONDS; | 
 |         #[cfg(any(target_os = "macos", target_os = "ios"))] | 
 |         NOTE_NONE; | 
 |         #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] | 
 |         NOTE_NSECONDS; | 
 |         #[cfg(target_os = "dragonfly")] | 
 |         NOTE_OOB; | 
 |         NOTE_PCTRLMASK; | 
 |         NOTE_PDATAMASK; | 
 |         NOTE_RENAME; | 
 |         NOTE_REVOKE; | 
 |         #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] | 
 |         NOTE_SECONDS; | 
 |         #[cfg(any(target_os = "macos", target_os = "ios"))] | 
 |         NOTE_SIGNAL; | 
 |         NOTE_TRACK; | 
 |         NOTE_TRACKERR; | 
 |         #[cfg(any(target_os = "macos", | 
 |                   target_os = "ios", | 
 |                   target_os = "freebsd", | 
 |                   target_os = "dragonfly"))] | 
 |         NOTE_TRIGGER; | 
 |         #[cfg(target_os = "openbsd")] | 
 |         NOTE_TRUNCATE; | 
 |         #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] | 
 |         NOTE_USECONDS; | 
 |         #[cfg(any(target_os = "macos", target_os = "ios"))] | 
 |         NOTE_VM_ERROR; | 
 |         #[cfg(any(target_os = "macos", target_os = "ios"))] | 
 |         NOTE_VM_PRESSURE; | 
 |         #[cfg(any(target_os = "macos", target_os = "ios"))] | 
 |         NOTE_VM_PRESSURE_SUDDEN_TERMINATE; | 
 |         #[cfg(any(target_os = "macos", target_os = "ios"))] | 
 |         NOTE_VM_PRESSURE_TERMINATE; | 
 |         NOTE_WRITE; | 
 |     } | 
 | ); | 
 |  | 
 | pub fn kqueue() -> Result<RawFd> { | 
 |     let res = unsafe { libc::kqueue() }; | 
 |  | 
 |     Errno::result(res) | 
 | } | 
 |  | 
 |  | 
 | // KEvent can't derive Send because on some operating systems, udata is defined | 
 | // as a void*.  However, KEvent's public API always treats udata as an intptr_t, | 
 | // which is safe to Send. | 
 | unsafe impl Send for KEvent { | 
 | } | 
 |  | 
 | impl KEvent { | 
 |     pub fn new(ident: uintptr_t, filter: EventFilter, flags: EventFlag, | 
 |                fflags:FilterFlag, data: intptr_t, udata: intptr_t) -> KEvent { | 
 |         KEvent { kevent: libc::kevent { | 
 |             ident, | 
 |             filter: filter as type_of_event_filter, | 
 |             flags: flags.bits(), | 
 |             fflags: fflags.bits(), | 
 |             data: data as type_of_data, | 
 |             udata: udata as type_of_udata | 
 |         } } | 
 |     } | 
 |  | 
 |     pub fn ident(&self) -> uintptr_t { | 
 |         self.kevent.ident | 
 |     } | 
 |  | 
 |     pub fn filter(&self) -> EventFilter { | 
 |         unsafe { mem::transmute(self.kevent.filter as type_of_event_filter) } | 
 |     } | 
 |  | 
 |     pub fn flags(&self) -> EventFlag { | 
 |         EventFlag::from_bits(self.kevent.flags).unwrap() | 
 |     } | 
 |  | 
 |     pub fn fflags(&self) -> FilterFlag { | 
 |         FilterFlag::from_bits(self.kevent.fflags).unwrap() | 
 |     } | 
 |  | 
 |     pub fn data(&self) -> intptr_t { | 
 |         self.kevent.data as intptr_t | 
 |     } | 
 |  | 
 |     pub fn udata(&self) -> intptr_t { | 
 |         self.kevent.udata as intptr_t | 
 |     } | 
 | } | 
 |  | 
 | pub fn kevent(kq: RawFd, | 
 |               changelist: &[KEvent], | 
 |               eventlist: &mut [KEvent], | 
 |               timeout_ms: usize) -> Result<usize> { | 
 |  | 
 |     // Convert ms to timespec | 
 |     let timeout = timespec { | 
 |         tv_sec: (timeout_ms / 1000) as time_t, | 
 |         tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long | 
 |     }; | 
 |  | 
 |     kevent_ts(kq, changelist, eventlist, Some(timeout)) | 
 | } | 
 |  | 
 | #[cfg(any(target_os = "macos", | 
 |           target_os = "ios", | 
 |           target_os = "freebsd", | 
 |           target_os = "dragonfly", | 
 |           target_os = "openbsd"))] | 
 | type type_of_nchanges = c_int; | 
 | #[cfg(target_os = "netbsd")] | 
 | type type_of_nchanges = size_t; | 
 |  | 
 | pub fn kevent_ts(kq: RawFd, | 
 |               changelist: &[KEvent], | 
 |               eventlist: &mut [KEvent], | 
 |               timeout_opt: Option<timespec>) -> Result<usize> { | 
 |  | 
 |     let res = unsafe { | 
 |         libc::kevent( | 
 |             kq, | 
 |             changelist.as_ptr() as *const libc::kevent, | 
 |             changelist.len() as type_of_nchanges, | 
 |             eventlist.as_mut_ptr() as *mut libc::kevent, | 
 |             eventlist.len() as type_of_nchanges, | 
 |             if let Some(ref timeout) = timeout_opt {timeout as *const timespec} else {ptr::null()}) | 
 |     }; | 
 |  | 
 |     Errno::result(res).map(|r| r as usize) | 
 | } | 
 |  | 
 | #[inline] | 
 | pub fn ev_set(ev: &mut KEvent, | 
 |               ident: usize, | 
 |               filter: EventFilter, | 
 |               flags: EventFlag, | 
 |               fflags: FilterFlag, | 
 |               udata: intptr_t) { | 
 |  | 
 |     ev.kevent.ident  = ident as uintptr_t; | 
 |     ev.kevent.filter = filter as type_of_event_filter; | 
 |     ev.kevent.flags  = flags.bits(); | 
 |     ev.kevent.fflags = fflags.bits(); | 
 |     ev.kevent.data   = 0; | 
 |     ev.kevent.udata  = udata as type_of_udata; | 
 | } | 
 |  | 
 | #[test] | 
 | fn test_struct_kevent() { | 
 |     let udata : intptr_t = 12345; | 
 |  | 
 |     let actual = KEvent::new(0xdead_beef, | 
 |                              EventFilter::EVFILT_READ, | 
 |                              EventFlag::EV_ONESHOT | EventFlag::EV_ADD, | 
 |                              FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, | 
 |                              0x1337, | 
 |                              udata); | 
 |     assert_eq!(0xdead_beef, actual.ident()); | 
 |     assert_eq!(libc::EVFILT_READ, actual.filter() as type_of_event_filter); | 
 |     assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits()); | 
 |     assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits()); | 
 |     assert_eq!(0x1337, actual.data() as type_of_data); | 
 |     assert_eq!(udata as type_of_udata, actual.udata() as type_of_udata); | 
 |     assert_eq!(mem::size_of::<libc::kevent>(), mem::size_of::<KEvent>()); | 
 | } |