fuchsia_zircon/
lib.rs

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]
11extern crate bitflags;
12
13pub extern crate fuchsia_zircon_sys as sys;
14
15#[deprecated(note="use fuchsia_zircon::sys::ZX_CPRNG_DRAW_MAX_LEN instead")]
16#[doc(hidden)]
17pub use sys::ZX_CPRNG_DRAW_MAX_LEN;
18
19// Implements the HandleBased traits for a Handle newtype struct
20macro_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);`
46macro_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
57mod channel;
58mod cprng;
59mod event;
60mod eventpair;
61mod fifo;
62mod handle;
63mod job;
64mod port;
65mod process;
66mod rights;
67mod socket;
68mod signals;
69mod status;
70mod time;
71mod thread;
72mod vmar;
73mod vmo;
74
75pub use channel::*;
76pub use cprng::*;
77pub use event::*;
78pub use eventpair::*;
79pub use fifo::*;
80pub use handle::*;
81pub use job::*;
82pub use port::*;
83pub use process::*;
84pub use rights::*;
85pub use socket::*;
86pub use signals::*;
87pub use status::*;
88pub use thread::*;
89pub use time::*;
90pub use vmar::*;
91pub use vmo::*;
92
93/// Prelude containing common utility traits.
94/// Designed for use like `use fuchsia_zircon::prelude::*;`
95pub 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`.
106pub 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)]
114pub 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)]
128pub 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.
147pub 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)]
159mod tests {
160    use super::*;
161    #[allow(unused_imports)]
162    use super::prelude::*;
163
164    #[test]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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
350pub 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
357pub 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}