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