[go: up one dir, main page]

magenta/
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 Magenta kernel
6//! [syscalls](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls.md).
7
8extern crate core;
9extern crate magenta_sys;
10
11use std::marker::PhantomData;
12
13macro_rules! impl_handle_based {
14    ($type_name:path) => {
15        impl AsHandleRef for $type_name {
16            fn as_handle_ref(&self) -> HandleRef {
17                self.0.as_handle_ref()
18            }
19        }
20
21        impl From<Handle> for $type_name {
22            fn from(handle: Handle) -> Self {
23                $type_name(handle)
24            }
25        }
26
27        impl Into<Handle> for $type_name {
28            fn into(self) -> Handle {
29                self.0
30            }
31        }
32
33        impl HandleBased for $type_name {}
34    }
35}
36
37mod channel;
38mod event;
39mod eventpair;
40mod fifo;
41mod job;
42mod port;
43mod process;
44mod socket;
45mod timer;
46mod thread;
47mod vmo;
48
49pub use channel::{Channel, ChannelOpts, MessageBuf};
50pub use event::{Event, EventOpts};
51pub use eventpair::{EventPair, EventPairOpts};
52pub use fifo::{Fifo, FifoOpts};
53pub use job::Job;
54pub use port::{Packet, PacketContents, Port, PortOpts, SignalPacket, UserPacket, WaitAsyncOpts};
55pub use process::Process;
56pub use socket::{Socket, SocketOpts, SocketReadOpts, SocketWriteOpts};
57pub use timer::{Timer, TimerOpts};
58pub use thread::Thread;
59pub use vmo::{Vmo, VmoCloneOpts, VmoOp, VmoOpts};
60
61use magenta_sys as sys;
62
63type Duration = sys::mx_duration_t;
64type Time = sys::mx_time_t;
65pub use magenta_sys::MX_TIME_INFINITE;
66
67// A placeholder value used for handles that have been taken from the message buf.
68// We rely on the kernel never to produce any actual handles with this value.
69const INVALID_HANDLE: sys::mx_handle_t = 0;
70
71/// A status code returned from the Magenta kernel.
72///
73/// See
74/// [errors.md](https://fuchsia.googlesource.com/magenta/+/master/docs/errors.md)
75/// in the Magenta documentation for more information about the meaning of these
76/// codes.
77#[derive(Debug, PartialEq, Eq, Clone, Copy)]
78#[repr(i32)]
79// Auto-generated using tools/gen_status.py
80pub enum Status {
81    NoError = 0,
82    ErrInternal = -1,
83    ErrNotSupported = -2,
84    ErrNoResources = -3,
85    ErrNoMemory = -4,
86    ErrCallFailed = -5,
87    ErrInterruptedRetry = -6,
88    ErrInvalidArgs = -10,
89    ErrBadHandle = -11,
90    ErrWrongType = -12,
91    ErrBadSyscall = -13,
92    ErrOutOfRange = -14,
93    ErrBufferTooSmall = -15,
94    ErrBadState = -20,
95    ErrTimedOut = -21,
96    ErrShouldWait = -22,
97    ErrCanceled = -23,
98    ErrPeerClosed = -24,
99    ErrNotFound = -25,
100    ErrAlreadyExists = -26,
101    ErrAlreadyBound = -27,
102    ErrUnavailable = -28,
103    ErrAccessDenied = -30,
104    ErrIo = -40,
105    ErrIoRefused = -41,
106    ErrIoDataIntegrity = -42,
107    ErrIoDataLoss = -43,
108    ErrBadPath = -50,
109    ErrNotDir = -51,
110    ErrNotFile = -52,
111    ErrFileBig = -53,
112    ErrNoSpace = -54,
113    ErrStop = -60,
114    ErrNext = -61,
115
116    /// Any mx_status_t not in the set above will map to the following:
117    UnknownOther = -32768,
118}
119
120impl Status {
121    pub fn from_raw(raw: sys::mx_status_t) -> Self {
122        match raw {
123            // Auto-generated using tools/gen_status.py
124            sys::MX_OK => Status::NoError,
125            sys::MX_ERR_INTERNAL => Status::ErrInternal,
126            sys::MX_ERR_NOT_SUPPORTED => Status::ErrNotSupported,
127            sys::MX_ERR_NO_RESOURCES => Status::ErrNoResources,
128            sys::MX_ERR_NO_MEMORY => Status::ErrNoMemory,
129            sys::MX_ERR_CALL_FAILED => Status::ErrCallFailed,
130            sys::MX_ERR_INTERRUPTED_RETRY => Status::ErrInterruptedRetry,
131            sys::MX_ERR_INVALID_ARGS => Status::ErrInvalidArgs,
132            sys::MX_ERR_BAD_HANDLE => Status::ErrBadHandle,
133            sys::MX_ERR_WRONG_TYPE => Status::ErrWrongType,
134            sys::MX_ERR_BAD_SYSCALL => Status::ErrBadSyscall,
135            sys::MX_ERR_OUT_OF_RANGE => Status::ErrOutOfRange,
136            sys::MX_ERR_BUFFER_TOO_SMALL => Status::ErrBufferTooSmall,
137            sys::MX_ERR_BAD_STATE => Status::ErrBadState,
138            sys::MX_ERR_TIMED_OUT => Status::ErrTimedOut,
139            sys::MX_ERR_SHOULD_WAIT => Status::ErrShouldWait,
140            sys::MX_ERR_CANCELED => Status::ErrCanceled,
141            sys::MX_ERR_PEER_CLOSED => Status::ErrPeerClosed,
142            sys::MX_ERR_NOT_FOUND => Status::ErrNotFound,
143            sys::MX_ERR_ALREADY_EXISTS => Status::ErrAlreadyExists,
144            sys::MX_ERR_ALREADY_BOUND => Status::ErrAlreadyBound,
145            sys::MX_ERR_UNAVAILABLE => Status::ErrUnavailable,
146            sys::MX_ERR_ACCESS_DENIED => Status::ErrAccessDenied,
147            sys::MX_ERR_IO => Status::ErrIo,
148            sys::MX_ERR_IO_REFUSED => Status::ErrIoRefused,
149            sys::MX_ERR_IO_DATA_INTEGRITY => Status::ErrIoDataIntegrity,
150            sys::MX_ERR_IO_DATA_LOSS => Status::ErrIoDataLoss,
151            sys::MX_ERR_BAD_PATH => Status::ErrBadPath,
152            sys::MX_ERR_NOT_DIR => Status::ErrNotDir,
153            sys::MX_ERR_NOT_FILE => Status::ErrNotFile,
154            sys::MX_ERR_FILE_BIG => Status::ErrFileBig,
155            sys::MX_ERR_NO_SPACE => Status::ErrNoSpace,
156            sys::MX_ERR_STOP => Status::ErrStop,
157            sys::MX_ERR_NEXT => Status::ErrNext,
158            _ => Status::UnknownOther,
159        }
160    }
161
162    // Note: no to_raw, even though it's easy to implement, partly because
163    // handling of UnknownOther would be tricky.
164}
165
166/// Rights associated with a handle.
167///
168/// See [rights.md](https://fuchsia.googlesource.com/magenta/+/master/docs/rights.md)
169/// for more information.
170pub type Rights = sys::mx_rights_t;
171pub use magenta_sys::{
172    MX_RIGHT_NONE,
173    MX_RIGHT_DUPLICATE,
174    MX_RIGHT_TRANSFER,
175    MX_RIGHT_READ,
176    MX_RIGHT_WRITE,
177    MX_RIGHT_EXECUTE,
178    MX_RIGHT_MAP,
179    MX_RIGHT_GET_PROPERTY,
180    MX_RIGHT_SET_PROPERTY,
181    MX_RIGHT_DEBUG,
182    MX_RIGHT_SAME_RIGHTS,
183};
184
185/// Signals that can be waited upon.
186///
187/// See
188/// [Objects and signals](https://fuchsia.googlesource.com/magenta/+/master/docs/concepts.md#Objects-and-Signals)
189/// in the Magenta kernel documentation. Note: the names of signals are still in flux.
190pub type Signals = sys::mx_signals_t;
191
192pub use magenta_sys::{
193        MX_SIGNAL_NONE,
194
195        MX_SIGNAL_HANDLE_CLOSED,
196        MX_SIGNAL_LAST_HANDLE,
197
198        MX_USER_SIGNAL_0,
199        MX_USER_SIGNAL_1,
200        MX_USER_SIGNAL_2,
201        MX_USER_SIGNAL_3,
202        MX_USER_SIGNAL_4,
203        MX_USER_SIGNAL_5,
204        MX_USER_SIGNAL_6,
205        MX_USER_SIGNAL_7,
206
207        // Event
208        MX_EVENT_SIGNALED,
209
210        // EventPair
211        MX_EPAIR_SIGNALED,
212        MX_EPAIR_CLOSED,
213
214        // Task signals (process, thread, job)
215        MX_TASK_TERMINATED,
216
217        // Channel
218        MX_CHANNEL_READABLE,
219        MX_CHANNEL_WRITABLE,
220        MX_CHANNEL_PEER_CLOSED,
221
222        // Socket
223        MX_SOCKET_READABLE,
224        MX_SOCKET_WRITABLE,
225        MX_SOCKET_PEER_CLOSED,
226
227        // Timer
228        MX_TIMER_SIGNALED,
229};
230
231/// A "wait item" containing a handle reference and information about what signals
232/// to wait on, and, on return from `object_wait_many`, which are pending.
233#[repr(C)]
234#[derive(Debug)]
235pub struct WaitItem<'a> {
236    /// The handle to wait on.
237    pub handle: HandleRef<'a>,
238    /// A set of signals to wait for.
239    pub waitfor: Signals,
240    /// The set of signals pending, on return of `object_wait_many`.
241    pub pending: Signals,
242}
243
244
245/// An identifier to select a particular clock. See
246/// [mx_time_get](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/time_get.md)
247/// for more information about the possible values.
248#[repr(u32)]
249#[derive(Debug, Copy, Clone, Eq, PartialEq)]
250pub enum ClockId {
251    /// The number of nanoseconds since the system was powered on. Corresponds to
252    /// `MX_CLOCK_MONOTONIC`.
253    Monotonic = 0,
254    /// The number of wall clock nanoseconds since the Unix epoch (midnight on January 1 1970) in
255    /// UTC. Corresponds to MX_CLOCK_UTC.
256    UTC = 1,
257    /// The number of nanoseconds the current thread has been running for. Corresponds to
258    /// MX_CLOCK_THREAD.
259    Thread = 2,
260}
261
262/// Get the current time, from the specific clock id.
263///
264/// Wraps the
265/// [mx_time_get](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/time_get.md)
266/// syscall.
267pub fn time_get(clock_id: ClockId) -> Time {
268    unsafe { sys::mx_time_get(clock_id as u32) }
269}
270
271/// Read the number of high-precision timer ticks since boot. These ticks may be processor cycles,
272/// high speed timer, profiling timer, etc. They are not guaranteed to continue advancing when the
273/// system is asleep.
274///
275/// Wraps the
276/// [mx_ticks_get](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/ticks_get.md)
277/// syscall.
278pub fn ticks_get() -> u64 {
279    unsafe { sys::mx_ticks_get() }
280}
281
282/// Compute a deadline for the time in the future that is the given `Duration` away.
283///
284/// Wraps the
285/// [mx_deadline_after](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/deadline_after.md)
286/// syscall.
287pub fn deadline_after(nanos: Duration) -> Time {
288    unsafe { sys::mx_deadline_after(nanos) }
289}
290
291/// Sleep until the given deadline.
292///
293/// Wraps the
294/// [mx_nanosleep](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/nanosleep.md)
295/// syscall.
296pub fn nanosleep(deadline: Time) {
297    unsafe { sys::mx_nanosleep(deadline); }
298}
299
300/// Return the number of high-precision timer ticks in a second.
301///
302/// Wraps the
303/// [mx_ticks_per_second](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/ticks_per_second.md)
304/// syscall.
305pub fn ticks_per_second() -> u64 {
306    unsafe { sys::mx_ticks_per_second() }
307}
308
309pub use magenta_sys::{
310    MX_CPRNG_DRAW_MAX_LEN,
311    MX_CPRNG_ADD_ENTROPY_MAX_LEN,
312};
313
314/// Draw random bytes from the kernel's CPRNG to fill the given buffer. Returns the actual number of
315/// bytes drawn, which may sometimes be less than the size of the buffer provided.
316///
317/// The buffer must have length less than `MX_CPRNG_DRAW_MAX_LEN`.
318///
319/// Wraps the
320/// [mx_cprng_draw](https://fuchsia.googlesource.com/magenta/+/HEAD/docs/syscalls/cprng_draw.md)
321/// syscall.
322pub fn cprng_draw(buffer: &mut [u8]) -> Result<usize, Status> {
323    let mut actual = 0;
324    let status = unsafe { sys::mx_cprng_draw(buffer.as_mut_ptr(), buffer.len(), &mut actual) };
325    into_result(status, || actual)
326}
327
328/// Mix the given entropy into the kernel CPRNG.
329///
330/// The buffer must have length less than `MX_CPRNG_ADD_ENTROPY_MAX_LEN`.
331///
332/// Wraps the
333/// [mx_cprng_add_entropy](https://fuchsia.googlesource.com/magenta/+/HEAD/docs/syscalls/cprng_add_entropy.md)
334/// syscall.
335pub fn cprng_add_entropy(buffer: &[u8]) -> Result<(), Status> {
336    let status = unsafe { sys::mx_cprng_add_entropy(buffer.as_ptr(), buffer.len()) };
337    into_result(status, || ())
338}
339
340fn into_result<T, F>(status: sys::mx_status_t, f: F) -> Result<T, Status>
341    where F: FnOnce() -> T {
342    // All non-negative values are assumed successful. Note: calls that don't try
343    // to multiplex success values into status return could be more strict here.
344    if status >= 0 {
345        Ok(f())
346    } else {
347        Err(Status::from_raw(status))
348    }
349}
350
351// Handles
352
353/// A borrowed reference to a `Handle`.
354///
355/// Mostly useful as part of a `WaitItem`.
356#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
357pub struct HandleRef<'a> {
358    handle: sys::mx_handle_t,
359    phantom: PhantomData<&'a sys::mx_handle_t>,
360}
361
362impl<'a> HandleRef<'a> {
363    pub fn raw_handle(&self) -> sys::mx_handle_t {
364        self.handle
365    }
366
367    pub fn duplicate(&self, rights: Rights) -> Result<Handle, Status> {
368        let handle = self.handle;
369        let mut out = 0;
370        let status = unsafe { sys::mx_handle_duplicate(handle, rights, &mut out) };
371        into_result(status, || Handle(out))
372    }
373
374    pub fn signal(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
375        let handle = self.handle;
376        let status = unsafe { sys::mx_object_signal(handle, clear_mask.bits(), set_mask.bits()) };
377        into_result(status, || ())
378    }
379
380    pub fn wait(&self, signals: Signals, deadline: Time) -> Result<Signals, Status> {
381        let handle = self.handle;
382        let mut pending = sys::mx_signals_t::empty();
383        let status = unsafe {
384            sys::mx_object_wait_one(handle, signals, deadline, &mut pending)
385        };
386        into_result(status, || pending)
387    }
388
389    pub fn wait_async(&self, port: &Port, key: u64, signals: Signals, options: WaitAsyncOpts)
390        -> Result<(), Status>
391    {
392        let handle = self.handle;
393        let status = unsafe {
394            sys::mx_object_wait_async(handle, port.raw_handle(), key, signals, options as u32)
395        };
396        into_result(status, || ())
397    }
398}
399
400/// A trait to get a reference to the underlying handle of an object.
401pub trait AsHandleRef {
402    /// Get a reference to the handle. One important use of such a reference is
403    /// for `object_wait_many`.
404    fn as_handle_ref(&self) -> HandleRef;
405
406    /// Interpret the reference as a raw handle (an integer type). Two distinct
407    /// handles will have different raw values (so it can perhaps be used as a
408    /// key in a data structure).
409    fn raw_handle(&self) -> sys::mx_handle_t {
410        self.as_handle_ref().raw_handle()
411    }
412
413    /// Set and clear userspace-accessible signal bits on an object. Wraps the
414    /// [mx_object_signal](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/object_signal.md)
415    /// syscall.
416    fn signal_handle(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
417        self.as_handle_ref().signal(clear_mask, set_mask)
418    }
419
420    /// Waits on a handle. Wraps the
421    /// [mx_object_wait_one](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/object_wait_one.md)
422    /// syscall.
423    fn wait_handle(&self, signals: Signals, deadline: Time) -> Result<Signals, Status> {
424        self.as_handle_ref().wait(signals, deadline)
425    }
426
427    /// Causes packet delivery on the given port when the object changes state and matches signals.
428    /// [mx_object_wait_async](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/object_wait_async.md)
429    /// syscall.
430    fn wait_async_handle(&self, port: &Port, key: u64, signals: Signals, options: WaitAsyncOpts)
431        -> Result<(), Status>
432    {
433        self.as_handle_ref().wait_async(port, key, signals, options)
434    }
435}
436
437impl<'a> AsHandleRef for HandleRef<'a> {
438    fn as_handle_ref(&self) -> HandleRef { *self }
439}
440
441/// A trait implemented by all handle-based types.
442///
443/// Note: it is reasonable for user-defined objects wrapping a handle to implement
444/// this trait. For example, a specific interface in some protocol might be
445/// represented as a newtype of `Channel`, and implement the `as_handle_ref`
446/// method and the `From<Handle>` trait to facilitate conversion from and to the
447/// interface.
448pub trait HandleBased: AsHandleRef + From<Handle> + Into<Handle> {
449    /// Duplicate a handle, possibly reducing the rights available. Wraps the
450    /// [mx_handle_duplicate](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/handle_duplicate.md)
451    /// syscall.
452    fn duplicate_handle(&self, rights: Rights) -> Result<Self, Status> {
453        self.as_handle_ref().duplicate(rights).map(|handle| Self::from(handle))
454    }
455
456    /// Create a replacement for a handle, possibly reducing the rights available. This invalidates
457    /// the original handle. Wraps the
458    /// [mx_handle_replace](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/handle_replace.md)
459    /// syscall.
460    fn replace_handle(self, rights: Rights) -> Result<Self, Status> {
461        <Self as Into<Handle>>::into(self)
462            .replace(rights).map(|handle| Self::from(handle))
463    }
464}
465
466/// A trait implemented by all handles for objects which have a peer.
467pub trait Peered: HandleBased {
468    /// Set and clear userspace-accessible signal bits on the object's peer. Wraps the
469    /// [mx_object_signal_peer](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/object_signal.md)
470    /// syscall.
471    fn signal_peer(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
472        let handle = self.as_handle_ref().handle;
473        let status = unsafe {
474            sys::mx_object_signal_peer(handle, clear_mask.bits(), set_mask.bits())
475        };
476        into_result(status, || ())
477    }
478}
479
480/// A trait implemented by all handles for objects which can have a cookie attached.
481pub trait Cookied: HandleBased {
482    /// Get the cookie attached to this object, if any. Wraps the
483    /// [mx_object_get_cookie](https://fuchsia.googlesource.com/magenta/+/HEAD/docs/syscalls/object_get_cookie.md)
484    /// syscall.
485    fn get_cookie(&self, scope: &HandleRef) -> Result<u64, Status> {
486        let handle = self.as_handle_ref().handle;
487        let mut cookie = 0;
488        let status = unsafe { sys::mx_object_get_cookie(handle, scope.handle, &mut cookie) };
489        into_result(status, || cookie)
490    }
491
492    /// Attach an opaque cookie to this object with the given scope. The cookie may be read or
493    /// changed in future only with the same scope. Wraps the
494    /// [mx_object_set_cookie](https://fuchsia.googlesource.com/magenta/+/HEAD/docs/syscalls/object_set_cookie.md)
495    /// syscall.
496    fn set_cookie(&self, scope: &HandleRef, cookie: u64) -> Result<(), Status> {
497        let handle = self.as_handle_ref().handle;
498        let status = unsafe { sys::mx_object_set_cookie(handle, scope.handle, cookie) };
499        into_result(status, || ())
500    }
501}
502
503fn handle_drop(handle: sys::mx_handle_t) {
504    let _ = unsafe { sys::mx_handle_close(handle) };
505}
506
507/// Wait on multiple handles.
508/// The success return value is a bool indicating whether one or more of the
509/// provided handle references was closed during the wait.
510///
511/// Wraps the
512/// [mx_object_wait_many](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/object_wait_many.md)
513/// syscall.
514pub fn object_wait_many(items: &mut [WaitItem], deadline: Time) -> Result<bool, Status>
515{
516    let len = try!(usize_into_u32(items.len()).map_err(|_| Status::ErrOutOfRange));
517    let items_ptr = items.as_mut_ptr() as *mut sys::mx_wait_item_t;
518    let status = unsafe { sys::mx_object_wait_many( items_ptr, len, deadline) };
519    if status == sys::MX_ERR_CANCELED {
520        return Ok((true))
521    }
522    into_result(status, || false)
523}
524
525// An untyped handle
526
527/// An object representing a Magenta
528/// [handle](https://fuchsia.googlesource.com/magenta/+/master/docs/handles.md).
529///
530/// Internally, it is represented as a 32-bit integer, but this wrapper enforces
531/// strict ownership semantics. The `Drop` implementation closes the handle.
532///
533/// This type represents the most general reference to a kernel object, and can
534/// be interconverted to and from more specific types. Those conversions are not
535/// enforced in the type system; attempting to use them will result in errors
536/// returned by the kernel. These conversions don't change the underlying
537/// representation, but do change the type and thus what operations are available.
538#[derive(Debug, Eq, PartialEq, Hash)]
539pub struct Handle(sys::mx_handle_t);
540
541impl AsHandleRef for Handle {
542    fn as_handle_ref(&self) -> HandleRef {
543        HandleRef { handle: self.0, phantom: Default::default() }
544    }
545}
546
547impl HandleBased for Handle {}
548
549impl Drop for Handle {
550    fn drop(&mut self) {
551        handle_drop(self.0)
552    }
553}
554
555impl Handle {
556    /// If a raw handle is obtained from some other source, this method converts
557    /// it into a type-safe owned handle.
558    pub unsafe fn from_raw(raw: sys::mx_handle_t) -> Handle {
559        Handle(raw)
560    }
561
562    pub fn replace(self, rights: Rights) -> Result<Handle, Status> {
563        let handle = self.0;
564        let mut out = 0;
565        let status = unsafe { sys::mx_handle_replace(handle, rights, &mut out) };
566        into_result(status, || Handle(out))
567    }
568}
569
570#[cfg(test)]
571mod tests {
572    use super::*;
573
574    #[test]
575    fn monotonic_time_increases() {
576        let time1 = time_get(ClockId::Monotonic);
577        nanosleep(deadline_after(1_000));
578        let time2 = time_get(ClockId::Monotonic);
579        assert!(time2 > time1);
580    }
581
582    #[test]
583    fn utc_time_increases() {
584        let time1 = time_get(ClockId::UTC);
585        nanosleep(deadline_after(1_000));
586        let time2 = time_get(ClockId::UTC);
587        assert!(time2 > time1);
588    }
589
590    #[test]
591    fn thread_time_increases() {
592        let time1 = time_get(ClockId::Thread);
593        nanosleep(deadline_after(1_000));
594        let time2 = time_get(ClockId::Thread);
595        assert!(time2 > time1);
596    }
597
598    #[test]
599    fn ticks_increases() {
600        let ticks1 = ticks_get();
601        nanosleep(deadline_after(1_000));
602        let ticks2 = ticks_get();
603        assert!(ticks2 > ticks1);
604    }
605
606    #[test]
607    fn tick_length() {
608        let sleep_ns = 1_000_000;  // 1ms
609        let one_second_ns = 1_000_000_000; // 1 second in ns
610        let ticks1 = ticks_get();
611        nanosleep(deadline_after(sleep_ns));
612        let ticks2 = ticks_get();
613        // The number of ticks should have increased by at least 1 ms worth
614        assert!(ticks2 > ticks1 + sleep_ns * ticks_per_second() / one_second_ns);
615        // And not more than 4 ms worth
616        assert!(ticks2 < ticks1 + 4 * sleep_ns * ticks_per_second() / one_second_ns);
617    }
618
619    #[test]
620    fn sleep() {
621        let sleep_ns = 1_000_000;  // 1ms
622        let time1 = time_get(ClockId::Monotonic);
623        nanosleep(deadline_after(sleep_ns));
624        let time2 = time_get(ClockId::Monotonic);
625        assert!(time2 > time1 + sleep_ns);
626    }
627
628    /// Test duplication by means of a VMO
629    #[test]
630    fn duplicate() {
631        let hello_length: usize = 5;
632
633        // Create a VMO and write some data to it.
634        let vmo = Vmo::create(hello_length as u64, VmoOpts::Default).unwrap();
635        assert!(vmo.write(b"hello", 0).is_ok());
636
637        // Replace, reducing rights to read.
638        let readonly_vmo = vmo.duplicate(MX_RIGHT_READ).unwrap();
639        // Make sure we can read but not write.
640        let mut read_vec = vec![0; hello_length];
641        assert_eq!(readonly_vmo.read(&mut read_vec, 0).unwrap(), hello_length);
642        assert_eq!(read_vec, b"hello");
643        assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ErrAccessDenied));
644
645        // Write new data to the original handle, and read it from the new handle
646        assert!(vmo.write(b"bye", 0).is_ok());
647        assert_eq!(readonly_vmo.read(&mut read_vec, 0).unwrap(), hello_length);
648        assert_eq!(read_vec, b"byelo");
649    }
650
651    // Test replace by means of a VMO
652    #[test]
653    fn replace() {
654        let hello_length: usize = 5;
655
656        // Create a VMO and write some data to it.
657        let vmo = Vmo::create(hello_length as u64, VmoOpts::Default).unwrap();
658        assert!(vmo.write(b"hello", 0).is_ok());
659
660        // Replace, reducing rights to read.
661        let readonly_vmo = vmo.replace(MX_RIGHT_READ).unwrap();
662        // Make sure we can read but not write.
663        let mut read_vec = vec![0; hello_length];
664        assert_eq!(readonly_vmo.read(&mut read_vec, 0).unwrap(), hello_length);
665        assert_eq!(read_vec, b"hello");
666        assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ErrAccessDenied));
667    }
668
669    #[test]
670    fn wait_and_signal() {
671        let event = Event::create(EventOpts::Default).unwrap();
672        let ten_ms: Duration = 10_000_000;
673
674        // Waiting on it without setting any signal should time out.
675        assert_eq!(event.wait(MX_USER_SIGNAL_0, deadline_after(ten_ms)), Err(Status::ErrTimedOut));
676
677        // If we set a signal, we should be able to wait for it.
678        assert!(event.signal(MX_SIGNAL_NONE, MX_USER_SIGNAL_0).is_ok());
679        assert_eq!(event.wait(MX_USER_SIGNAL_0, deadline_after(ten_ms)).unwrap(),
680            MX_USER_SIGNAL_0 | MX_SIGNAL_LAST_HANDLE);
681
682        // Should still work, signals aren't automatically cleared.
683        assert_eq!(event.wait(MX_USER_SIGNAL_0, deadline_after(ten_ms)).unwrap(),
684            MX_USER_SIGNAL_0 | MX_SIGNAL_LAST_HANDLE);
685
686        // Now clear it, and waiting should time out again.
687        assert!(event.signal(MX_USER_SIGNAL_0, MX_SIGNAL_NONE).is_ok());
688        assert_eq!(event.wait(MX_USER_SIGNAL_0, deadline_after(ten_ms)), Err(Status::ErrTimedOut));
689    }
690
691    #[test]
692    fn wait_many_and_signal() {
693        let ten_ms: Duration = 10_000_000;
694        let e1 = Event::create(EventOpts::Default).unwrap();
695        let e2 = Event::create(EventOpts::Default).unwrap();
696
697        // Waiting on them now should time out.
698        let mut items = vec![
699          WaitItem { handle: e1.as_handle_ref(), waitfor: MX_USER_SIGNAL_0, pending: MX_SIGNAL_NONE },
700          WaitItem { handle: e2.as_handle_ref(), waitfor: MX_USER_SIGNAL_1, pending: MX_SIGNAL_NONE },
701        ];
702        assert_eq!(object_wait_many(&mut items, deadline_after(ten_ms)), Err(Status::ErrTimedOut));
703        assert_eq!(items[0].pending, MX_SIGNAL_LAST_HANDLE);
704        assert_eq!(items[1].pending, MX_SIGNAL_LAST_HANDLE);
705
706        // Signal one object and it should return success.
707        assert!(e1.signal(MX_SIGNAL_NONE, MX_USER_SIGNAL_0).is_ok());
708        assert!(object_wait_many(&mut items, deadline_after(ten_ms)).is_ok());
709        assert_eq!(items[0].pending, MX_USER_SIGNAL_0 | MX_SIGNAL_LAST_HANDLE);
710        assert_eq!(items[1].pending, MX_SIGNAL_LAST_HANDLE);
711
712        // Signal the other and it should return both.
713        assert!(e2.signal(MX_SIGNAL_NONE, MX_USER_SIGNAL_1).is_ok());
714        assert!(object_wait_many(&mut items, deadline_after(ten_ms)).is_ok());
715        assert_eq!(items[0].pending, MX_USER_SIGNAL_0 | MX_SIGNAL_LAST_HANDLE);
716        assert_eq!(items[1].pending, MX_USER_SIGNAL_1 | MX_SIGNAL_LAST_HANDLE);
717
718        // Clear signals on both; now it should time out again.
719        assert!(e1.signal(MX_USER_SIGNAL_0, MX_SIGNAL_NONE).is_ok());
720        assert!(e2.signal(MX_USER_SIGNAL_1, MX_SIGNAL_NONE).is_ok());
721        assert_eq!(object_wait_many(&mut items, deadline_after(ten_ms)), Err(Status::ErrTimedOut));
722        assert_eq!(items[0].pending, MX_SIGNAL_LAST_HANDLE);
723        assert_eq!(items[1].pending, MX_SIGNAL_LAST_HANDLE);
724    }
725
726    #[test]
727    fn cookies() {
728        let event = Event::create(EventOpts::Default).unwrap();
729        let scope = Event::create(EventOpts::Default).unwrap();
730
731        // Getting a cookie when none has been set should fail.
732        assert_eq!(event.get_cookie(&scope.as_handle_ref()), Err(Status::ErrAccessDenied));
733
734        // Set a cookie.
735        assert_eq!(event.set_cookie(&scope.as_handle_ref(), 42), Ok(()));
736
737        // Should get it back....
738        assert_eq!(event.get_cookie(&scope.as_handle_ref()), Ok(42));
739
740        // but not with the wrong scope!
741        assert_eq!(event.get_cookie(&event.as_handle_ref()), Err(Status::ErrAccessDenied));
742
743        // Can change it, with the same scope...
744        assert_eq!(event.set_cookie(&scope.as_handle_ref(), 123), Ok(()));
745
746        // but not with a different scope.
747        assert_eq!(event.set_cookie(&event.as_handle_ref(), 123), Err(Status::ErrAccessDenied));
748    }
749
750    #[test]
751    fn cprng() {
752        let mut buffer = [0; 20];
753        assert_eq!(cprng_draw(&mut buffer), Ok(20));
754        assert_ne!(buffer[0], 0);
755        assert_ne!(buffer[19], 0);
756    }
757
758    #[test]
759    fn cprng_too_large() {
760        let mut buffer = [0; MX_CPRNG_DRAW_MAX_LEN + 1];
761        assert_eq!(cprng_draw(&mut buffer), Err(Status::ErrInvalidArgs));
762
763        for mut s in buffer.chunks_mut(MX_CPRNG_DRAW_MAX_LEN) {
764            assert_eq!(cprng_draw(&mut s), Ok(s.len()));
765        }
766    }
767
768    #[test]
769    fn cprng_add() {
770        let buffer = [0, 1, 2];
771        assert_eq!(cprng_add_entropy(&buffer), Ok(()));
772    }
773}
774
775pub fn usize_into_u32(n: usize) -> Result<u32, ()> {
776    if n > ::std::u32::MAX as usize || n < ::std::u32::MIN as usize {
777        return Err(())
778    }
779    Ok(n as u32)
780}
781
782pub fn size_to_u32_sat(n: usize) -> u32 {
783    if n > ::std::u32::MAX as usize {
784        return ::std::u32::MAX;
785    }
786    if n < ::std::u32::MIN as usize {
787        return ::std::u32::MIN;
788    }
789    n as u32
790}