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 #[repr(C)]
16 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
17 pub struct KEvent {
18 kevent: libc::kevent,
19 }
20
21 #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
22 target_os = "ios", target_os = "macos",
23 target_os = "openbsd"))]
24 type type_of_udata = *mut libc::c_void;
25 #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
26 target_os = "ios", target_os = "macos"))]
27 type type_of_data = intptr_t;
28 #[cfg(any(target_os = "netbsd"))]
29 type type_of_udata = intptr_t;
30 #[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
31 type type_of_data = libc::int64_t;
32
33 #[cfg(target_os = "netbsd")]
34 type type_of_event_filter = u32;
35 #[cfg(not(target_os = "netbsd"))]
36 type type_of_event_filter = i16;
37 libc_enum! {
38 #[cfg_attr(target_os = "netbsd", repr(u32))]
39 #[cfg_attr(not(target_os = "netbsd"), repr(i16))]
40 pub enum EventFilter {
41 EVFILT_AIO,
42 /// Returns whenever there is no remaining data in the write buffer
43 #[cfg(target_os = "freebsd")]
44 EVFILT_EMPTY,
45 #[cfg(target_os = "dragonfly")]
46 EVFILT_EXCEPT,
47 #[cfg(any(target_os = "dragonfly",
48 target_os = "freebsd",
49 target_os = "ios",
50 target_os = "macos"))]
51 EVFILT_FS,
52 #[cfg(target_os = "freebsd")]
53 EVFILT_LIO,
54 #[cfg(any(target_os = "ios", target_os = "macos"))]
55 EVFILT_MACHPORT,
56 EVFILT_PROC,
57 /// Returns events associated with the process referenced by a given
58 /// process descriptor, created by `pdfork()`. The events to monitor are:
59 ///
60 /// - NOTE_EXIT: the process has exited. The exit status will be stored in data.
61 #[cfg(target_os = "freebsd")]
62 EVFILT_PROCDESC,
63 EVFILT_READ,
64 /// Returns whenever an asynchronous `sendfile()` call completes.
65 #[cfg(target_os = "freebsd")]
66 EVFILT_SENDFILE,
67 EVFILT_SIGNAL,
68 EVFILT_TIMER,
69 #[cfg(any(target_os = "dragonfly",
70 target_os = "freebsd",
71 target_os = "ios",
72 target_os = "macos"))]
73 EVFILT_USER,
74 #[cfg(any(target_os = "ios", target_os = "macos"))]
75 EVFILT_VM,
76 EVFILT_VNODE,
77 EVFILT_WRITE,
78 }
79 }
80
81 #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
82 target_os = "ios", target_os = "macos",
83 target_os = "openbsd"))]
84 pub type type_of_event_flag = u16;
85 #[cfg(any(target_os = "netbsd"))]
86 pub type type_of_event_flag = u32;
87 libc_bitflags!{
88 pub struct EventFlag: type_of_event_flag {
89 EV_ADD;
90 EV_CLEAR;
91 EV_DELETE;
92 EV_DISABLE;
93 // No released version of OpenBSD supports EV_DISPATCH or EV_RECEIPT.
94 // These have been commited to the -current branch though and are
95 // expected to be part of the OpenBSD 6.2 release in Nov 2017.
96 // See: https://marc.info/?l=openbsd-tech&m=149621427511219&w=2
97 // https://github.com/rust-lang/libc/pull/613
98 #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
99 target_os = "ios", target_os = "macos",
100 target_os = "netbsd"))]
101 EV_DISPATCH;
102 #[cfg(target_os = "freebsd")]
103 EV_DROP;
104 EV_ENABLE;
105 EV_EOF;
106 EV_ERROR;
107 #[cfg(any(target_os = "macos", target_os = "ios"))]
108 EV_FLAG0;
109 EV_FLAG1;
110 #[cfg(target_os = "dragonfly")]
111 EV_NODATA;
112 EV_ONESHOT;
113 #[cfg(any(target_os = "macos", target_os = "ios"))]
114 EV_OOBAND;
115 #[cfg(any(target_os = "macos", target_os = "ios"))]
116 EV_POLL;
117 #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
118 target_os = "ios", target_os = "macos",
119 target_os = "netbsd"))]
120 EV_RECEIPT;
121 EV_SYSFLAGS;
122 }
123 }
124
125 libc_bitflags!(
126 pub struct FilterFlag: u32 {
127 #[cfg(any(target_os = "macos", target_os = "ios"))]
128 NOTE_ABSOLUTE;
129 NOTE_ATTRIB;
130 NOTE_CHILD;
131 NOTE_DELETE;
132 #[cfg(target_os = "openbsd")]
133 NOTE_EOF;
134 NOTE_EXEC;
135 NOTE_EXIT;
136 #[cfg(any(target_os = "macos", target_os = "ios"))]
137 #[deprecated( since="0.14.0", note="Deprecated since OSX 10.9")]
138 #[allow(deprecated)]
139 NOTE_EXIT_REPARENTED;
140 #[cfg(any(target_os = "macos", target_os = "ios"))]
141 NOTE_EXITSTATUS;
142 NOTE_EXTEND;
143 #[cfg(any(target_os = "macos",
144 target_os = "ios",
145 target_os = "freebsd",
146 target_os = "dragonfly"))]
147 NOTE_FFAND;
148 #[cfg(any(target_os = "macos",
149 target_os = "ios",
150 target_os = "freebsd",
151 target_os = "dragonfly"))]
152 NOTE_FFCOPY;
153 #[cfg(any(target_os = "macos",
154 target_os = "ios",
155 target_os = "freebsd",
156 target_os = "dragonfly"))]
157 NOTE_FFCTRLMASK;
158 #[cfg(any(target_os = "macos",
159 target_os = "ios",
160 target_os = "freebsd",
161 target_os = "dragonfly"))]
162 NOTE_FFLAGSMASK;
163 #[cfg(any(target_os = "macos",
164 target_os = "ios",
165 target_os = "freebsd",
166 target_os = "dragonfly"))]
167 NOTE_FFNOP;
168 #[cfg(any(target_os = "macos",
169 target_os = "ios",
170 target_os = "freebsd",
171 target_os = "dragonfly"))]
172 NOTE_FFOR;
173 NOTE_FORK;
174 NOTE_LINK;
175 NOTE_LOWAT;
176 #[cfg(target_os = "freebsd")]
177 NOTE_MSECONDS;
178 #[cfg(any(target_os = "macos", target_os = "ios"))]
179 NOTE_NONE;
180 #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
181 NOTE_NSECONDS;
182 #[cfg(target_os = "dragonfly")]
183 NOTE_OOB;
184 NOTE_PCTRLMASK;
185 NOTE_PDATAMASK;
186 #[cfg(any(target_os = "macos", target_os = "ios"))]
187 #[cfg(any(target_os = "macos", target_os = "ios"))]
188 #[deprecated( since="0.14.0", note="Deprecated since OSX 10.9")]
189 #[allow(deprecated)]
190 NOTE_REAP;
191 NOTE_RENAME;
192 NOTE_REVOKE;
193 #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
194 NOTE_SECONDS;
195 #[cfg(any(target_os = "macos", target_os = "ios"))]
196 NOTE_SIGNAL;
197 NOTE_TRACK;
198 NOTE_TRACKERR;
199 #[cfg(any(target_os = "macos",
200 target_os = "ios",
201 target_os = "freebsd",
202 target_os = "dragonfly"))]
203 NOTE_TRIGGER;
204 #[cfg(target_os = "openbsd")]
205 NOTE_TRUNCATE;
206 #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
207 NOTE_USECONDS;
208 #[cfg(any(target_os = "macos", target_os = "ios"))]
209 NOTE_VM_ERROR;
210 #[cfg(any(target_os = "macos", target_os = "ios"))]
211 NOTE_VM_PRESSURE;
212 #[cfg(any(target_os = "macos", target_os = "ios"))]
213 NOTE_VM_PRESSURE_SUDDEN_TERMINATE;
214 #[cfg(any(target_os = "macos", target_os = "ios"))]
215 NOTE_VM_PRESSURE_TERMINATE;
216 NOTE_WRITE;
217 }
218 );
219
kqueue() -> Result<RawFd>220 pub fn kqueue() -> Result<RawFd> {
221 let res = unsafe { libc::kqueue() };
222
223 Errno::result(res)
224 }
225
226
227 // KEvent can't derive Send because on some operating systems, udata is defined
228 // as a void*. However, KEvent's public API always treats udata as an intptr_t,
229 // which is safe to Send.
230 unsafe impl Send for KEvent {
231 }
232
233 impl KEvent {
new(ident: uintptr_t, filter: EventFilter, flags: EventFlag, fflags:FilterFlag, data: intptr_t, udata: intptr_t) -> KEvent234 pub fn new(ident: uintptr_t, filter: EventFilter, flags: EventFlag,
235 fflags:FilterFlag, data: intptr_t, udata: intptr_t) -> KEvent {
236 KEvent { kevent: libc::kevent {
237 ident,
238 filter: filter as type_of_event_filter,
239 flags: flags.bits(),
240 fflags: fflags.bits(),
241 data: data as type_of_data,
242 udata: udata as type_of_udata
243 } }
244 }
245
ident(&self) -> uintptr_t246 pub fn ident(&self) -> uintptr_t {
247 self.kevent.ident
248 }
249
filter(&self) -> EventFilter250 pub fn filter(&self) -> EventFilter {
251 unsafe { mem::transmute(self.kevent.filter as type_of_event_filter) }
252 }
253
flags(&self) -> EventFlag254 pub fn flags(&self) -> EventFlag {
255 EventFlag::from_bits(self.kevent.flags).unwrap()
256 }
257
fflags(&self) -> FilterFlag258 pub fn fflags(&self) -> FilterFlag {
259 FilterFlag::from_bits(self.kevent.fflags).unwrap()
260 }
261
data(&self) -> intptr_t262 pub fn data(&self) -> intptr_t {
263 self.kevent.data as intptr_t
264 }
265
udata(&self) -> intptr_t266 pub fn udata(&self) -> intptr_t {
267 self.kevent.udata as intptr_t
268 }
269 }
270
kevent(kq: RawFd, changelist: &[KEvent], eventlist: &mut [KEvent], timeout_ms: usize) -> Result<usize>271 pub fn kevent(kq: RawFd,
272 changelist: &[KEvent],
273 eventlist: &mut [KEvent],
274 timeout_ms: usize) -> Result<usize> {
275
276 // Convert ms to timespec
277 let timeout = timespec {
278 tv_sec: (timeout_ms / 1000) as time_t,
279 tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long
280 };
281
282 kevent_ts(kq, changelist, eventlist, Some(timeout))
283 }
284
285 #[cfg(any(target_os = "macos",
286 target_os = "ios",
287 target_os = "freebsd",
288 target_os = "dragonfly",
289 target_os = "openbsd"))]
290 type type_of_nchanges = c_int;
291 #[cfg(target_os = "netbsd")]
292 type type_of_nchanges = size_t;
293
kevent_ts(kq: RawFd, changelist: &[KEvent], eventlist: &mut [KEvent], timeout_opt: Option<timespec>) -> Result<usize>294 pub fn kevent_ts(kq: RawFd,
295 changelist: &[KEvent],
296 eventlist: &mut [KEvent],
297 timeout_opt: Option<timespec>) -> Result<usize> {
298
299 let res = unsafe {
300 libc::kevent(
301 kq,
302 changelist.as_ptr() as *const libc::kevent,
303 changelist.len() as type_of_nchanges,
304 eventlist.as_mut_ptr() as *mut libc::kevent,
305 eventlist.len() as type_of_nchanges,
306 if let Some(ref timeout) = timeout_opt {timeout as *const timespec} else {ptr::null()})
307 };
308
309 Errno::result(res).map(|r| r as usize)
310 }
311
312 #[inline]
ev_set(ev: &mut KEvent, ident: usize, filter: EventFilter, flags: EventFlag, fflags: FilterFlag, udata: intptr_t)313 pub fn ev_set(ev: &mut KEvent,
314 ident: usize,
315 filter: EventFilter,
316 flags: EventFlag,
317 fflags: FilterFlag,
318 udata: intptr_t) {
319
320 ev.kevent.ident = ident as uintptr_t;
321 ev.kevent.filter = filter as type_of_event_filter;
322 ev.kevent.flags = flags.bits();
323 ev.kevent.fflags = fflags.bits();
324 ev.kevent.data = 0;
325 ev.kevent.udata = udata as type_of_udata;
326 }
327
328 #[test]
test_struct_kevent()329 fn test_struct_kevent() {
330 let udata : intptr_t = 12345;
331
332 let actual = KEvent::new(0xdead_beef,
333 EventFilter::EVFILT_READ,
334 EventFlag::EV_ONESHOT | EventFlag::EV_ADD,
335 FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
336 0x1337,
337 udata);
338 assert_eq!(0xdead_beef, actual.ident());
339 assert_eq!(libc::EVFILT_READ, actual.filter() as type_of_event_filter);
340 assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits());
341 assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits());
342 assert_eq!(0x1337, actual.data() as type_of_data);
343 assert_eq!(udata as type_of_udata, actual.udata() as type_of_udata);
344 assert_eq!(mem::size_of::<libc::kevent>(), mem::size_of::<KEvent>());
345 }
346