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