fuchsia-zircon-0.3.3/BUILD.gn010064016041200011610000000006071322374737200140550ustar0000000000000000# Copyright 2017 The Fuchsia Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import("//build/rust/rust_library.gni") rust_library("fuchsia-zircon") { deps = [ "//garnet/public/rust/crates/fuchsia-zircon/fuchsia-zircon-sys", "//third_party/rust-crates:bitflags-0.7.0", ] with_tests = true } fuchsia-zircon-0.3.3/Cargo.toml.orig010064016041200011610000000005201322375115200155400ustar0000000000000000[package] name = "fuchsia-zircon" version = "0.3.3" license = "BSD-3-Clause" authors = ["Raph Levien "] description = "Rust bindings for the Zircon kernel" repository = "https://fuchsia.googlesource.com/garnet/" [dependencies] bitflags = "1.0.0" fuchsia-zircon-sys = { path = "fuchsia-zircon-sys", version = "0.3.3" } fuchsia-zircon-0.3.3/Cargo.toml0000644000000015200000000000000120160ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g. crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "fuchsia-zircon" version = "0.3.3" authors = ["Raph Levien "] description = "Rust bindings for the Zircon kernel" license = "BSD-3-Clause" repository = "https://fuchsia.googlesource.com/garnet/" [dependencies.bitflags] version = "1.0.0" [dependencies.fuchsia-zircon-sys] version = "0.3.3" fuchsia-zircon-0.3.3/LICENSE010064016041200011610000000030261322323014300136520ustar0000000000000000// Copyright 2016 The Fuchsia Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. fuchsia-zircon-0.3.3/README.md010064016041200011610000000011001322323014300141130ustar0000000000000000Rust bindings for Zircon kernel ================================ This repository contains Rust language bindings for Zircon kernel syscalls. The main crate contains type-safe wrappers, while the inner "sys" crate contains the raw types and FFI declarations. There are two ways to build Rust artifacts targeting Fuchsia; using the [Fargo](https://fuchsia.googlesource.com/fargo/) cross compiling tool or including your [artifact in the GN build](https://fuchsia.googlesource.com/docs/+/master/rust.md). Of the two, Fargo is likely better for exploration and experimentation. fuchsia-zircon-0.3.3/examples/BUILD.gn010064016041200011610000000005251322374737200156720ustar0000000000000000# Copyright 2017 The Fuchsia Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import("//build/package.gni") package("zircon_rust_examples") { system_image = true deps = [ "zx_toy", ] binaries = [ { name = "example_zx_toy" } ] } fuchsia-zircon-0.3.3/src/channel.rs010064016041200011610000000371161322323014300154210ustar0000000000000000// Copyright 2017 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //! Type-safe bindings for Zircon channel objects. use {AsHandleRef, HandleBased, Handle, HandleRef, Peered, Status, Time, usize_into_u32, size_to_u32_sat}; use {sys, ok}; use std::mem; /// An object representing a Zircon /// [channel](https://fuchsia.googlesource.com/zircon/+/master/docs/objects/channel.md). /// /// As essentially a subtype of `Handle`, it can be freely interconverted. #[derive(Debug, Eq, PartialEq, Hash)] pub struct Channel(Handle); impl_handle_based!(Channel); impl Peered for Channel {} impl Channel { /// Create a channel, resulting an a pair of `Channel` objects representing both /// sides of the channel. Messages written into one maybe read from the opposite. /// /// Wraps the /// [zx_channel_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/channel_create.md) /// syscall. pub fn create() -> Result<(Channel, Channel), Status> { unsafe { let mut handle0 = 0; let mut handle1 = 0; let opts = 0; ok(sys::zx_channel_create(opts, &mut handle0, &mut handle1))?; Ok(( Self::from(Handle::from_raw(handle0)), Self::from(Handle::from_raw(handle1)) )) } } /// Read a message from a channel. Wraps the /// [zx_channel_read](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/channel_read.md) /// syscall. /// /// If the `MessageBuf` lacks the capacity to hold the pending message, /// returns an `Err` with the number of bytes and number of handles needed. /// Otherwise returns an `Ok` with the result as usual. pub fn read_raw(&self, buf: &mut MessageBuf) -> Result, (usize, usize)> { let opts = 0; unsafe { buf.clear(); let raw_handle = self.raw_handle(); let mut num_bytes: u32 = size_to_u32_sat(buf.bytes.capacity()); let mut num_handles: u32 = size_to_u32_sat(buf.handles.capacity()); let status = ok(sys::zx_channel_read(raw_handle, opts, buf.bytes.as_mut_ptr(), buf.handles.as_mut_ptr() as *mut _, num_bytes, num_handles, &mut num_bytes, &mut num_handles)); if status == Err(Status::BUFFER_TOO_SMALL) { Err((num_bytes as usize, num_handles as usize)) } else { Ok(status.map(|()| { buf.bytes.set_len(num_bytes as usize); buf.handles.set_len(num_handles as usize); })) } } } /// Read a message from a channel. /// /// Note that this method can cause internal reallocations in the `MessageBuf` /// if it is lacks capacity to hold the full message. If such reallocations /// are not desirable, use `read_raw` instead. pub fn read(&self, buf: &mut MessageBuf) -> Result<(), Status> { loop { match self.read_raw(buf) { Ok(result) => return result, Err((num_bytes, num_handles)) => { buf.ensure_capacity_bytes(num_bytes); buf.ensure_capacity_handles(num_handles); } } } } /// Write a message to a channel. Wraps the /// [zx_channel_write](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/channel_write.md) /// syscall. pub fn write(&self, bytes: &[u8], handles: &mut Vec) -> Result<(), Status> { let opts = 0; let n_bytes = try!(usize_into_u32(bytes.len()).map_err(|_| Status::OUT_OF_RANGE)); let n_handles = try!(usize_into_u32(handles.len()).map_err(|_| Status::OUT_OF_RANGE)); unsafe { let status = sys::zx_channel_write(self.raw_handle(), opts, bytes.as_ptr(), n_bytes, handles.as_ptr() as *const sys::zx_handle_t, n_handles); ok(status)?; // Handles were successfully transferred, forget them on sender side handles.set_len(0); Ok(()) } } /// Send a message consisting of the given bytes and handles to a channel and await a reply. The /// bytes should start with a four byte 'txid' which is used to identify the matching reply. /// /// Wraps the /// [zx_channel_call](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/channel_call.md) /// syscall. /// /// Note that unlike [`read`][read], the caller must ensure that the MessageBuf has enough /// capacity for the bytes and handles which will be received, as replies which are too large /// are discarded. /// /// On failure returns the both the main and read status. /// /// [read]: struct.Channel.html#method.read pub fn call(&self, timeout: Time, bytes: &[u8], handles: &mut Vec, buf: &mut MessageBuf) -> Result<(), (Status, Status)> { let write_num_bytes = try!(usize_into_u32(bytes.len()).map_err( |_| (Status::OUT_OF_RANGE, Status::OK))); let write_num_handles = try!(usize_into_u32(handles.len()).map_err( |_| (Status::OUT_OF_RANGE, Status::OK))); buf.clear(); let read_num_bytes: u32 = size_to_u32_sat(buf.bytes.capacity()); let read_num_handles: u32 = size_to_u32_sat(buf.handles.capacity()); let args = sys::zx_channel_call_args_t { wr_bytes: bytes.as_ptr(), wr_handles: handles.as_ptr() as *const sys::zx_handle_t, rd_bytes: buf.bytes.as_mut_ptr(), rd_handles: buf.handles.as_mut_ptr() as *mut _, wr_num_bytes: write_num_bytes, wr_num_handles: write_num_handles, rd_num_bytes: read_num_bytes, rd_num_handles: read_num_handles, }; let mut actual_read_bytes: u32 = 0; let mut actual_read_handles: u32 = 0; let mut read_status = Status::OK.into_raw(); let options = 0; let status = unsafe { Status::from_raw( sys::zx_channel_call( self.raw_handle(), options, timeout.nanos(), &args, &mut actual_read_bytes, &mut actual_read_handles, &mut read_status)) }; match status { Status::OK | Status::TIMED_OUT | Status::CALL_FAILED => { // Handles were successfully transferred, // even if we didn't get a response, so forget // them on the sender side. unsafe { handles.set_len(0); } } _ => {} } unsafe { buf.bytes.set_len(actual_read_bytes as usize); buf.handles.set_len(actual_read_handles as usize); } if Status::OK == status { Ok(()) } else { Err((status, Status::from_raw(read_status))) } } } #[test] pub fn test_handle_repr() { assert_eq!(::std::mem::size_of::(), 4); assert_eq!(::std::mem::size_of::(), 4); assert_eq!(::std::mem::align_of::(), ::std::mem::align_of::()); // This test asserts that repr(transparent) still works for Handle -> zx_handle_t let n: Vec = vec![0, 100, 2<<32-1]; let v: Vec = n.iter().map(|h| unsafe { Handle::from_raw(*h) } ).collect(); for (handle, raw) in v.iter().zip(n.iter()) { unsafe { assert_eq!(*(handle as *const _ as *const [u8; 4]), *(raw as *const _ as *const [u8; 4])); } } for h in v.into_iter() { ::std::mem::forget(h); } } impl AsRef for Channel { fn as_ref(&self) -> &Self { &self } } /// A buffer for _receiving_ messages from a channel. /// /// A `MessageBuf` is essentially a byte buffer and a vector of /// handles, but move semantics for "taking" handles requires special handling. /// /// Note that for sending messages to a channel, the caller manages the buffers, /// using a plain byte slice and `Vec`. #[derive(Default)] #[derive(Debug)] pub struct MessageBuf { bytes: Vec, handles: Vec, } impl MessageBuf { /// Create a new, empty, message buffer. pub fn new() -> Self { Default::default() } /// Create a new non-empty message buffer. pub fn new_with(v: Vec, h: Vec) -> Self { Self{ bytes: v, handles: h, } } /// Ensure that the buffer has the capacity to hold at least `n_bytes` bytes. pub fn ensure_capacity_bytes(&mut self, n_bytes: usize) { ensure_capacity(&mut self.bytes, n_bytes); } /// Ensure that the buffer has the capacity to hold at least `n_handles` handles. pub fn ensure_capacity_handles(&mut self, n_handles: usize) { ensure_capacity(&mut self.handles, n_handles); } /// Ensure that at least n_bytes bytes are initialized (0 fill). pub fn ensure_initialized_bytes(&mut self, n_bytes: usize) { if n_bytes <= self.bytes.len() { return; } self.bytes.resize(n_bytes, 0); } /// Get a reference to the bytes of the message buffer, as a `&[u8]` slice. pub fn bytes(&self) -> &[u8] { self.bytes.as_slice() } /// The number of handles in the message buffer. Note this counts the number /// available when the message was received; `take_handle` does not affect /// the count. pub fn n_handles(&self) -> usize { self.handles.len() } /// Take the handle at the specified index from the message buffer. If the /// method is called again with the same index, it will return `None`, as /// will happen if the index exceeds the number of handles available. pub fn take_handle(&mut self, index: usize) -> Option { self.handles.get_mut(index).and_then(|handle| if handle.is_invalid() { None } else { Some(mem::replace(handle, Handle::invalid())) } ) } /// Clear the bytes and handles contained in the buf. This will drop any /// contained handles, resulting in their resources being freed. pub fn clear(&mut self) { self.bytes.clear(); self.handles.clear(); } } fn ensure_capacity(vec: &mut Vec, size: usize) { let len = vec.len(); if size > len { vec.reserve(size - len); } } #[cfg(test)] mod tests { use super::*; use {DurationNum, Rights, Signals, Vmo}; use std::thread; #[test] fn channel_basic() { let (p1, p2) = Channel::create().unwrap(); let mut empty = vec![]; assert!(p1.write(b"hello", &mut empty).is_ok()); let mut buf = MessageBuf::new(); assert!(p2.read(&mut buf).is_ok()); assert_eq!(buf.bytes(), b"hello"); } #[test] fn channel_read_raw_too_small() { let (p1, p2) = Channel::create().unwrap(); let mut empty = vec![]; assert!(p1.write(b"hello", &mut empty).is_ok()); let mut buf = MessageBuf::new(); let result = p2.read_raw(&mut buf); assert_eq!(result, Err((5, 0))); assert_eq!(buf.bytes(), b""); } #[test] fn channel_send_handle() { let hello_length: usize = 5; // Create a pair of channels and a virtual memory object. let (p1, p2) = Channel::create().unwrap(); let vmo = Vmo::create(hello_length as u64).unwrap(); // Duplicate VMO handle and send it down the channel. let duplicate_vmo_handle = vmo.duplicate_handle(Rights::SAME_RIGHTS).unwrap().into(); let mut handles_to_send: Vec = vec![duplicate_vmo_handle]; assert!(p1.write(b"", &mut handles_to_send).is_ok()); // Handle should be removed from vector. assert!(handles_to_send.is_empty()); // Read the handle from the receiving channel. let mut buf = MessageBuf::new(); assert!(p2.read(&mut buf).is_ok()); assert_eq!(buf.n_handles(), 1); // Take the handle from the buffer. let received_handle = buf.take_handle(0).unwrap(); // Should not affect number of handles. assert_eq!(buf.n_handles(), 1); // Trying to take it again should fail. assert!(buf.take_handle(0).is_none()); // Now to test that we got the right handle, try writing something to it... let received_vmo = Vmo::from(received_handle); assert_eq!(received_vmo.write(b"hello", 0).unwrap(), hello_length); // ... and reading it back from the original VMO. let mut read_vec = vec![0; hello_length]; assert_eq!(vmo.read(&mut read_vec, 0).unwrap(), hello_length); assert_eq!(read_vec, b"hello"); } #[test] fn channel_call_timeout() { let ten_ms = 10.millis(); // Create a pair of channels and a virtual memory object. let (p1, p2) = Channel::create().unwrap(); let vmo = Vmo::create(0 as u64).unwrap(); // Duplicate VMO handle and send it along with the call. let duplicate_vmo_handle = vmo.duplicate_handle(Rights::SAME_RIGHTS).unwrap().into(); let mut handles_to_send: Vec = vec![duplicate_vmo_handle]; let mut buf = MessageBuf::new(); assert_eq!(p1.call(ten_ms.after_now(), b"call", &mut handles_to_send, &mut buf), Err((Status::TIMED_OUT, Status::OK))); // Handle should be removed from vector even though we didn't get a response, as it was // still sent over the channel. assert!(handles_to_send.is_empty()); // Should be able to read call even though it timed out waiting for a response. let mut buf = MessageBuf::new(); assert!(p2.read(&mut buf).is_ok()); assert_eq!(buf.bytes(), b"call"); assert_eq!(buf.n_handles(), 1); } #[test] fn channel_call() { // Create a pair of channels let (p1, p2) = Channel::create().unwrap(); // create an mpsc channel for communicating the call data for later assertion let (tx, rx) = ::std::sync::mpsc::channel(); // Start a new thread to respond to the call. thread::spawn(move || { let mut buf = MessageBuf::new(); // if either the read or the write fail, this thread will panic, // resulting in tx being dropped, which will be noticed by the rx. p2.wait_handle(Signals::CHANNEL_READABLE, 1.seconds().after_now()).expect("callee wait error"); p2.read(&mut buf).expect("callee read error"); p2.write(b"txidresponse", &mut vec![]).expect("callee write error"); tx.send(buf).expect("callee mpsc send error"); }); // Make the call. let mut buf = MessageBuf::new(); buf.ensure_capacity_bytes(12); // NOTE(raggi): CQ has been seeing some long stalls from channel call, // and it's as yet unclear why. The timeout here has been made much // larger in order to avoid that, as the issues are not issues with this // crate's concerns. The timeout is here just to prevent the tests from // stalling forever if a developer makes a mistake locally in this // crate. Tests of Zircon behavior or virtualization behavior should be // covered elsewhere. See ZX-1324. p1.call(30.seconds().after_now(), b"txidcall", &mut vec![], &mut buf).expect("channel call error"); assert_eq!(buf.bytes(), b"txidresponse"); assert_eq!(buf.n_handles(), 0); let sbuf = rx.recv().expect("mpsc channel recv error"); assert_eq!(sbuf.bytes(), b"txidcall"); assert_eq!(sbuf.n_handles(), 0); } } fuchsia-zircon-0.3.3/src/cprng.rs010064016041200011610000000040571322323014300151200ustar0000000000000000use {Status, ok, sys}; /// Draw random bytes from the kernel's CPRNG to fill the given buffer. Returns the actual number of /// bytes drawn, which may sometimes be less than the size of the buffer provided. /// /// The buffer must have length less than `ZX_CPRNG_DRAW_MAX_LEN`. /// /// Wraps the /// [zx_cprng_draw](https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/cprng_draw.md) /// syscall. pub fn cprng_draw(buffer: &mut [u8]) -> Result { let mut actual = 0; let status = unsafe { sys::zx_cprng_draw(buffer.as_mut_ptr(), buffer.len(), &mut actual) }; ok(status).map(|()| actual) } /// Mix the given entropy into the kernel CPRNG. /// /// The buffer must have length less than `ZX_CPRNG_ADD_ENTROPY_MAX_LEN`. /// /// Wraps the /// [zx_cprng_add_entropy](https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/cprng_add_entropy.md) /// syscall. pub fn cprng_add_entropy(buffer: &[u8]) -> Result<(), Status> { let status = unsafe { sys::zx_cprng_add_entropy(buffer.as_ptr(), buffer.len()) }; ok(status) } #[cfg(test)] mod tests { use super::*; #[test] fn cprng() { let mut buffer = [0; 20]; assert_eq!(cprng_draw(&mut buffer), Ok(20)); let mut first_zero = 0; let mut last_zero = 0; for _ in 0..30 { let mut buffer = [0; 20]; assert_eq!(cprng_draw(&mut buffer), Ok(20)); if buffer[0] == 0 { first_zero += 1; } if buffer[19] == 0 { last_zero += 1; } } assert_ne!(first_zero, 30); assert_ne!(last_zero, 30); } #[test] fn cprng_too_large() { let mut buffer = [0; sys::ZX_CPRNG_DRAW_MAX_LEN + 1]; assert_eq!(cprng_draw(&mut buffer), Err(Status::INVALID_ARGS)); for mut s in buffer.chunks_mut(sys::ZX_CPRNG_DRAW_MAX_LEN) { assert_eq!(cprng_draw(&mut s), Ok(s.len())); } } #[test] fn cprng_add() { let buffer = [0, 1, 2]; assert_eq!(cprng_add_entropy(&buffer), Ok(())); } }fuchsia-zircon-0.3.3/src/event.rs010064016041200011610000000021321322323014300151200ustar0000000000000000// Copyright 2017 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //! Type-safe bindings for Zircon event objects. use {AsHandleRef, Cookied, HandleBased, Handle, HandleRef, Status}; use {sys, ok}; /// An object representing a Zircon /// [event object](https://fuchsia.googlesource.com/zircon/+/master/docs/objects/event.md). /// /// As essentially a subtype of `Handle`, it can be freely interconverted. #[derive(Debug, Eq, PartialEq)] pub struct Event(Handle); impl_handle_based!(Event); impl Cookied for Event {} impl Event { /// Create an event object, an object which is signalable but nothing else. Wraps the /// [zx_event_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/event_create.md) /// syscall. pub fn create() -> Result { let mut out = 0; let opts = 0; let status = unsafe { sys::zx_event_create(opts, &mut out) }; ok(status)?; unsafe { Ok(Self::from(Handle::from_raw(out))) } } } fuchsia-zircon-0.3.3/src/eventpair.rs010064016041200011610000000045641322323014300160070ustar0000000000000000// Copyright 2016 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //! Type-safe bindings for Zircon event pairs. use {AsHandleRef, Cookied, HandleBased, Handle, HandleRef, Peered, Status}; use {sys, ok}; /// An object representing a Zircon /// [event pair](https://fuchsia.googlesource.com/zircon/+/master/docs/concepts.md#Other-IPC_Events_Event-Pairs_and-User-Signals). /// /// As essentially a subtype of `Handle`, it can be freely interconverted. #[derive(Debug, Eq, PartialEq)] pub struct EventPair(Handle); impl_handle_based!(EventPair); impl Peered for EventPair {} impl Cookied for EventPair {} impl EventPair { /// Create an event pair, a pair of objects which can signal each other. Wraps the /// [zx_eventpair_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/eventpair_create.md) /// syscall. pub fn create() -> Result<(EventPair, EventPair), Status> { let mut out0 = 0; let mut out1 = 0; let options = 0; let status = unsafe { sys::zx_eventpair_create(options, &mut out0, &mut out1) }; ok(status)?; unsafe { Ok(( Self::from(Handle::from_raw(out0)), Self::from(Handle::from_raw(out1)) )) } } } #[cfg(test)] mod tests { use super::*; use {DurationNum, Signals}; #[test] fn wait_and_signal_peer() { let (p1, p2) = EventPair::create().unwrap(); let eighty_ms = 80.millis(); // Waiting on one without setting any signal should time out. assert_eq!(p2.wait_handle(Signals::USER_0, eighty_ms.after_now()), Err(Status::TIMED_OUT)); // If we set a signal, we should be able to wait for it. assert!(p1.signal_peer(Signals::NONE, Signals::USER_0).is_ok()); assert_eq!(p2.wait_handle(Signals::USER_0, eighty_ms.after_now()).unwrap(), Signals::USER_0); // Should still work, signals aren't automatically cleared. assert_eq!(p2.wait_handle(Signals::USER_0, eighty_ms.after_now()).unwrap(), Signals::USER_0); // Now clear it, and waiting should time out again. assert!(p1.signal_peer(Signals::USER_0, Signals::NONE).is_ok()); assert_eq!(p2.wait_handle(Signals::USER_0, eighty_ms.after_now()), Err(Status::TIMED_OUT)); } } fuchsia-zircon-0.3.3/src/fifo.rs010064016041200011610000000072151322323014300147310ustar0000000000000000// Copyright 2017 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //! Type-safe bindings for Zircon fifo objects. use {AsHandleRef, HandleBased, Handle, HandleRef, Status}; use {sys, ok}; /// An object representing a Zircon fifo. /// /// As essentially a subtype of `Handle`, it can be freely interconverted. #[derive(Debug, Eq, PartialEq)] pub struct Fifo(Handle); impl_handle_based!(Fifo); impl Fifo { /// Create a pair of fifos and return their endpoints. Writing to one endpoint enqueues an /// element into the fifo from which the opposing endpoint reads. Wraps the /// [zx_fifo_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/fifo_create.md) /// syscall. pub fn create(elem_count: u32, elem_size: u32) -> Result<(Fifo, Fifo), Status> { let mut out0 = 0; let mut out1 = 0; let options = 0; let status = unsafe { sys::zx_fifo_create(elem_count, elem_size, options, &mut out0, &mut out1) }; ok(status)?; unsafe { Ok(( Self::from(Handle::from_raw(out0)), Self::from(Handle::from_raw(out1)) ))} } /// Attempts to write some number of elements into the fifo. The number of bytes written will be /// rounded down to a multiple of the fifo's element size. /// Return value (on success) is number of elements actually written. /// /// Wraps /// [zx_fifo_write](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/fifo_write.md). pub fn write(&self, bytes: &[u8]) -> Result { let mut num_entries_written = 0; let status = unsafe { sys::zx_fifo_write(self.raw_handle(), bytes.as_ptr(), bytes.len(), &mut num_entries_written) }; ok(status).map(|()| num_entries_written) } /// Attempts to read some number of elements out of the fifo. The number of bytes read will /// always be a multiple of the fifo's element size. /// Return value (on success) is number of elements actually read. /// /// Wraps /// [zx_fifo_read](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/fifo_read.md). pub fn read(&self, bytes: &mut [u8]) -> Result { let mut num_entries_read = 0; let status = unsafe { sys::zx_fifo_read(self.raw_handle(), bytes.as_mut_ptr(), bytes.len(), &mut num_entries_read) }; ok(status).map(|()| num_entries_read) } } #[cfg(test)] mod tests { use super::*; #[test] fn fifo_basic() { let (fifo1, fifo2) = Fifo::create(4, 2).unwrap(); // Trying to write less than one element should fail. assert_eq!(fifo1.write(b""), Err(Status::OUT_OF_RANGE)); assert_eq!(fifo1.write(b"h"), Err(Status::OUT_OF_RANGE)); // Should write one element "he" and ignore the last half-element as it rounds down. assert_eq!(fifo1.write(b"hex").unwrap(), 1); // Should write three elements "ll" "o " "wo" and drop the rest as it is full. assert_eq!(fifo1.write(b"llo worlds").unwrap(), 3); // Now that the fifo is full any further attempts to write should fail. assert_eq!(fifo1.write(b"blah blah"), Err(Status::SHOULD_WAIT)); // Read all 4 entries from the other end. let mut read_vec = vec![0; 8]; assert_eq!(fifo2.read(&mut read_vec).unwrap(), 4); assert_eq!(read_vec, b"hello wo"); // Reading again should fail as the fifo is empty. assert_eq!(fifo2.read(&mut read_vec), Err(Status::SHOULD_WAIT)); } } fuchsia-zircon-0.3.3/src/handle.rs010064016041200011610000000223671322323014300152460ustar0000000000000000use {Port, Rights, Signals, Status, Time, WaitAsyncOpts, ok, sys}; use std::marker::PhantomData; use std::mem; /// An object representing a Zircon /// [handle](https://fuchsia.googlesource.com/zircon/+/master/docs/handles.md). /// /// Internally, it is represented as a 32-bit integer, but this wrapper enforces /// strict ownership semantics. The `Drop` implementation closes the handle. /// /// This type represents the most general reference to a kernel object, and can /// be interconverted to and from more specific types. Those conversions are not /// enforced in the type system; attempting to use them will result in errors /// returned by the kernel. These conversions don't change the underlying /// representation, but do change the type and thus what operations are available. #[derive(Debug, Eq, PartialEq, Hash)] pub struct Handle(sys::zx_handle_t); impl AsHandleRef for Handle { fn as_handle_ref(&self) -> HandleRef { HandleRef { handle: self.0, phantom: Default::default() } } } impl HandleBased for Handle {} impl Drop for Handle { fn drop(&mut self) { if self.0 != sys::ZX_HANDLE_INVALID { unsafe { sys::zx_handle_close(self.0) }; } } } impl Handle { /// Initialize a handle backed by ZX_HANDLE_INVALID, the only safe non-handle. pub fn invalid() -> Handle { Handle(sys::ZX_HANDLE_INVALID) } /// If a raw handle is obtained from some other source, this method converts /// it into a type-safe owned handle. pub unsafe fn from_raw(raw: sys::zx_handle_t) -> Handle { Handle(raw) } pub fn is_invalid(&self) -> bool { self.0 == sys::ZX_HANDLE_INVALID } pub fn replace(self, rights: Rights) -> Result { let handle = self.0; let mut out = 0; let status = unsafe { sys::zx_handle_replace(handle, rights.bits(), &mut out) }; ok(status).map(|()| Handle(out)) } } /// A borrowed reference to a `Handle`. /// /// Mostly useful as part of a `WaitItem`. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub struct HandleRef<'a> { handle: sys::zx_handle_t, phantom: PhantomData<&'a sys::zx_handle_t>, } impl<'a> HandleRef<'a> { pub fn raw_handle(&self) -> sys::zx_handle_t { self.handle } pub fn duplicate(&self, rights: Rights) -> Result { let handle = self.handle; let mut out = 0; let status = unsafe { sys::zx_handle_duplicate(handle, rights.bits(), &mut out) }; ok(status).map(|()| Handle(out)) } pub fn signal(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> { let handle = self.handle; let status = unsafe { sys::zx_object_signal(handle, clear_mask.bits(), set_mask.bits()) }; ok(status) } pub fn wait(&self, signals: Signals, deadline: Time) -> Result { let handle = self.handle; let mut pending = Signals::empty().bits(); let status = unsafe { sys::zx_object_wait_one(handle, signals.bits(), deadline.nanos(), &mut pending) }; ok(status).map(|()| Signals::from_bits_truncate(pending)) } pub fn wait_async(&self, port: &Port, key: u64, signals: Signals, options: WaitAsyncOpts) -> Result<(), Status> { let handle = self.handle; let status = unsafe { sys::zx_object_wait_async( handle, port.raw_handle(), key, signals.bits(), options as u32) }; ok(status) } } /// A trait to get a reference to the underlying handle of an object. pub trait AsHandleRef { /// Get a reference to the handle. One important use of such a reference is /// for `object_wait_many`. fn as_handle_ref(&self) -> HandleRef; /// Interpret the reference as a raw handle (an integer type). Two distinct /// handles will have different raw values (so it can perhaps be used as a /// key in a data structure). fn raw_handle(&self) -> sys::zx_handle_t { self.as_handle_ref().raw_handle() } /// Set and clear userspace-accessible signal bits on an object. Wraps the /// [zx_object_signal](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/object_signal.md) /// syscall. fn signal_handle(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> { self.as_handle_ref().signal(clear_mask, set_mask) } /// Waits on a handle. Wraps the /// [zx_object_wait_one](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/object_wait_one.md) /// syscall. fn wait_handle(&self, signals: Signals, deadline: Time) -> Result { self.as_handle_ref().wait(signals, deadline) } /// Causes packet delivery on the given port when the object changes state and matches signals. /// [zx_object_wait_async](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/object_wait_async.md) /// syscall. fn wait_async_handle(&self, port: &Port, key: u64, signals: Signals, options: WaitAsyncOpts) -> Result<(), Status> { self.as_handle_ref().wait_async(port, key, signals, options) } } impl<'a> AsHandleRef for HandleRef<'a> { fn as_handle_ref(&self) -> HandleRef { *self } } /// A trait implemented by all handle-based types. /// /// Note: it is reasonable for user-defined objects wrapping a handle to implement /// this trait. For example, a specific interface in some protocol might be /// represented as a newtype of `Channel`, and implement the `as_handle_ref` /// method and the `From` trait to facilitate conversion from and to the /// interface. pub trait HandleBased: AsHandleRef + From + Into { /// Duplicate a handle, possibly reducing the rights available. Wraps the /// [zx_handle_duplicate](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/handle_duplicate.md) /// syscall. fn duplicate_handle(&self, rights: Rights) -> Result { self.as_handle_ref().duplicate(rights).map(|handle| Self::from(handle)) } /// Create a replacement for a handle, possibly reducing the rights available. This invalidates /// the original handle. Wraps the /// [zx_handle_replace](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/handle_replace.md) /// syscall. fn replace_handle(self, rights: Rights) -> Result { >::into(self) .replace(rights).map(|handle| Self::from(handle)) } /// Converts the value into its inner handle. /// /// This is a convenience function which simply forwards to the `Into` trait. fn into_handle(self) -> Handle { self.into() } /// Converts the handle into it's raw representation. /// /// The caller takes ownership over the raw handle, and must close or transfer it to avoid a handle leak. fn into_raw(self) -> sys::zx_handle_t { let h = self.into_handle(); let r = h.0; mem::forget(h); r } /// Creates an instance of this type from a handle. /// /// This is a convenience function which simply forwards to the `From` trait. fn from_handle(handle: Handle) -> Self { Self::from(handle) } /// Creates an instance of another handle-based type from this value's inner handle. fn into_handle_based(self) -> H { H::from_handle(self.into_handle()) } /// Creates an instance of this type from the inner handle of another /// handle-based type. fn from_handle_based(h: H) -> Self { Self::from_handle(h.into_handle()) } } /// A trait implemented by all handles for objects which have a peer. pub trait Peered: HandleBased { /// Set and clear userspace-accessible signal bits on the object's peer. Wraps the /// [zx_object_signal_peer](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/object_signal.md) /// syscall. fn signal_peer(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> { let handle = self.as_handle_ref().handle; let status = unsafe { sys::zx_object_signal_peer(handle, clear_mask.bits(), set_mask.bits()) }; ok(status) } } /// A trait implemented by all handles for objects which can have a cookie attached. pub trait Cookied: HandleBased { /// Get the cookie attached to this object, if any. Wraps the /// [zx_object_get_cookie](https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/object_get_cookie.md) /// syscall. fn get_cookie(&self, scope: &HandleRef) -> Result { let handle = self.as_handle_ref().handle; let mut cookie = 0; let status = unsafe { sys::zx_object_get_cookie(handle, scope.handle, &mut cookie) }; ok(status).map(|()| cookie) } /// Attach an opaque cookie to this object with the given scope. The cookie may be read or /// changed in future only with the same scope. Wraps the /// [zx_object_set_cookie](https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/object_set_cookie.md) /// syscall. fn set_cookie(&self, scope: &HandleRef, cookie: u64) -> Result<(), Status> { let handle = self.as_handle_ref().handle; let status = unsafe { sys::zx_object_set_cookie(handle, scope.handle, cookie) }; ok(status) } } fuchsia-zircon-0.3.3/src/job.rs010064016041200011610000000007111322323014300145520ustar0000000000000000// Copyright 2017 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //! Type-safe bindings for Zircon job. use {AsHandleRef, HandleBased, Handle, HandleRef}; /// An object representing a Zircon job. /// /// As essentially a subtype of `Handle`, it can be freely interconverted. #[derive(Debug, Eq, PartialEq)] pub struct Job(Handle); impl_handle_based!(Job);fuchsia-zircon-0.3.3/src/lib.rs010064016041200011610000000265431322374774600146070ustar0000000000000000// Copyright 2016 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //! Type-safe bindings for Zircon kernel //! [syscalls](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls.md). #![deny(warnings)] #[macro_use] extern crate bitflags; pub extern crate fuchsia_zircon_sys as sys; #[deprecated(note="use fuchsia_zircon::sys::ZX_CPRNG_DRAW_MAX_LEN instead")] #[doc(hidden)] pub use sys::ZX_CPRNG_DRAW_MAX_LEN; // Implements the HandleBased traits for a Handle newtype struct macro_rules! impl_handle_based { ($type_name:path) => { impl AsHandleRef for $type_name { fn as_handle_ref(&self) -> HandleRef { self.0.as_handle_ref() } } impl From for $type_name { fn from(handle: Handle) -> Self { $type_name(handle) } } impl From<$type_name> for Handle { fn from(x: $type_name) -> Handle { x.0 } } impl HandleBased for $type_name {} } } // Creates associated constants of TypeName of the form // `pub const NAME: TypeName = TypeName(value);` macro_rules! assoc_consts { ($typename:ident, [$($name:ident = $num:expr;)*]) => { #[allow(non_upper_case_globals)] impl $typename { $( pub const $name: $typename = $typename($num); )* } } } mod channel; mod cprng; mod event; mod eventpair; mod fifo; mod handle; mod job; mod port; mod process; mod rights; mod socket; mod signals; mod status; mod time; mod thread; mod vmar; mod vmo; pub use channel::*; pub use cprng::*; pub use event::*; pub use eventpair::*; pub use fifo::*; pub use handle::*; pub use job::*; pub use port::*; pub use process::*; pub use rights::*; pub use socket::*; pub use signals::*; pub use status::*; pub use thread::*; pub use time::*; pub use vmar::*; pub use vmo::*; /// Prelude containing common utility traits. /// Designed for use like `use fuchsia_zircon::prelude::*;` pub mod prelude { pub use { AsHandleRef, Cookied, DurationNum, HandleBased, Peered, }; } /// Convenience re-export of `Status::ok`. pub fn ok(raw: sys::zx_status_t) -> Result<(), Status> { Status::ok(raw) } /// A "wait item" containing a handle reference and information about what signals /// to wait on, and, on return from `object_wait_many`, which are pending. #[repr(C)] #[derive(Debug)] pub struct WaitItem<'a> { /// The handle to wait on. pub handle: HandleRef<'a>, /// A set of signals to wait for. pub waitfor: Signals, /// The set of signals pending, on return of `object_wait_many`. pub pending: Signals, } /// An identifier to select a particular clock. See /// [zx_time_get](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/time_get.md) /// for more information about the possible values. #[repr(u32)] #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum ClockId { /// The number of nanoseconds since the system was powered on. Corresponds to /// `ZX_CLOCK_MONOTONIC`. Monotonic = 0, /// The number of wall clock nanoseconds since the Unix epoch (midnight on January 1 1970) in /// UTC. Corresponds to ZX_CLOCK_UTC. UTC = 1, /// The number of nanoseconds the current thread has been running for. Corresponds to /// ZX_CLOCK_THREAD. Thread = 2, } /// Wait on multiple handles. /// The success return value is a bool indicating whether one or more of the /// provided handle references was closed during the wait. /// /// Wraps the /// [zx_object_wait_many](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/object_wait_many.md) /// syscall. pub fn object_wait_many(items: &mut [WaitItem], deadline: Time) -> Result { let len = try!(usize_into_u32(items.len()).map_err(|_| Status::OUT_OF_RANGE)); let items_ptr = items.as_mut_ptr() as *mut sys::zx_wait_item_t; let status = unsafe { sys::zx_object_wait_many( items_ptr, len, deadline.nanos()) }; if status == sys::ZX_ERR_CANCELED { return Ok(true) } ok(status).map(|()| false) } #[cfg(test)] mod tests { use super::*; #[allow(unused_imports)] use super::prelude::*; #[test] fn monotonic_time_increases() { let time1 = Time::get(ClockId::Monotonic); 1_000.nanos().sleep(); let time2 = Time::get(ClockId::Monotonic); assert!(time2 > time1); } #[test] fn utc_time_increases() { let time1 = Time::get(ClockId::UTC); 1_000.nanos().sleep(); let time2 = Time::get(ClockId::UTC); assert!(time2 > time1); } #[test] fn thread_time_increases() { let time1 = Time::get(ClockId::Thread); 1_000.nanos().sleep(); let time2 = Time::get(ClockId::Thread); assert!(time2 > time1); } #[test] fn ticks_increases() { let ticks1 = ticks_get(); 1_000.nanos().sleep(); let ticks2 = ticks_get(); assert!(ticks2 > ticks1); } #[test] fn tick_length() { let sleep_time = 1.milli(); let ticks1 = ticks_get(); sleep_time.sleep(); let ticks2 = ticks_get(); // The number of ticks should have increased by at least 1 ms worth let sleep_ticks = sleep_time.millis() * ticks_per_second() / 1000; assert!(ticks2 >= (ticks1 + sleep_ticks)); } #[test] fn into_raw() { let vmo = Vmo::create(1).unwrap(); let h = vmo.into_raw(); let vmo2 = Vmo::from(unsafe { Handle::from_raw(h) }); assert!(vmo2.write(b"1", 0).is_ok()); } #[test] fn sleep() { let sleep_ns = 1.millis(); let time1 = Time::get(ClockId::Monotonic); sleep_ns.sleep(); let time2 = Time::get(ClockId::Monotonic); assert!(time2 > time1 + sleep_ns); } /// Test duplication by means of a VMO #[test] fn duplicate() { let hello_length: usize = 5; // Create a VMO and write some data to it. let vmo = Vmo::create(hello_length as u64).unwrap(); assert!(vmo.write(b"hello", 0).is_ok()); // Replace, reducing rights to read. let readonly_vmo = vmo.duplicate_handle(Rights::READ).unwrap(); // Make sure we can read but not write. let mut read_vec = vec![0; hello_length]; assert_eq!(readonly_vmo.read(&mut read_vec, 0).unwrap(), hello_length); assert_eq!(read_vec, b"hello"); assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED)); // Write new data to the original handle, and read it from the new handle assert!(vmo.write(b"bye", 0).is_ok()); assert_eq!(readonly_vmo.read(&mut read_vec, 0).unwrap(), hello_length); assert_eq!(read_vec, b"byelo"); } // Test replace by means of a VMO #[test] fn replace() { let hello_length: usize = 5; // Create a VMO and write some data to it. let vmo = Vmo::create(hello_length as u64).unwrap(); assert!(vmo.write(b"hello", 0).is_ok()); // Replace, reducing rights to read. let readonly_vmo = vmo.replace_handle(Rights::READ).unwrap(); // Make sure we can read but not write. let mut read_vec = vec![0; hello_length]; assert_eq!(readonly_vmo.read(&mut read_vec, 0).unwrap(), hello_length); assert_eq!(read_vec, b"hello"); assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED)); } #[test] fn wait_and_signal() { let event = Event::create().unwrap(); let ten_ms = 10.millis(); // Waiting on it without setting any signal should time out. assert_eq!(event.wait_handle( Signals::USER_0, ten_ms.after_now()), Err(Status::TIMED_OUT)); // If we set a signal, we should be able to wait for it. assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); assert_eq!(event.wait_handle(Signals::USER_0, ten_ms.after_now()).unwrap(), Signals::USER_0); // Should still work, signals aren't automatically cleared. assert_eq!(event.wait_handle(Signals::USER_0, ten_ms.after_now()).unwrap(), Signals::USER_0); // Now clear it, and waiting should time out again. assert!(event.signal_handle(Signals::USER_0, Signals::NONE).is_ok()); assert_eq!(event.wait_handle( Signals::USER_0, ten_ms.after_now()), Err(Status::TIMED_OUT)); } #[test] fn wait_many_and_signal() { let ten_ms = 10.millis(); let e1 = Event::create().unwrap(); let e2 = Event::create().unwrap(); // Waiting on them now should time out. let mut items = vec![ WaitItem { handle: e1.as_handle_ref(), waitfor: Signals::USER_0, pending: Signals::NONE }, WaitItem { handle: e2.as_handle_ref(), waitfor: Signals::USER_1, pending: Signals::NONE }, ]; assert_eq!(object_wait_many(&mut items, ten_ms.after_now()), Err(Status::TIMED_OUT)); assert_eq!(items[0].pending, Signals::NONE); assert_eq!(items[1].pending, Signals::NONE); // Signal one object and it should return success. assert!(e1.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); assert!(object_wait_many(&mut items, ten_ms.after_now()).is_ok()); assert_eq!(items[0].pending, Signals::USER_0); assert_eq!(items[1].pending, Signals::NONE); // Signal the other and it should return both. assert!(e2.signal_handle(Signals::NONE, Signals::USER_1).is_ok()); assert!(object_wait_many(&mut items, ten_ms.after_now()).is_ok()); assert_eq!(items[0].pending, Signals::USER_0); assert_eq!(items[1].pending, Signals::USER_1); // Clear signals on both; now it should time out again. assert!(e1.signal_handle(Signals::USER_0, Signals::NONE).is_ok()); assert!(e2.signal_handle(Signals::USER_1, Signals::NONE).is_ok()); assert_eq!(object_wait_many(&mut items, ten_ms.after_now()), Err(Status::TIMED_OUT)); assert_eq!(items[0].pending, Signals::NONE); assert_eq!(items[1].pending, Signals::NONE); } #[test] fn cookies() { let event = Event::create().unwrap(); let scope = Event::create().unwrap(); // Getting a cookie when none has been set should fail. assert_eq!(event.get_cookie(&scope.as_handle_ref()), Err(Status::ACCESS_DENIED)); // Set a cookie. assert_eq!(event.set_cookie(&scope.as_handle_ref(), 42), Ok(())); // Should get it back.... assert_eq!(event.get_cookie(&scope.as_handle_ref()), Ok(42)); // but not with the wrong scope! assert_eq!(event.get_cookie(&event.as_handle_ref()), Err(Status::ACCESS_DENIED)); // Can change it, with the same scope... assert_eq!(event.set_cookie(&scope.as_handle_ref(), 123), Ok(())); // but not with a different scope. assert_eq!(event.set_cookie(&event.as_handle_ref(), 123), Err(Status::ACCESS_DENIED)); } } pub fn usize_into_u32(n: usize) -> Result { if n > ::std::u32::MAX as usize || n < ::std::u32::MIN as usize { return Err(()) } Ok(n as u32) } pub fn size_to_u32_sat(n: usize) -> u32 { if n > ::std::u32::MAX as usize { return ::std::u32::MAX; } if n < ::std::u32::MIN as usize { return ::std::u32::MIN; } n as u32 } fuchsia-zircon-0.3.3/src/port.rs010064016041200011610000000307001322323014300147650ustar0000000000000000// Copyright 2017 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //! Type-safe bindings for Zircon port objects. use std::mem; use {AsHandleRef, HandleBased, Handle, HandleRef, Signals, Status, Time}; use {sys, ok}; /// An object representing a Zircon /// [port](https://fuchsia.googlesource.com/zircon/+/master/docs/objects/port.md). /// /// As essentially a subtype of `Handle`, it can be freely interconverted. #[derive(Debug, Eq, PartialEq)] pub struct Port(Handle); impl_handle_based!(Port); /// A packet sent through a port. This is a type-safe wrapper for /// [zx_port_packet_t](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_wait.md). #[derive(PartialEq, Eq, Debug)] pub struct Packet(sys::zx_port_packet_t); /// The contents of a `Packet`. #[derive(Debug, Copy, Clone)] pub enum PacketContents { /// A user-generated packet. User(UserPacket), /// A one-shot signal packet generated via `object_wait_async`. SignalOne(SignalPacket), /// A repeating signal packet generated via `object_wait_async`. SignalRep(SignalPacket), #[doc(hidden)] __Nonexhaustive } /// Contents of a user packet (one sent by `port_queue`). This is a type-safe wrapper for /// [zx_packet_user_t](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_wait.md). #[derive(Debug, Copy, Clone)] pub struct UserPacket(sys::zx_packet_user_t); /// Contents of a signal packet (one generated by the kernel). This is a type-safe wrapper for /// [zx_packet_signal_t](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_wait.md). #[derive(Debug, Copy, Clone)] pub struct SignalPacket(sys::zx_packet_signal_t); impl Packet { /// Creates a new packet with `UserPacket` data. pub fn from_user_packet(key: u64, status: i32, user: UserPacket) -> Packet { Packet( sys::zx_port_packet_t { key: key, packet_type: sys::zx_packet_type_t::ZX_PKT_TYPE_USER, status: status, union: user.0, } ) } /// The packet's key. pub fn key(&self) -> u64 { self.0.key } /// The packet's status. // TODO: should this type be wrapped? pub fn status(&self) -> i32 { self.0.status } /// The contents of the packet. pub fn contents(&self) -> PacketContents { if self.0.packet_type == sys::zx_packet_type_t::ZX_PKT_TYPE_USER { PacketContents::User(UserPacket(self.0.union)) } else if self.0.packet_type == sys::zx_packet_type_t::ZX_PKT_TYPE_SIGNAL_ONE { PacketContents::SignalOne(SignalPacket(unsafe { mem::transmute_copy(&self.0.union) })) } else if self.0.packet_type == sys::zx_packet_type_t::ZX_PKT_TYPE_SIGNAL_REP { PacketContents::SignalRep(SignalPacket(unsafe { mem::transmute_copy(&self.0.union) })) } else { panic!("unexpected packet type"); } } } impl UserPacket { pub fn from_u8_array(val: [u8; 32]) -> UserPacket { UserPacket(val) } pub fn as_u8_array(&self) -> &[u8; 32] { &self.0 } pub fn as_mut_u8_array(&mut self) -> &mut [u8; 32] { &mut self.0 } } impl SignalPacket { /// The signals used in the call to `object_wait_async`. pub fn trigger(&self) -> Signals { Signals::from_bits_truncate(self.0.trigger) } /// The observed signals. pub fn observed(&self) -> Signals { Signals::from_bits_truncate(self.0.observed) } /// A per object count of pending operations. pub fn count(&self) -> u64 { self.0.count } } impl Port { /// Create an IO port, allowing IO packets to be read and enqueued. /// /// Wraps the /// [zx_port_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_create.md) /// syscall. pub fn create() -> Result { unsafe { let mut handle = 0; let opts = 0; let status = sys::zx_port_create(opts, &mut handle); ok(status)?; Ok(Handle::from_raw(handle).into()) } } /// Attempt to queue a user packet to the IO port. /// /// Wraps the /// [zx_port_queue](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_queue.md) /// syscall. pub fn queue(&self, packet: &Packet) -> Result<(), Status> { let status = unsafe { sys::zx_port_queue(self.raw_handle(), &packet.0 as *const sys::zx_port_packet_t, 0) }; ok(status) } /// Wait for a packet to arrive on a (V2) port. /// /// Wraps the /// [zx_port_wait](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_wait.md) /// syscall. pub fn wait(&self, deadline: Time) -> Result { let mut packet = Default::default(); let status = unsafe { sys::zx_port_wait(self.raw_handle(), deadline.nanos(), &mut packet as *mut sys::zx_port_packet_t, 0) }; ok(status)?; Ok(Packet(packet)) } /// Cancel pending wait_async calls for an object with the given key. /// /// Wraps the /// [zx_port_cancel](https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/port_cancel.md) /// syscall. pub fn cancel(&self, source: &H, key: u64) -> Result<(), Status> where H: HandleBased { let status = unsafe { sys::zx_port_cancel(self.raw_handle(), source.raw_handle(), key) }; ok(status) } } /// Options for wait_async. #[repr(u32)] #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum WaitAsyncOpts { Once = sys::ZX_WAIT_ASYNC_ONCE, Repeating = sys::ZX_WAIT_ASYNC_REPEATING, } #[cfg(test)] mod tests { use super::*; use {DurationNum, Event}; #[test] fn port_basic() { let ten_ms = 10.millis(); let port = Port::create().unwrap(); // Waiting now should time out. assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); // Send a valid packet. let packet = Packet::from_user_packet( 42, 123, UserPacket::from_u8_array([13; 32]), ); assert!(port.queue(&packet).is_ok()); // Waiting should succeed this time. We should get back the packet we sent. let read_packet = port.wait(ten_ms.after_now()).unwrap(); assert_eq!(read_packet, packet); } #[test] fn wait_async_once() { let ten_ms = 10.millis(); let key = 42; let port = Port::create().unwrap(); let event = Event::create().unwrap(); assert!(event.wait_async_handle(&port, key, Signals::USER_0 | Signals::USER_1, WaitAsyncOpts::Once).is_ok()); // Waiting without setting any signal should time out. assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); // If we set a signal, we should be able to wait for it. assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); let read_packet = port.wait(ten_ms.after_now()).unwrap(); assert_eq!(read_packet.key(), key); assert_eq!(read_packet.status(), 0); match read_packet.contents() { PacketContents::SignalOne(sig) => { assert_eq!(sig.trigger(), Signals::USER_0 | Signals::USER_1); assert_eq!(sig.observed(), Signals::USER_0); assert_eq!(sig.count(), 1); } _ => panic!("wrong packet type"), } // Shouldn't get any more packets. assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); // Calling wait_async again should result in another packet. assert!(event.wait_async_handle(&port, key, Signals::USER_0, WaitAsyncOpts::Once).is_ok()); let read_packet = port.wait(ten_ms.after_now()).unwrap(); assert_eq!(read_packet.key(), key); assert_eq!(read_packet.status(), 0); match read_packet.contents() { PacketContents::SignalOne(sig) => { assert_eq!(sig.trigger(), Signals::USER_0); assert_eq!(sig.observed(), Signals::USER_0); assert_eq!(sig.count(), 1); } _ => panic!("wrong packet type"), } // Calling wait_async_handle then cancel, we should not get a packet as cancel will // remove it from the queue. assert!(event.wait_async_handle(&port, key, Signals::USER_0, WaitAsyncOpts::Once).is_ok()); assert!(port.cancel(&event, key).is_ok()); assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); // If the event is signalled after the cancel, we also shouldn't get a packet. assert!(event.signal_handle(Signals::USER_0, Signals::NONE).is_ok()); // clear signal assert!(event.wait_async_handle(&port, key, Signals::USER_0, WaitAsyncOpts::Once).is_ok()); assert!(port.cancel(&event, key).is_ok()); assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); } #[test] fn wait_async_repeating() { let ten_ms = 10.millis(); let key = 42; let port = Port::create().unwrap(); let event = Event::create().unwrap(); assert!(event.wait_async_handle(&port, key, Signals::USER_0 | Signals::USER_1, WaitAsyncOpts::Repeating).is_ok()); // Waiting without setting any signal should time out. assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); // If we set a signal, we should be able to wait for it. assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); let read_packet = port.wait(ten_ms.after_now()).unwrap(); assert_eq!(read_packet.key(), key); assert_eq!(read_packet.status(), 0); match read_packet.contents() { PacketContents::SignalRep(sig) => { assert_eq!(sig.trigger(), Signals::USER_0 | Signals::USER_1); assert_eq!(sig.observed(), Signals::USER_0); assert_eq!(sig.count(), 1); } _ => panic!("wrong packet type"), } // Should not get any more packets, as ZX_WAIT_ASYNC_REPEATING is edge triggered rather than // level triggered. assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); // If we clear and resignal, we should get the same packet again, // even though we didn't call event.wait_async again. assert!(event.signal_handle(Signals::USER_0, Signals::NONE).is_ok()); // clear signal assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); let read_packet = port.wait(ten_ms.after_now()).unwrap(); assert_eq!(read_packet.key(), key); assert_eq!(read_packet.status(), 0); match read_packet.contents() { PacketContents::SignalRep(sig) => { assert_eq!(sig.trigger(), Signals::USER_0 | Signals::USER_1); assert_eq!(sig.observed(), Signals::USER_0); assert_eq!(sig.count(), 1); } _ => panic!("wrong packet type"), } // Cancelling the wait should stop us getting packets... assert!(port.cancel(&event, key).is_ok()); assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); // ... even if we clear and resignal assert!(event.signal_handle(Signals::USER_0, Signals::NONE).is_ok()); // clear signal assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); // Calling wait_async again should result in another packet. assert!(event.wait_async_handle( &port, key, Signals::USER_0, WaitAsyncOpts::Repeating).is_ok()); let read_packet = port.wait(ten_ms.after_now()).unwrap(); assert_eq!(read_packet.key(), key); assert_eq!(read_packet.status(), 0); match read_packet.contents() { PacketContents::SignalRep(sig) => { assert_eq!(sig.trigger(), Signals::USER_0); assert_eq!(sig.observed(), Signals::USER_0); assert_eq!(sig.count(), 1); } _ => panic!("wrong packet type"), } // Closing the handle should stop us getting packets. drop(event); assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); } } fuchsia-zircon-0.3.3/src/process.rs010064016041200011610000000007311322323014300154600ustar0000000000000000// Copyright 2017 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //! Type-safe bindings for Zircon process. use {AsHandleRef, HandleBased, Handle, HandleRef}; /// An object representing a Zircon process. /// /// As essentially a subtype of `Handle`, it can be freely interconverted. #[derive(Debug, Eq, PartialEq)] pub struct Process(Handle); impl_handle_based!(Process);fuchsia-zircon-0.3.3/src/rights.rs010064016041200011610000000021771322323014300153100ustar0000000000000000use sys; bitflags! { /// Rights associated with a handle. /// /// See [rights.md](https://fuchsia.googlesource.com/zircon/+/master/docs/rights.md) /// for more information. #[repr(C)] pub struct Rights: sys::zx_rights_t { const NONE = sys::ZX_RIGHT_NONE; const DUPLICATE = sys::ZX_RIGHT_DUPLICATE; const TRANSFER = sys::ZX_RIGHT_TRANSFER; const READ = sys::ZX_RIGHT_READ; const WRITE = sys::ZX_RIGHT_WRITE; const EXECUTE = sys::ZX_RIGHT_EXECUTE; const MAP = sys::ZX_RIGHT_MAP; const GET_PROPERTY = sys::ZX_RIGHT_GET_PROPERTY; const SET_PROPERTY = sys::ZX_RIGHT_SET_PROPERTY; const ENUMERATE = sys::ZX_RIGHT_ENUMERATE; const DESTROY = sys::ZX_RIGHT_DESTROY; const SET_POLICY = sys::ZX_RIGHT_SET_POLICY; const GET_POLICY = sys::ZX_RIGHT_GET_POLICY; const SIGNAL = sys::ZX_RIGHT_SIGNAL; const SIGNAL_PEER = sys::ZX_RIGHT_SIGNAL_PEER; const WAIT = sys::ZX_RIGHT_WAIT; const SAME_RIGHTS = sys::ZX_RIGHT_SAME_RIGHTS; } }fuchsia-zircon-0.3.3/src/signals.rs010064016041200011610000000076731322323014300154560ustar0000000000000000use sys::*; bitflags! { /// Signals that can be waited upon. /// /// See /// [Objects and signals](https://fuchsia.googlesource.com/zircon/+/master/docs/concepts.md#Objects-and-Signals) /// in the Zircon kernel documentation. Note: the names of signals are still in flux. #[repr(C)] pub struct Signals: zx_signals_t { const NONE = ZX_SIGNAL_NONE; const OBJECT_ALL = ZX_OBJECT_SIGNAL_ALL; const USER_ALL = ZX_USER_SIGNAL_ALL; const OBJECT_0 = ZX_OBJECT_SIGNAL_0; const OBJECT_1 = ZX_OBJECT_SIGNAL_1; const OBJECT_2 = ZX_OBJECT_SIGNAL_2; const OBJECT_3 = ZX_OBJECT_SIGNAL_3; const OBJECT_4 = ZX_OBJECT_SIGNAL_4; const OBJECT_5 = ZX_OBJECT_SIGNAL_5; const OBJECT_6 = ZX_OBJECT_SIGNAL_6; const OBJECT_7 = ZX_OBJECT_SIGNAL_7; const OBJECT_8 = ZX_OBJECT_SIGNAL_8; const OBJECT_9 = ZX_OBJECT_SIGNAL_9; const OBJECT_10 = ZX_OBJECT_SIGNAL_10; const OBJECT_11 = ZX_OBJECT_SIGNAL_11; const OBJECT_12 = ZX_OBJECT_SIGNAL_12; const OBJECT_13 = ZX_OBJECT_SIGNAL_13; const OBJECT_14 = ZX_OBJECT_SIGNAL_14; const OBJECT_15 = ZX_OBJECT_SIGNAL_15; const OBJECT_16 = ZX_OBJECT_SIGNAL_16; const OBJECT_17 = ZX_OBJECT_SIGNAL_17; const OBJECT_18 = ZX_OBJECT_SIGNAL_18; const OBJECT_19 = ZX_OBJECT_SIGNAL_19; const OBJECT_20 = ZX_OBJECT_SIGNAL_20; const OBJECT_21 = ZX_OBJECT_SIGNAL_21; const OBJECT_22 = ZX_OBJECT_SIGNAL_22; const OBJECT_HANDLE_CLOSED = ZX_OBJECT_HANDLE_CLOSED; const USER_0 = ZX_USER_SIGNAL_0; const USER_1 = ZX_USER_SIGNAL_1; const USER_2 = ZX_USER_SIGNAL_2; const USER_3 = ZX_USER_SIGNAL_3; const USER_4 = ZX_USER_SIGNAL_4; const USER_5 = ZX_USER_SIGNAL_5; const USER_6 = ZX_USER_SIGNAL_6; const USER_7 = ZX_USER_SIGNAL_7; const OBJECT_READABLE = ZX_OBJECT_READABLE; const OBJECT_WRITABLE = ZX_OBJECT_WRITABLE; const OBJECT_PEER_CLOSED = ZX_OBJECT_PEER_CLOSED; // Cancelation (handle was closed while waiting with it) const HANDLE_CLOSED = ZX_SIGNAL_HANDLE_CLOSED; // Event const EVENT_SIGNALED = ZX_EVENT_SIGNALED; // EventPair const EVENT_PAIR_SIGNALED = ZX_EPAIR_SIGNALED; const EVENT_PAIR_CLOSED = ZX_EPAIR_CLOSED; // Task signals (process, thread, job) const TASK_TERMINATED = ZX_TASK_TERMINATED; // Channel const CHANNEL_READABLE = ZX_CHANNEL_READABLE; const CHANNEL_WRITABLE = ZX_CHANNEL_WRITABLE; const CHANNEL_PEER_CLOSED = ZX_CHANNEL_PEER_CLOSED; // Socket const SOCKET_READABLE = ZX_SOCKET_READABLE; const SOCKET_WRITABLE = ZX_SOCKET_WRITABLE; const SOCKET_PEER_CLOSED = ZX_SOCKET_PEER_CLOSED; // Port const PORT_READABLE = ZX_PORT_READABLE; // Resource const RESOURCE_DESTROYED = ZX_RESOURCE_DESTROYED; const RESOURCE_READABLE = ZX_RESOURCE_READABLE; const RESOURCE_WRITABLE = ZX_RESOURCE_WRITABLE; const RESOURCE_CHILD_ADDED = ZX_RESOURCE_CHILD_ADDED; // Fifo const FIFO_READABLE = ZX_FIFO_READABLE; const FIFO_WRITABLE = ZX_FIFO_WRITABLE; const FIFO_PEER_CLOSED = ZX_FIFO_PEER_CLOSED; // Job const JOB_NO_PROCESSES = ZX_JOB_NO_PROCESSES; const JOB_NO_JOBS = ZX_JOB_NO_JOBS; // Process const PROCESS_TERMINATED = ZX_PROCESS_TERMINATED; // Thread const THREAD_TERMINATED = ZX_THREAD_TERMINATED; // Log const LOG_READABLE = ZX_LOG_READABLE; const LOG_WRITABLE = ZX_LOG_WRITABLE; // Timer const TIMER_SIGNALED = ZX_TIMER_SIGNALED; } }fuchsia-zircon-0.3.3/src/socket.rs010064016041200011610000000106371322323014300153000ustar0000000000000000// Copyright 2016 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //! Type-safe bindings for Zircon sockets. use {AsHandleRef, HandleBased, Handle, HandleRef, Peered}; use {sys, Status, ok}; use std::ptr; /// An object representing a Zircon /// [socket](https://fuchsia.googlesource.com/zircon/+/master/docs/concepts.md#Message-Passing_Sockets-and-Channels). /// /// As essentially a subtype of `Handle`, it can be freely interconverted. #[derive(Debug, Eq, PartialEq)] pub struct Socket(Handle); impl_handle_based!(Socket); impl Peered for Socket {} impl Socket { /// Create a socket, accessed through a pair of endpoints. Data written /// into one may be read from the other. /// /// Wraps /// [zx_socket_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/socket_create.md). pub fn create() -> Result<(Socket, Socket), Status> { unsafe { let mut out0 = 0; let mut out1 = 0; let opts = 0; let status = sys::zx_socket_create(opts, &mut out0, &mut out1); ok(status)?; Ok(( Self::from(Handle::from_raw(out0)), Self::from(Handle::from_raw(out1)) )) } } /// Write the given bytes into the socket. /// Return value (on success) is number of bytes actually written. /// /// Wraps /// [zx_socket_write](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/socket_write.md). pub fn write(&self, bytes: &[u8]) -> Result { let mut actual = 0; let opts = 0; let status = unsafe { sys::zx_socket_write(self.raw_handle(), opts, bytes.as_ptr(), bytes.len(), &mut actual) }; ok(status).map(|()| actual) } /// Read the given bytes from the socket. /// Return value (on success) is number of bytes actually read. /// /// Wraps /// [zx_socket_read](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/socket_read.md). pub fn read(&self, bytes: &mut [u8]) -> Result { let mut actual = 0; let opts = 0; let status = unsafe { sys::zx_socket_read(self.raw_handle(), opts, bytes.as_mut_ptr(), bytes.len(), &mut actual) }; ok(status) .map(|()| actual) .map_err(|status| { // If an error is returned then actual is undefined, so to be safe // we set it to 0 and ignore any data that is set in bytes. actual = 0; status }) } /// Close half of the socket, so attempts by the other side to write will fail. /// /// Implements the `ZX_SOCKET_HALF_CLOSE` option of /// [zx_socket_write](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/socket_write.md). pub fn half_close(&self) -> Result<(), Status> { let status = unsafe { sys::zx_socket_write(self.raw_handle(), sys::ZX_SOCKET_HALF_CLOSE, ptr::null(), 0, ptr::null_mut()) }; ok(status) } pub fn outstanding_read_bytes(&self) -> Result { let mut outstanding = 0; let status = unsafe { sys::zx_socket_read(self.raw_handle(), 0, ptr::null_mut(), 0, &mut outstanding) }; ok(status).map(|()| outstanding) } } #[cfg(test)] mod tests { use super::*; #[test] fn socket_basic() { let (s1, s2) = Socket::create().unwrap(); // Write in one end and read it back out the other. assert_eq!(s1.write(b"hello").unwrap(), 5); let mut read_vec = vec![0; 8]; assert_eq!(s2.read(&mut read_vec).unwrap(), 5); assert_eq!(&read_vec[0..5], b"hello"); // Try reading when there is nothing to read. assert_eq!(s2.read(&mut read_vec), Err(Status::SHOULD_WAIT)); // Close the socket from one end. assert!(s1.half_close().is_ok()); assert_eq!(s2.read(&mut read_vec), Err(Status::BAD_STATE)); assert_eq!(s1.write(b"fail"), Err(Status::BAD_STATE)); // Writing in the other direction should still work. assert_eq!(s1.read(&mut read_vec), Err(Status::SHOULD_WAIT)); assert_eq!(s2.write(b"back").unwrap(), 4); assert_eq!(s1.read(&mut read_vec).unwrap(), 4); assert_eq!(&read_vec[0..4], b"back"); } } fuchsia-zircon-0.3.3/src/status.rs010064016041200011610000000125721322323014300153330ustar0000000000000000use std::ffi::NulError; use std::io; use sys; /// Status type indicating the result of a Fuchsia syscall. /// /// This type is generally used to indicate the reason for an error. /// While this type can contain `Status::OK` (`ZX_OK` in C land), elements of this type are /// generally constructed using the `ok` method, which checks for `ZX_OK` and returns a /// `Result<(), Status>` appropriately. #[repr(C)] #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct Status(sys::zx_status_t); impl Status { /// Returns `Ok(())` if the status was `OK`, /// otherwise returns `Err(status)`. pub fn ok(raw: sys::zx_status_t) -> Result<(), Status> { if raw == Status::OK.0 { Ok(()) } else { Err(Status(raw)) } } pub fn from_raw(raw: sys::zx_status_t) -> Self { Status(raw) } pub fn into_raw(self) -> sys::zx_status_t { self.0 } } assoc_consts!(Status, [ OK = sys::ZX_OK; INTERNAL = sys::ZX_ERR_INTERNAL; NOT_SUPPORTED = sys::ZX_ERR_NOT_SUPPORTED; NO_RESOURCES = sys::ZX_ERR_NO_RESOURCES; NO_MEMORY = sys::ZX_ERR_NO_MEMORY; CALL_FAILED = sys::ZX_ERR_CALL_FAILED; INTERRUPTED_RETRY = sys::ZX_ERR_INTERRUPTED_RETRY; INVALID_ARGS = sys::ZX_ERR_INVALID_ARGS; BAD_HANDLE = sys::ZX_ERR_BAD_HANDLE; WRONG_TYPE = sys::ZX_ERR_WRONG_TYPE; BAD_SYSCALL = sys::ZX_ERR_BAD_SYSCALL; OUT_OF_RANGE = sys::ZX_ERR_OUT_OF_RANGE; BUFFER_TOO_SMALL = sys::ZX_ERR_BUFFER_TOO_SMALL; BAD_STATE = sys::ZX_ERR_BAD_STATE; TIMED_OUT = sys::ZX_ERR_TIMED_OUT; SHOULD_WAIT = sys::ZX_ERR_SHOULD_WAIT; CANCELED = sys::ZX_ERR_CANCELED; PEER_CLOSED = sys::ZX_ERR_PEER_CLOSED; NOT_FOUND = sys::ZX_ERR_NOT_FOUND; ALREADY_EXISTS = sys::ZX_ERR_ALREADY_EXISTS; ALREADY_BOUND = sys::ZX_ERR_ALREADY_BOUND; UNAVAILABLE = sys::ZX_ERR_UNAVAILABLE; ACCESS_DENIED = sys::ZX_ERR_ACCESS_DENIED; IO = sys::ZX_ERR_IO; IO_REFUSED = sys::ZX_ERR_IO_REFUSED; IO_DATA_INTEGRITY = sys::ZX_ERR_IO_DATA_INTEGRITY; IO_DATA_LOSS = sys::ZX_ERR_IO_DATA_LOSS; BAD_PATH = sys::ZX_ERR_BAD_PATH; NOT_DIR = sys::ZX_ERR_NOT_DIR; NOT_FILE = sys::ZX_ERR_NOT_FILE; FILE_BIG = sys::ZX_ERR_FILE_BIG; NO_SPACE = sys::ZX_ERR_NO_SPACE; STOP = sys::ZX_ERR_STOP; NEXT = sys::ZX_ERR_NEXT; ]); impl Status { pub fn into_io_error(self) -> io::Error { self.into() } } impl From for Status { fn from(kind: io::ErrorKind) -> Self { use std::io::ErrorKind::*; match kind { NotFound => Status::NOT_FOUND, PermissionDenied => Status::ACCESS_DENIED, ConnectionRefused => Status::IO_REFUSED, ConnectionAborted => Status::PEER_CLOSED, AddrInUse => Status::ALREADY_BOUND, AddrNotAvailable => Status::UNAVAILABLE, BrokenPipe => Status::PEER_CLOSED, AlreadyExists => Status::ALREADY_EXISTS, WouldBlock => Status::SHOULD_WAIT, InvalidInput => Status::INVALID_ARGS, TimedOut => Status::TIMED_OUT, Interrupted => Status::INTERRUPTED_RETRY, UnexpectedEof | WriteZero | ConnectionReset | NotConnected | Other | _ => Status::IO, } } } impl From for io::ErrorKind { fn from(status: Status) -> io::ErrorKind { use std::io::ErrorKind::*; match status { Status::INTERRUPTED_RETRY => Interrupted, Status::BAD_HANDLE => BrokenPipe, Status::TIMED_OUT => TimedOut, Status::SHOULD_WAIT => WouldBlock, Status::PEER_CLOSED => ConnectionAborted, Status::NOT_FOUND => NotFound, Status::ALREADY_EXISTS => AlreadyExists, Status::ALREADY_BOUND => AlreadyExists, Status::UNAVAILABLE => AddrNotAvailable, Status::ACCESS_DENIED => PermissionDenied, Status::IO_REFUSED => ConnectionRefused, Status::IO_DATA_INTEGRITY => InvalidData, Status::BAD_PATH | Status::INVALID_ARGS | Status::OUT_OF_RANGE | Status::WRONG_TYPE => InvalidInput, Status::OK | Status::NEXT | Status::STOP | Status::NO_SPACE | Status::FILE_BIG | Status::NOT_FILE | Status::NOT_DIR | Status::IO_DATA_LOSS | Status::IO | Status::CANCELED | Status::BAD_STATE | Status::BUFFER_TOO_SMALL | Status::BAD_SYSCALL | Status::INTERNAL | Status::NOT_SUPPORTED | Status::NO_RESOURCES | Status::NO_MEMORY | Status::CALL_FAILED | _ => Other, } } } impl From for Status { fn from(err: io::Error) -> Status { err.kind().into() } } impl From for io::Error { fn from(status: Status) -> io::Error { io::Error::from(io::ErrorKind::from(status)) } } impl From for Status { fn from(_error: NulError) -> Status { Status::INVALID_ARGS } } fuchsia-zircon-0.3.3/src/thread.rs010064016041200011610000000007251322323014300152540ustar0000000000000000// Copyright 2017 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //! Type-safe bindings for Zircon thread. use {AsHandleRef, HandleBased, Handle, HandleRef}; /// An object representing a Zircon thread. /// /// As essentially a subtype of `Handle`, it can be freely interconverted. #[derive(Debug, Eq, PartialEq)] pub struct Thread(Handle); impl_handle_based!(Thread);fuchsia-zircon-0.3.3/src/time.rs010064016041200011610000000226751322323014300147530ustar0000000000000000// Copyright 2016 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //! Type-safe bindings for Zircon timer objects. use {AsHandleRef, ClockId, HandleBased, Handle, HandleRef, Status}; use {sys, ok}; use std::ops; use std::time as stdtime; #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct Duration(sys::zx_duration_t); #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct Time(sys::zx_time_t); impl From for Duration { fn from(dur: stdtime::Duration) -> Self { Duration::from_seconds(dur.as_secs()) + Duration::from_nanos(dur.subsec_nanos() as u64) } } impl From for stdtime::Duration { fn from(dur: Duration) -> Self { let secs = dur.seconds(); let nanos = (dur.nanos() - (secs * 1_000_000_000)) as u32; stdtime::Duration::new(secs, nanos) } } impl ops::Add for Time { type Output = Time; fn add(self, dur: Duration) -> Time { Time::from_nanos(dur.nanos() + self.nanos()) } } impl ops::Add