1 /* TOOD: Implement for other kqueue based systems
2  */
3 
4 use {Errno, Result};
5 #[cfg(not(target_os = "netbsd"))]
6 use libc::{timespec, time_t, c_int, c_long, intptr_t, uintptr_t};
7 #[cfg(target_os = "netbsd")]
8 use libc::{timespec, time_t, c_long, intptr_t, uintptr_t, size_t};
9 use libc;
10 use std::os::unix::io::RawFd;
11 use std::ptr;
12 use std::mem;
13 
14 // Redefine kevent in terms of programmer-friendly enums and bitfields.
15 #[derive(Clone, Copy)]
16 #[repr(C)]
17 pub struct KEvent {
18     kevent: libc::kevent,
19 }
20 
21 #[cfg(any(target_os = "openbsd", target_os = "freebsd",
22           target_os = "dragonfly", target_os = "macos",
23           target_os = "ios"))]
24 type type_of_udata = *mut libc::c_void;
25 #[cfg(any(target_os = "openbsd", target_os = "freebsd",
26           target_os = "dragonfly", target_os = "macos",
27           target_os = "ios"))]
28 type type_of_data = libc::intptr_t;
29 #[cfg(any(target_os = "netbsd"))]
30 type type_of_udata = intptr_t;
31 #[cfg(any(target_os = "netbsd"))]
32 type type_of_data = libc::int64_t;
33 
34 #[cfg(not(target_os = "netbsd"))]
35 type type_of_event_filter = i16;
36 #[cfg(not(target_os = "netbsd"))]
37 #[repr(i16)]
38 #[derive(Clone, Copy, Debug, PartialEq)]
39 pub enum EventFilter {
40     EVFILT_AIO = libc::EVFILT_AIO,
41     #[cfg(target_os = "dragonfly")]
42     EVFILT_EXCEPT = libc::EVFILT_EXCEPT,
43     #[cfg(any(target_os = "macos", target_os = "ios",
44               target_os = "dragonfly",
45               target_os = "freebsd"))]
46     EVFILT_FS = libc::EVFILT_FS,
47     #[cfg(target_os = "freebsd")]
48     EVFILT_LIO = libc::EVFILT_LIO,
49     #[cfg(any(target_os = "macos", target_os = "ios"))]
50     EVFILT_MACHPORT = libc::EVFILT_MACHPORT,
51     EVFILT_PROC = libc::EVFILT_PROC,
52     EVFILT_READ = libc::EVFILT_READ,
53     EVFILT_SIGNAL = libc::EVFILT_SIGNAL,
54     EVFILT_TIMER = libc::EVFILT_TIMER,
55     #[cfg(any(target_os = "macos",
56               target_os = "ios",
57               target_os = "dragonfly",
58               target_os = "freebsd"))]
59     EVFILT_USER = libc::EVFILT_USER,
60     #[cfg(any(target_os = "macos", target_os = "ios"))]
61     EVFILT_VM = libc::EVFILT_VM,
62     EVFILT_VNODE = libc::EVFILT_VNODE,
63     EVFILT_WRITE = libc::EVFILT_WRITE,
64 }
65 
66 #[cfg(target_os = "netbsd")]
67 type type_of_event_filter = libc::uint32_t;
68 #[cfg(target_os = "netbsd")]
69 #[repr(i32)]
70 #[derive(Clone, Copy, Debug, PartialEq)]
71 pub enum EventFilter {
72     EVFILT_READ = libc::EVFILT_READ,
73     EVFILT_WRITE = libc::EVFILT_WRITE,
74     EVFILT_AIO = libc::EVFILT_AIO,
75     EVFILT_VNODE = libc::EVFILT_VNODE,
76     EVFILT_PROC = libc::EVFILT_PROC,
77     EVFILT_SIGNAL = libc::EVFILT_SIGNAL,
78     EVFILT_TIMER = libc::EVFILT_TIMER,
79 }
80 
81 #[cfg(any(target_os = "macos", target_os = "ios",
82           target_os = "freebsd", target_os = "dragonfly"))]
83 pub type type_of_event_flag = u16;
84 #[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
85 pub type type_of_event_flag = u32;
86 libc_bitflags!{
87     pub flags EventFlag: type_of_event_flag {
88         EV_ADD,
89         EV_CLEAR,
90         EV_DELETE,
91         EV_DISABLE,
92         EV_DISPATCH,
93         #[cfg(target_os = "freebsd")]
94         EV_DROP,
95         EV_ENABLE,
96         EV_EOF,
97         EV_ERROR,
98         #[cfg(any(target_os = "macos", target_os = "ios"))]
99         EV_FLAG0,
100         EV_FLAG1,
101         #[cfg(target_os = "dragonfly")]
102         EV_NODATA,
103         EV_ONESHOT,
104         #[cfg(any(target_os = "macos", target_os = "ios"))]
105         EV_OOBAND,
106         #[cfg(any(target_os = "macos", target_os = "ios"))]
107         EV_POLL,
108         #[cfg(not(target_os = "openbsd"))]
109         EV_RECEIPT,
110         EV_SYSFLAGS,
111     }
112 }
113 
114 libc_bitflags!(
115     pub flags FilterFlag: u32 {
116         #[cfg(any(target_os = "macos", target_os = "ios"))]
117         NOTE_ABSOLUTE,
118         NOTE_ATTRIB,
119         NOTE_CHILD,
120         NOTE_DELETE,
121         #[cfg(target_os = "openbsd")]
122         NOTE_EOF,
123         NOTE_EXEC,
124         NOTE_EXIT,
125         #[cfg(any(target_os = "macos", target_os = "ios"))]
126         NOTE_EXIT_REPARENTED,
127         #[cfg(any(target_os = "macos", target_os = "ios"))]
128         NOTE_EXITSTATUS,
129         NOTE_EXTEND,
130         #[cfg(any(target_os = "macos",
131                   target_os = "ios",
132                   target_os = "freebsd",
133                   target_os = "dragonfly"))]
134         NOTE_FFAND,
135         #[cfg(any(target_os = "macos",
136                   target_os = "ios",
137                   target_os = "freebsd",
138                   target_os = "dragonfly"))]
139         NOTE_FFCOPY,
140         #[cfg(any(target_os = "macos",
141                   target_os = "ios",
142                   target_os = "freebsd",
143                   target_os = "dragonfly"))]
144         NOTE_FFCTRLMASK,
145         #[cfg(any(target_os = "macos",
146                   target_os = "ios",
147                   target_os = "freebsd",
148                   target_os = "dragonfly"))]
149         NOTE_FFLAGSMASK,
150         #[cfg(any(target_os = "macos",
151                   target_os = "ios",
152                   target_os = "freebsd",
153                   target_os = "dragonfly"))]
154         NOTE_FFNOP,
155         #[cfg(any(target_os = "macos",
156                   target_os = "ios",
157                   target_os = "freebsd",
158                   target_os = "dragonfly"))]
159         NOTE_FFOR,
160         NOTE_FORK,
161         NOTE_LINK,
162         NOTE_LOWAT,
163         #[cfg(target_os = "freebsd")]
164         NOTE_MSECONDS,
165         #[cfg(any(target_os = "macos", target_os = "ios"))]
166         NOTE_NONE,
167         #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
168         NOTE_NSECONDS,
169         #[cfg(target_os = "dragonfly")]
170         NOTE_OOB,
171         NOTE_PCTRLMASK,
172         NOTE_PDATAMASK,
173         #[cfg(any(target_os = "macos", target_os = "ios"))]
174         NOTE_REAP,
175         NOTE_RENAME,
176         NOTE_REVOKE,
177         #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
178         NOTE_SECONDS,
179         #[cfg(any(target_os = "macos", target_os = "ios"))]
180         NOTE_SIGNAL,
181         NOTE_TRACK,
182         NOTE_TRACKERR,
183         #[cfg(any(target_os = "macos",
184                   target_os = "ios",
185                   target_os = "freebsd",
186                   target_os = "dragonfly"))]
187         NOTE_TRIGGER,
188         #[cfg(target_os = "openbsd")]
189         NOTE_TRUNCATE,
190         #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
191         NOTE_USECONDS,
192         #[cfg(any(target_os = "macos", target_os = "ios"))]
193         NOTE_VM_ERROR,
194         #[cfg(any(target_os = "macos", target_os = "ios"))]
195         NOTE_VM_PRESSURE,
196         #[cfg(any(target_os = "macos", target_os = "ios"))]
197         NOTE_VM_PRESSURE_SUDDEN_TERMINATE,
198         #[cfg(any(target_os = "macos", target_os = "ios"))]
199         NOTE_VM_PRESSURE_TERMINATE,
200         NOTE_WRITE,
201     }
202 );
203 
kqueue() -> Result<RawFd>204 pub fn kqueue() -> Result<RawFd> {
205     let res = unsafe { libc::kqueue() };
206 
207     Errno::result(res)
208 }
209 
210 
211 // KEvent can't derive Send because on some operating systems, udata is defined
212 // as a void*.  However, KEvent's public API always treats udata as an intptr_t,
213 // which is safe to Send.
214 unsafe impl Send for KEvent {
215 }
216 
217 impl KEvent {
new(ident: uintptr_t, filter: EventFilter, flags: EventFlag, fflags:FilterFlag, data: intptr_t, udata: intptr_t) -> KEvent218     pub fn new(ident: uintptr_t, filter: EventFilter, flags: EventFlag,
219                fflags:FilterFlag, data: intptr_t, udata: intptr_t) -> KEvent {
220         KEvent { kevent: libc::kevent {
221             ident: ident,
222             filter: filter as type_of_event_filter,
223             flags: flags.bits(),
224             fflags: fflags.bits(),
225             data: data as type_of_data,
226             udata: udata as type_of_udata
227         } }
228     }
229 
ident(&self) -> uintptr_t230     pub fn ident(&self) -> uintptr_t {
231         self.kevent.ident
232     }
233 
filter(&self) -> EventFilter234     pub fn filter(&self) -> EventFilter {
235         unsafe { mem::transmute(self.kevent.filter as type_of_event_filter) }
236     }
237 
flags(&self) -> EventFlag238     pub fn flags(&self) -> EventFlag {
239         EventFlag::from_bits(self.kevent.flags).unwrap()
240     }
241 
fflags(&self) -> FilterFlag242     pub fn fflags(&self) -> FilterFlag {
243         FilterFlag::from_bits(self.kevent.fflags).unwrap()
244     }
245 
data(&self) -> intptr_t246     pub fn data(&self) -> intptr_t {
247         self.kevent.data as intptr_t
248     }
249 
udata(&self) -> intptr_t250     pub fn udata(&self) -> intptr_t {
251         self.kevent.udata as intptr_t
252     }
253 }
254 
kevent(kq: RawFd, changelist: &[KEvent], eventlist: &mut [KEvent], timeout_ms: usize) -> Result<usize>255 pub fn kevent(kq: RawFd,
256               changelist: &[KEvent],
257               eventlist: &mut [KEvent],
258               timeout_ms: usize) -> Result<usize> {
259 
260     // Convert ms to timespec
261     let timeout = timespec {
262         tv_sec: (timeout_ms / 1000) as time_t,
263         tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long
264     };
265 
266     kevent_ts(kq, changelist, eventlist, Some(timeout))
267 }
268 
269 #[cfg(any(target_os = "macos",
270           target_os = "ios",
271           target_os = "freebsd",
272           target_os = "dragonfly",
273           target_os = "openbsd"))]
274 type type_of_nchanges = c_int;
275 #[cfg(target_os = "netbsd")]
276 type type_of_nchanges = size_t;
277 
kevent_ts(kq: RawFd, changelist: &[KEvent], eventlist: &mut [KEvent], timeout_opt: Option<timespec>) -> Result<usize>278 pub fn kevent_ts(kq: RawFd,
279               changelist: &[KEvent],
280               eventlist: &mut [KEvent],
281               timeout_opt: Option<timespec>) -> Result<usize> {
282 
283     let res = unsafe {
284         libc::kevent(
285             kq,
286             changelist.as_ptr() as *const libc::kevent,
287             changelist.len() as type_of_nchanges,
288             eventlist.as_mut_ptr() as *mut libc::kevent,
289             eventlist.len() as type_of_nchanges,
290             if let Some(ref timeout) = timeout_opt {timeout as *const timespec} else {ptr::null()})
291     };
292 
293     Errno::result(res).map(|r| r as usize)
294 }
295 
296 #[inline]
ev_set(ev: &mut KEvent, ident: usize, filter: EventFilter, flags: EventFlag, fflags: FilterFlag, udata: intptr_t)297 pub fn ev_set(ev: &mut KEvent,
298               ident: usize,
299               filter: EventFilter,
300               flags: EventFlag,
301               fflags: FilterFlag,
302               udata: intptr_t) {
303 
304     ev.kevent.ident  = ident as uintptr_t;
305     ev.kevent.filter = filter as type_of_event_filter;
306     ev.kevent.flags  = flags.bits();
307     ev.kevent.fflags = fflags.bits();
308     ev.kevent.data   = 0;
309     ev.kevent.udata  = udata as type_of_udata;
310 }
311 
312 #[test]
test_struct_kevent()313 fn test_struct_kevent() {
314     let udata : intptr_t = 12345;
315 
316     let expected = libc::kevent{ident: 0xdeadbeef,
317                                 filter: libc::EVFILT_READ,
318                                 flags: libc::EV_DISPATCH | libc::EV_ADD,
319                                 fflags: libc::NOTE_CHILD | libc::NOTE_EXIT,
320                                 data: 0x1337,
321                                 udata: udata as type_of_udata};
322     let actual = KEvent::new(0xdeadbeef,
323                              EventFilter::EVFILT_READ,
324                              EV_DISPATCH | EV_ADD,
325                              NOTE_CHILD | NOTE_EXIT,
326                              0x1337,
327                              udata);
328     assert!(expected.ident == actual.ident());
329     assert!(expected.filter == actual.filter() as type_of_event_filter);
330     assert!(expected.flags == actual.flags().bits());
331     assert!(expected.fflags == actual.fflags().bits());
332     assert!(expected.data == actual.data());
333     assert!(expected.udata == actual.udata() as type_of_udata);
334     assert!(mem::size_of::<libc::kevent>() == mem::size_of::<KEvent>());
335 }
336