1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! Type-safe bindings for Zircon kernel
6 //! [syscalls](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls.md).
7 
8 #![deny(warnings)]
9 
10 #[macro_use]
11 extern crate bitflags;
12 
13 pub extern crate fuchsia_zircon_sys as sys;
14 
15 #[deprecated(note="use fuchsia_zircon::sys::ZX_CPRNG_DRAW_MAX_LEN instead")]
16 #[doc(hidden)]
17 pub use sys::ZX_CPRNG_DRAW_MAX_LEN;
18 
19 // Implements the HandleBased traits for a Handle newtype struct
20 macro_rules! impl_handle_based {
21     ($type_name:path) => {
22         impl AsHandleRef for $type_name {
23             fn as_handle_ref(&self) -> HandleRef {
24                 self.0.as_handle_ref()
25             }
26         }
27 
28         impl From<Handle> for $type_name {
29             fn from(handle: Handle) -> Self {
30                 $type_name(handle)
31             }
32         }
33 
34         impl From<$type_name> for Handle {
35             fn from(x: $type_name) -> Handle {
36                 x.0
37             }
38         }
39 
40         impl HandleBased for $type_name {}
41     }
42 }
43 
44 // Creates associated constants of TypeName of the form
45 // `pub const NAME: TypeName = TypeName(value);`
46 macro_rules! assoc_consts {
47     ($typename:ident, [$($name:ident = $num:expr;)*]) => {
48         #[allow(non_upper_case_globals)]
49         impl $typename {
50             $(
51                 pub const $name: $typename = $typename($num);
52             )*
53         }
54     }
55 }
56 
57 mod channel;
58 mod cprng;
59 mod event;
60 mod eventpair;
61 mod fifo;
62 mod handle;
63 mod job;
64 mod port;
65 mod process;
66 mod rights;
67 mod socket;
68 mod signals;
69 mod status;
70 mod time;
71 mod thread;
72 mod vmar;
73 mod vmo;
74 
75 pub use channel::*;
76 pub use cprng::*;
77 pub use event::*;
78 pub use eventpair::*;
79 pub use fifo::*;
80 pub use handle::*;
81 pub use job::*;
82 pub use port::*;
83 pub use process::*;
84 pub use rights::*;
85 pub use socket::*;
86 pub use signals::*;
87 pub use status::*;
88 pub use thread::*;
89 pub use time::*;
90 pub use vmar::*;
91 pub use vmo::*;
92 
93 /// Prelude containing common utility traits.
94 /// Designed for use like `use fuchsia_zircon::prelude::*;`
95 pub mod prelude {
96     pub use {
97         AsHandleRef,
98         Cookied,
99         DurationNum,
100         HandleBased,
101         Peered,
102     };
103 }
104 
105 /// Convenience re-export of `Status::ok`.
ok(raw: sys::zx_status_t) -> Result<(), Status>106 pub fn ok(raw: sys::zx_status_t) -> Result<(), Status> {
107     Status::ok(raw)
108 }
109 
110 /// A "wait item" containing a handle reference and information about what signals
111 /// to wait on, and, on return from `object_wait_many`, which are pending.
112 #[repr(C)]
113 #[derive(Debug)]
114 pub struct WaitItem<'a> {
115     /// The handle to wait on.
116     pub handle: HandleRef<'a>,
117     /// A set of signals to wait for.
118     pub waitfor: Signals,
119     /// The set of signals pending, on return of `object_wait_many`.
120     pub pending: Signals,
121 }
122 
123 /// An identifier to select a particular clock. See
124 /// [zx_time_get](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/time_get.md)
125 /// for more information about the possible values.
126 #[repr(u32)]
127 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
128 pub enum ClockId {
129     /// The number of nanoseconds since the system was powered on. Corresponds to
130     /// `ZX_CLOCK_MONOTONIC`.
131     Monotonic = 0,
132     /// The number of wall clock nanoseconds since the Unix epoch (midnight on January 1 1970) in
133     /// UTC. Corresponds to ZX_CLOCK_UTC.
134     UTC = 1,
135     /// The number of nanoseconds the current thread has been running for. Corresponds to
136     /// ZX_CLOCK_THREAD.
137     Thread = 2,
138 }
139 
140 /// Wait on multiple handles.
141 /// The success return value is a bool indicating whether one or more of the
142 /// provided handle references was closed during the wait.
143 ///
144 /// Wraps the
145 /// [zx_object_wait_many](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/object_wait_many.md)
146 /// syscall.
object_wait_many(items: &mut [WaitItem], deadline: Time) -> Result<bool, Status>147 pub fn object_wait_many(items: &mut [WaitItem], deadline: Time) -> Result<bool, Status>
148 {
149     let len = try!(usize_into_u32(items.len()).map_err(|_| Status::OUT_OF_RANGE));
150     let items_ptr = items.as_mut_ptr() as *mut sys::zx_wait_item_t;
151     let status = unsafe { sys::zx_object_wait_many( items_ptr, len, deadline.nanos()) };
152     if status == sys::ZX_ERR_CANCELED {
153         return Ok(true)
154     }
155     ok(status).map(|()| false)
156 }
157 
158 #[cfg(test)]
159 mod tests {
160     use super::*;
161     #[allow(unused_imports)]
162     use super::prelude::*;
163 
164     #[test]
monotonic_time_increases()165     fn monotonic_time_increases() {
166         let time1 = Time::get(ClockId::Monotonic);
167         1_000.nanos().sleep();
168         let time2 = Time::get(ClockId::Monotonic);
169         assert!(time2 > time1);
170     }
171 
172     #[test]
utc_time_increases()173     fn utc_time_increases() {
174         let time1 = Time::get(ClockId::UTC);
175         1_000.nanos().sleep();
176         let time2 = Time::get(ClockId::UTC);
177         assert!(time2 > time1);
178     }
179 
180     #[test]
thread_time_increases()181     fn thread_time_increases() {
182         let time1 = Time::get(ClockId::Thread);
183         1_000.nanos().sleep();
184         let time2 = Time::get(ClockId::Thread);
185         assert!(time2 > time1);
186     }
187 
188     #[test]
ticks_increases()189     fn ticks_increases() {
190         let ticks1 = ticks_get();
191         1_000.nanos().sleep();
192         let ticks2 = ticks_get();
193         assert!(ticks2 > ticks1);
194     }
195 
196     #[test]
tick_length()197     fn tick_length() {
198         let sleep_time = 1.milli();
199         let ticks1 = ticks_get();
200         sleep_time.sleep();
201         let ticks2 = ticks_get();
202 
203         // The number of ticks should have increased by at least 1 ms worth
204         let sleep_ticks = sleep_time.millis() * ticks_per_second() / 1000;
205         assert!(ticks2 >= (ticks1 + sleep_ticks));
206     }
207 
208     #[test]
into_raw()209     fn into_raw() {
210         let vmo = Vmo::create(1).unwrap();
211         let h = vmo.into_raw();
212         let vmo2 = Vmo::from(unsafe { Handle::from_raw(h) });
213         assert!(vmo2.write(b"1", 0).is_ok());
214     }
215 
216     #[test]
sleep()217     fn sleep() {
218         let sleep_ns = 1.millis();
219         let time1 = Time::get(ClockId::Monotonic);
220         sleep_ns.sleep();
221         let time2 = Time::get(ClockId::Monotonic);
222         assert!(time2 > time1 + sleep_ns);
223     }
224 
225     /// Test duplication by means of a VMO
226     #[test]
duplicate()227     fn duplicate() {
228         let hello_length: usize = 5;
229 
230         // Create a VMO and write some data to it.
231         let vmo = Vmo::create(hello_length as u64).unwrap();
232         assert!(vmo.write(b"hello", 0).is_ok());
233 
234         // Replace, reducing rights to read.
235         let readonly_vmo = vmo.duplicate_handle(Rights::READ).unwrap();
236         // Make sure we can read but not write.
237         let mut read_vec = vec![0; hello_length];
238         assert_eq!(readonly_vmo.read(&mut read_vec, 0).unwrap(), hello_length);
239         assert_eq!(read_vec, b"hello");
240         assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED));
241 
242         // Write new data to the original handle, and read it from the new handle
243         assert!(vmo.write(b"bye", 0).is_ok());
244         assert_eq!(readonly_vmo.read(&mut read_vec, 0).unwrap(), hello_length);
245         assert_eq!(read_vec, b"byelo");
246     }
247 
248     // Test replace by means of a VMO
249     #[test]
replace()250     fn replace() {
251         let hello_length: usize = 5;
252 
253         // Create a VMO and write some data to it.
254         let vmo = Vmo::create(hello_length as u64).unwrap();
255         assert!(vmo.write(b"hello", 0).is_ok());
256 
257         // Replace, reducing rights to read.
258         let readonly_vmo = vmo.replace_handle(Rights::READ).unwrap();
259         // Make sure we can read but not write.
260         let mut read_vec = vec![0; hello_length];
261         assert_eq!(readonly_vmo.read(&mut read_vec, 0).unwrap(), hello_length);
262         assert_eq!(read_vec, b"hello");
263         assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED));
264     }
265 
266     #[test]
wait_and_signal()267     fn wait_and_signal() {
268         let event = Event::create().unwrap();
269         let ten_ms = 10.millis();
270 
271         // Waiting on it without setting any signal should time out.
272         assert_eq!(event.wait_handle(
273             Signals::USER_0, ten_ms.after_now()), Err(Status::TIMED_OUT));
274 
275         // If we set a signal, we should be able to wait for it.
276         assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok());
277         assert_eq!(event.wait_handle(Signals::USER_0, ten_ms.after_now()).unwrap(),
278             Signals::USER_0);
279 
280         // Should still work, signals aren't automatically cleared.
281         assert_eq!(event.wait_handle(Signals::USER_0, ten_ms.after_now()).unwrap(),
282             Signals::USER_0);
283 
284         // Now clear it, and waiting should time out again.
285         assert!(event.signal_handle(Signals::USER_0, Signals::NONE).is_ok());
286         assert_eq!(event.wait_handle(
287             Signals::USER_0, ten_ms.after_now()), Err(Status::TIMED_OUT));
288     }
289 
290     #[test]
wait_many_and_signal()291     fn wait_many_and_signal() {
292         let ten_ms = 10.millis();
293         let e1 = Event::create().unwrap();
294         let e2 = Event::create().unwrap();
295 
296         // Waiting on them now should time out.
297         let mut items = vec![
298           WaitItem { handle: e1.as_handle_ref(), waitfor: Signals::USER_0, pending: Signals::NONE },
299           WaitItem { handle: e2.as_handle_ref(), waitfor: Signals::USER_1, pending: Signals::NONE },
300         ];
301         assert_eq!(object_wait_many(&mut items, ten_ms.after_now()), Err(Status::TIMED_OUT));
302         assert_eq!(items[0].pending, Signals::NONE);
303         assert_eq!(items[1].pending, Signals::NONE);
304 
305         // Signal one object and it should return success.
306         assert!(e1.signal_handle(Signals::NONE, Signals::USER_0).is_ok());
307         assert!(object_wait_many(&mut items, ten_ms.after_now()).is_ok());
308         assert_eq!(items[0].pending, Signals::USER_0);
309         assert_eq!(items[1].pending, Signals::NONE);
310 
311         // Signal the other and it should return both.
312         assert!(e2.signal_handle(Signals::NONE, Signals::USER_1).is_ok());
313         assert!(object_wait_many(&mut items, ten_ms.after_now()).is_ok());
314         assert_eq!(items[0].pending, Signals::USER_0);
315         assert_eq!(items[1].pending, Signals::USER_1);
316 
317         // Clear signals on both; now it should time out again.
318         assert!(e1.signal_handle(Signals::USER_0, Signals::NONE).is_ok());
319         assert!(e2.signal_handle(Signals::USER_1, Signals::NONE).is_ok());
320         assert_eq!(object_wait_many(&mut items, ten_ms.after_now()), Err(Status::TIMED_OUT));
321         assert_eq!(items[0].pending, Signals::NONE);
322         assert_eq!(items[1].pending, Signals::NONE);
323     }
324 
325     #[test]
cookies()326     fn cookies() {
327         let event = Event::create().unwrap();
328         let scope = Event::create().unwrap();
329 
330         // Getting a cookie when none has been set should fail.
331         assert_eq!(event.get_cookie(&scope.as_handle_ref()), Err(Status::ACCESS_DENIED));
332 
333         // Set a cookie.
334         assert_eq!(event.set_cookie(&scope.as_handle_ref(), 42), Ok(()));
335 
336         // Should get it back....
337         assert_eq!(event.get_cookie(&scope.as_handle_ref()), Ok(42));
338 
339         // but not with the wrong scope!
340         assert_eq!(event.get_cookie(&event.as_handle_ref()), Err(Status::ACCESS_DENIED));
341 
342         // Can change it, with the same scope...
343         assert_eq!(event.set_cookie(&scope.as_handle_ref(), 123), Ok(()));
344 
345         // but not with a different scope.
346         assert_eq!(event.set_cookie(&event.as_handle_ref(), 123), Err(Status::ACCESS_DENIED));
347     }
348 }
349 
usize_into_u32(n: usize) -> Result<u32, ()>350 pub fn usize_into_u32(n: usize) -> Result<u32, ()> {
351     if n > ::std::u32::MAX as usize || n < ::std::u32::MIN as usize {
352         return Err(())
353     }
354     Ok(n as u32)
355 }
356 
size_to_u32_sat(n: usize) -> u32357 pub fn size_to_u32_sat(n: usize) -> u32 {
358     if n > ::std::u32::MAX as usize {
359         return ::std::u32::MAX;
360     }
361     if n < ::std::u32::MIN as usize {
362         return ::std::u32::MIN;
363     }
364     n as u32
365 }
366