summaryrefslogtreecommitdiffstats
path: root/third_party/rust/fuchsia-zircon
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/fuchsia-zircon')
-rw-r--r--third_party/rust/fuchsia-zircon/.cargo-checksum.json1
-rw-r--r--third_party/rust/fuchsia-zircon/BUILD.gn14
-rw-r--r--third_party/rust/fuchsia-zircon/Cargo.toml24
-rw-r--r--third_party/rust/fuchsia-zircon/LICENSE27
-rw-r--r--third_party/rust/fuchsia-zircon/README.md12
-rw-r--r--third_party/rust/fuchsia-zircon/examples/BUILD.gn17
-rw-r--r--third_party/rust/fuchsia-zircon/src/channel.rs418
-rw-r--r--third_party/rust/fuchsia-zircon/src/cprng.rs68
-rw-r--r--third_party/rust/fuchsia-zircon/src/event.rs32
-rw-r--r--third_party/rust/fuchsia-zircon/src/eventpair.rs65
-rw-r--r--third_party/rust/fuchsia-zircon/src/fifo.rs98
-rw-r--r--third_party/rust/fuchsia-zircon/src/handle.rs243
-rw-r--r--third_party/rust/fuchsia-zircon/src/job.rs14
-rw-r--r--third_party/rust/fuchsia-zircon/src/lib.rs365
-rw-r--r--third_party/rust/fuchsia-zircon/src/port.rs344
-rw-r--r--third_party/rust/fuchsia-zircon/src/process.rs14
-rw-r--r--third_party/rust/fuchsia-zircon/src/rights.rs28
-rw-r--r--third_party/rust/fuchsia-zircon/src/signals.rs105
-rw-r--r--third_party/rust/fuchsia-zircon/src/socket.rs126
-rw-r--r--third_party/rust/fuchsia-zircon/src/status.rs162
-rw-r--r--third_party/rust/fuchsia-zircon/src/thread.rs14
-rw-r--r--third_party/rust/fuchsia-zircon/src/time.rs346
-rw-r--r--third_party/rust/fuchsia-zircon/src/vmar.rs18
-rw-r--r--third_party/rust/fuchsia-zircon/src/vmo.rs256
-rwxr-xr-xthird_party/rust/fuchsia-zircon/tools/gen_status.py49
25 files changed, 2860 insertions, 0 deletions
diff --git a/third_party/rust/fuchsia-zircon/.cargo-checksum.json b/third_party/rust/fuchsia-zircon/.cargo-checksum.json
new file mode 100644
index 0000000000..482d8e4f3b
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"BUILD.gn":"651b841730c01aa677f22906fd5eee96234a01d13139e4be12943698dd486a17","Cargo.toml":"0f744f8a2ee868ebcb30356bebc5dcf9be09927f9b72fd7c0625d4c4a35b1803","LICENSE":"f82f9062a6dff28145c185f90f94c485eebdc2bb4c6f1c840513709e6d228453","README.md":"f4bff6efc5d888460e2d1eaf62fa0eaca8afe7b51df528ad7829340ec397b32c","examples/BUILD.gn":"51c9291631e59d368709d9959a88bc8be1fe7375c65f2e1fc6e26184e8971137","src/channel.rs":"15c2a404f760d1594b9b8cfbaf8a828f5c506c6cb09a3408b4d5e894360eb1fc","src/cprng.rs":"cd8a163f7e5e75e536ee898a00c1c377b10c748c7dc574c7c3582bb86fdc86c5","src/event.rs":"bbf0c91d154f01ec1618182efbaaa8c71580f05a807cac1d12208b5cbe8f6b74","src/eventpair.rs":"0bf0b1137c2fb08398edb4d09b89ded5990d07f94ffe55b6ec917c7bc9059ebe","src/fifo.rs":"9ac29d11330fdea847902b8dba6b2004ad44878d8ef65d26a197780cd443ebb8","src/handle.rs":"8741c4b5056a200cfb4237af2d2d2c1db083075b112df68166e351e6d81eb3f3","src/job.rs":"827db2e4ea1bbf5ecabec9fb279f2721792032e4223b6bd15b56922d80c7ac01","src/lib.rs":"9f65dd6ba52e56190825542d6d2dfeca2a5610257513f373fa2cdb4d45d9fc6b","src/port.rs":"32501f17218ec9ad4d97741f4ff2d5ca8e89b7da7226473c82441fd06adbecc4","src/process.rs":"0b5e42c4eb79b2a7fff9c70f0d99c8b805cefab99285e94fabf2542290b4b990","src/rights.rs":"679422da3c0ff9f4e4928b8f41098ef0f5ec09af098496e088e2bac82fc9568d","src/signals.rs":"c07501df58b3c6264e37ebc0f5fd28f44ced040273a5ab5e839e3a204d351ea7","src/socket.rs":"cfb2f6ecb5ba9d9e354c18088061d6e5330dd420a20d0ced4a11f05d3332e3b8","src/status.rs":"4831adf17c1fbd4d52a0aacc63eebd98e49f6c0e28c407e8a0e40f380b3f3b2b","src/thread.rs":"d703414c440b5fa597dbafe7b8be925a94d1fe0cf8b47366c786b45eaaec4c60","src/time.rs":"33d9662c58b921ebe701d927d30ebc01d95594d081c38824355093206f29fba0","src/vmar.rs":"e69a51287e3cb016fa39bb8d884c88ffba4799a452c17e881af9d63a507b37f7","src/vmo.rs":"377968eec57b79a7f4b117dff2f59f26a57ba97ca7f2f0334bd27b99fe87b299","tools/gen_status.py":"a2330db86564e12412af2dce60d4c605c0ab203fcdea8039d5c6a8e7f218a3c3"},"package":"2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"} \ No newline at end of file
diff --git a/third_party/rust/fuchsia-zircon/BUILD.gn b/third_party/rust/fuchsia-zircon/BUILD.gn
new file mode 100644
index 0000000000..1edb419d8f
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/BUILD.gn
@@ -0,0 +1,14 @@
+# 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
+}
diff --git a/third_party/rust/fuchsia-zircon/Cargo.toml b/third_party/rust/fuchsia-zircon/Cargo.toml
new file mode 100644
index 0000000000..4f8cd92b0f
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/Cargo.toml
@@ -0,0 +1,24 @@
+# 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 <raph@google.com>"]
+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"
diff --git a/third_party/rust/fuchsia-zircon/LICENSE b/third_party/rust/fuchsia-zircon/LICENSE
new file mode 100644
index 0000000000..ac6402fd91
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/LICENSE
@@ -0,0 +1,27 @@
+// 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.
diff --git a/third_party/rust/fuchsia-zircon/README.md b/third_party/rust/fuchsia-zircon/README.md
new file mode 100644
index 0000000000..9a597e0977
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/README.md
@@ -0,0 +1,12 @@
+Rust 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.
diff --git a/third_party/rust/fuchsia-zircon/examples/BUILD.gn b/third_party/rust/fuchsia-zircon/examples/BUILD.gn
new file mode 100644
index 0000000000..dee61f5829
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/examples/BUILD.gn
@@ -0,0 +1,17 @@
+# 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"
+ } ]
+}
diff --git a/third_party/rust/fuchsia-zircon/src/channel.rs b/third_party/rust/fuchsia-zircon/src/channel.rs
new file mode 100644
index 0000000000..44ffc6cd9c
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/channel.rs
@@ -0,0 +1,418 @@
+// 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<Result<(), Status>, (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<Handle>)
+ -> 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<Handle>,
+ 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::<sys::zx_handle_t>(), 4);
+ assert_eq!(::std::mem::size_of::<Handle>(), 4);
+ assert_eq!(::std::mem::align_of::<sys::zx_handle_t>(), ::std::mem::align_of::<Handle>());
+
+ // This test asserts that repr(transparent) still works for Handle -> zx_handle_t
+
+ let n: Vec<sys::zx_handle_t> = vec![0, 100, 2<<32-1];
+ let v: Vec<Handle> = 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<Channel> 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<Handle>`.
+#[derive(Default)]
+#[derive(Debug)]
+pub struct MessageBuf {
+ bytes: Vec<u8>,
+ handles: Vec<Handle>,
+}
+
+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<u8>, h: Vec<Handle>) -> 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<Handle> {
+ 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<T>(vec: &mut Vec<T>, 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<Handle> = 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<Handle> = 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);
+ }
+}
diff --git a/third_party/rust/fuchsia-zircon/src/cprng.rs b/third_party/rust/fuchsia-zircon/src/cprng.rs
new file mode 100644
index 0000000000..433ed26d9e
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/cprng.rs
@@ -0,0 +1,68 @@
+use {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<usize, Status> {
+ 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(()));
+ }
+} \ No newline at end of file
diff --git a/third_party/rust/fuchsia-zircon/src/event.rs b/third_party/rust/fuchsia-zircon/src/event.rs
new file mode 100644
index 0000000000..533a8aafcc
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/event.rs
@@ -0,0 +1,32 @@
+// 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<Event, Status> {
+ 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)))
+ }
+ }
+}
diff --git a/third_party/rust/fuchsia-zircon/src/eventpair.rs b/third_party/rust/fuchsia-zircon/src/eventpair.rs
new file mode 100644
index 0000000000..6f2d29806d
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/eventpair.rs
@@ -0,0 +1,65 @@
+// 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));
+ }
+}
diff --git a/third_party/rust/fuchsia-zircon/src/fifo.rs b/third_party/rust/fuchsia-zircon/src/fifo.rs
new file mode 100644
index 0000000000..20af6f5236
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/fifo.rs
@@ -0,0 +1,98 @@
+// 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<u32, Status> {
+ 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<u32, Status> {
+ 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));
+ }
+}
diff --git a/third_party/rust/fuchsia-zircon/src/handle.rs b/third_party/rust/fuchsia-zircon/src/handle.rs
new file mode 100644
index 0000000000..5c50f29f0e
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/handle.rs
@@ -0,0 +1,243 @@
+use {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<Handle, Status> {
+ 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<Handle, Status> {
+ 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<Signals, Status> {
+ 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<Signals, Status> {
+ 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<Handle>` trait to facilitate conversion from and to the
+/// interface.
+pub trait HandleBased: AsHandleRef + From<Handle> + Into<Handle> {
+ /// 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, Status> {
+ 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<Self, Status> {
+ <Self as Into<Handle>>::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<H: HandleBased>(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: HandleBased>(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<u64, Status> {
+ 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)
+ }
+}
diff --git a/third_party/rust/fuchsia-zircon/src/job.rs b/third_party/rust/fuchsia-zircon/src/job.rs
new file mode 100644
index 0000000000..1bb1ef274d
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/job.rs
@@ -0,0 +1,14 @@
+// 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); \ No newline at end of file
diff --git a/third_party/rust/fuchsia-zircon/src/lib.rs b/third_party/rust/fuchsia-zircon/src/lib.rs
new file mode 100644
index 0000000000..26444402cc
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/lib.rs
@@ -0,0 +1,365 @@
+// 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<Handle> 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<bool, Status>
+{
+ 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<u32, ()> {
+ 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
+}
diff --git a/third_party/rust/fuchsia-zircon/src/port.rs b/third_party/rust/fuchsia-zircon/src/port.rs
new file mode 100644
index 0000000000..6a9e8a8f7f
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/port.rs
@@ -0,0 +1,344 @@
+// 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<Port, Status> {
+ 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<Packet, Status> {
+ 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<H>(&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));
+ }
+}
diff --git a/third_party/rust/fuchsia-zircon/src/process.rs b/third_party/rust/fuchsia-zircon/src/process.rs
new file mode 100644
index 0000000000..b46f1bdd23
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/process.rs
@@ -0,0 +1,14 @@
+// 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); \ No newline at end of file
diff --git a/third_party/rust/fuchsia-zircon/src/rights.rs b/third_party/rust/fuchsia-zircon/src/rights.rs
new file mode 100644
index 0000000000..a41ad12f54
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/rights.rs
@@ -0,0 +1,28 @@
+use 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;
+ }
+} \ No newline at end of file
diff --git a/third_party/rust/fuchsia-zircon/src/signals.rs b/third_party/rust/fuchsia-zircon/src/signals.rs
new file mode 100644
index 0000000000..e5189f5ebc
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/signals.rs
@@ -0,0 +1,105 @@
+use 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;
+ }
+} \ No newline at end of file
diff --git a/third_party/rust/fuchsia-zircon/src/socket.rs b/third_party/rust/fuchsia-zircon/src/socket.rs
new file mode 100644
index 0000000000..c93e98cb73
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/socket.rs
@@ -0,0 +1,126 @@
+// 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<usize, Status> {
+ 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<usize, Status> {
+ 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<usize, Status> {
+ 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");
+ }
+}
diff --git a/third_party/rust/fuchsia-zircon/src/status.rs b/third_party/rust/fuchsia-zircon/src/status.rs
new file mode 100644
index 0000000000..4f3e38f988
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/status.rs
@@ -0,0 +1,162 @@
+use 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<io::ErrorKind> 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<Status> 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<io::Error> for Status {
+ fn from(err: io::Error) -> Status {
+ err.kind().into()
+ }
+}
+
+impl From<Status> for io::Error {
+ fn from(status: Status) -> io::Error {
+ io::Error::from(io::ErrorKind::from(status))
+ }
+}
+
+impl From<NulError> for Status {
+ fn from(_error: NulError) -> Status {
+ Status::INVALID_ARGS
+ }
+}
diff --git a/third_party/rust/fuchsia-zircon/src/thread.rs b/third_party/rust/fuchsia-zircon/src/thread.rs
new file mode 100644
index 0000000000..be482375d4
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/thread.rs
@@ -0,0 +1,14 @@
+// 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); \ No newline at end of file
diff --git a/third_party/rust/fuchsia-zircon/src/time.rs b/third_party/rust/fuchsia-zircon/src/time.rs
new file mode 100644
index 0000000000..1b1deaceed
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/time.rs
@@ -0,0 +1,346 @@
+// 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<stdtime::Duration> for Duration {
+ fn from(dur: stdtime::Duration) -> Self {
+ Duration::from_seconds(dur.as_secs()) +
+ Duration::from_nanos(dur.subsec_nanos() as u64)
+ }
+}
+
+impl From<Duration> 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<Duration> for Time {
+ type Output = Time;
+ fn add(self, dur: Duration) -> Time {
+ Time::from_nanos(dur.nanos() + self.nanos())
+ }
+}
+
+impl ops::Add<Time> for Duration {
+ type Output = Time;
+ fn add(self, time: Time) -> Time {
+ Time::from_nanos(self.nanos() + time.nanos())
+ }
+}
+
+impl ops::Add for Duration {
+ type Output = Duration;
+ fn add(self, dur: Duration) -> Duration {
+ Duration::from_nanos(self.nanos() + dur.nanos())
+ }
+}
+
+impl ops::Sub for Duration {
+ type Output = Duration;
+ fn sub(self, dur: Duration) -> Duration {
+ Duration::from_nanos(self.nanos() - dur.nanos())
+ }
+}
+
+impl ops::Sub<Duration> for Time {
+ type Output = Time;
+ fn sub(self, dur: Duration) -> Time {
+ Time::from_nanos(self.nanos() - dur.nanos())
+ }
+}
+
+impl ops::AddAssign for Duration {
+ fn add_assign(&mut self, dur: Duration) {
+ self.0 += dur.nanos()
+ }
+}
+
+impl ops::SubAssign for Duration {
+ fn sub_assign(&mut self, dur: Duration) {
+ self.0 -= dur.nanos()
+ }
+}
+
+impl ops::AddAssign<Duration> for Time {
+ fn add_assign(&mut self, dur: Duration) {
+ self.0 += dur.nanos()
+ }
+}
+
+impl ops::SubAssign<Duration> for Time {
+ fn sub_assign(&mut self, dur: Duration) {
+ self.0 -= dur.nanos()
+ }
+}
+
+impl<T> ops::Mul<T> for Duration
+ where T: Into<u64>
+{
+ type Output = Self;
+ fn mul(self, mul: T) -> Self {
+ Duration::from_nanos(self.0 * mul.into())
+ }
+}
+
+impl<T> ops::Div<T> for Duration
+ where T: Into<u64>
+{
+ type Output = Self;
+ fn div(self, div: T) -> Self {
+ Duration::from_nanos(self.0 / div.into())
+ }
+}
+
+impl Duration {
+ /// Sleep for the given amount of time.
+ pub fn sleep(self) {
+ Time::after(self).sleep()
+ }
+
+ pub fn nanos(self) -> u64 {
+ self.0
+ }
+
+ pub fn millis(self) -> u64 {
+ self.0 / 1_000_000
+ }
+
+ pub fn seconds(self) -> u64 {
+ self.millis() / 1_000
+ }
+
+ pub fn minutes(self) -> u64 {
+ self.seconds() / 60
+ }
+
+ pub fn hours(self) -> u64 {
+ self.minutes() / 60
+ }
+
+ pub fn from_nanos(nanos: u64) -> Self {
+ Duration(nanos)
+ }
+
+ pub fn from_millis(millis: u64) -> Self {
+ Duration(millis * 1_000_000)
+ }
+
+ pub fn from_seconds(secs: u64) -> Self {
+ Duration::from_millis(secs * 1_000)
+ }
+
+ pub fn from_minutes(min: u64) -> Self {
+ Duration::from_seconds(min * 60)
+ }
+
+ pub fn from_hours(hours: u64) -> Self {
+ Duration::from_minutes(hours * 60)
+ }
+
+ /// Returns a `Time` which is a `Duration` after the current time.
+ /// `duration.after_now()` is equivalent to `Time::after(duration)`.
+ pub fn after_now(self) -> Time {
+ Time::after(self)
+ }
+}
+
+pub trait DurationNum: Sized {
+ fn nanos(self) -> Duration;
+ fn millis(self) -> Duration;
+ fn seconds(self) -> Duration;
+ fn minutes(self) -> Duration;
+ fn hours(self) -> Duration;
+
+ // Singular versions to allow for `1.milli()` and `1.second()`, etc.
+ fn milli(self) -> Duration { self.millis() }
+ fn second(self) -> Duration { self.seconds() }
+ fn minute(self) -> Duration { self.minutes() }
+ fn hour(self) -> Duration { self.hours() }
+}
+
+// Note: this could be implemented for other unsized integer types, but it doesn't seem
+// necessary to support the usual case.
+impl DurationNum for u64 {
+ fn nanos(self) -> Duration {
+ Duration::from_nanos(self)
+ }
+
+ fn millis(self) -> Duration {
+ Duration::from_millis(self)
+ }
+
+ fn seconds(self) -> Duration {
+ Duration::from_seconds(self)
+ }
+
+ fn minutes(self) -> Duration {
+ Duration::from_minutes(self)
+ }
+
+ fn hours(self) -> Duration {
+ Duration::from_hours(self)
+ }
+}
+
+impl Time {
+ pub const INFINITE: Time = Time(sys::ZX_TIME_INFINITE);
+
+ /// Get the current time, from the specific clock id.
+ ///
+ /// Wraps the
+ /// [zx_time_get](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/time_get.md)
+ /// syscall.
+ pub fn get(clock_id: ClockId) -> Time {
+ unsafe { Time(sys::zx_time_get(clock_id as u32)) }
+ }
+
+ /// Compute a deadline for the time in the future that is the given `Duration` away.
+ ///
+ /// Wraps the
+ /// [zx_deadline_after](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/deadline_after.md)
+ /// syscall.
+ pub fn after(duration: Duration) -> Time {
+ unsafe { Time(sys::zx_deadline_after(duration.0)) }
+ }
+
+ /// Sleep until the given time.
+ ///
+ /// Wraps the
+ /// [zx_nanosleep](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/nanosleep.md)
+ /// syscall.
+ pub fn sleep(self) {
+ unsafe { sys::zx_nanosleep(self.0); }
+ }
+
+ pub fn nanos(self) -> u64 {
+ self.0
+ }
+
+ pub fn from_nanos(nanos: u64) -> Self {
+ Time(nanos)
+ }
+}
+
+/// Read the number of high-precision timer ticks since boot. These ticks may be processor cycles,
+/// high speed timer, profiling timer, etc. They are not guaranteed to continue advancing when the
+/// system is asleep.
+///
+/// Wraps the
+/// [zx_ticks_get](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/ticks_get.md)
+/// syscall.
+pub fn ticks_get() -> u64 {
+ unsafe { sys::zx_ticks_get() }
+}
+
+/// Return the number of high-precision timer ticks in a second.
+///
+/// Wraps the
+/// [zx_ticks_per_second](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/ticks_per_second.md)
+/// syscall.
+pub fn ticks_per_second() -> u64 {
+ unsafe { sys::zx_ticks_per_second() }
+}
+
+/// An object representing a Zircon timer, such as the one returned by
+/// [zx_timer_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/timer_create.md).
+///
+/// As essentially a subtype of `Handle`, it can be freely interconverted.
+#[derive(Debug, Eq, PartialEq)]
+pub struct Timer(Handle);
+impl_handle_based!(Timer);
+
+impl Timer {
+ /// Create a timer, an object that can signal when a specified point in time has been reached.
+ /// Wraps the
+ /// [zx_timer_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/timer_create.md)
+ /// syscall.
+ pub fn create(clock_id: ClockId) -> Result<Timer, Status> {
+ let mut out = 0;
+ let opts = 0;
+ let status = unsafe { sys::zx_timer_create(opts, clock_id as u32, &mut out) };
+ ok(status)?;
+ unsafe {
+ Ok(Self::from(Handle::from_raw(out)))
+ }
+ }
+
+ /// Start a one-shot timer that will fire when `deadline` passes. Wraps the
+ /// [zx_timer_set](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/timer_set.md)
+ /// syscall.
+ pub fn set(&self, deadline: Time, slack: Duration) -> Result<(), Status> {
+ let status = unsafe {
+ sys::zx_timer_set(self.raw_handle(), deadline.nanos(), slack.nanos())
+ };
+ ok(status)
+ }
+
+ /// Cancels a pending timer that was started with start(). Wraps the
+ /// [zx_timer_cancel](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/timer_cancel.md)
+ /// syscall.
+ pub fn cancel(&self) -> Result<(), Status> {
+ let status = unsafe { sys::zx_timer_cancel(self.raw_handle()) };
+ ok(status)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use Signals;
+
+ #[test]
+ fn create_timer_invalid_clock() {
+ assert_eq!(Timer::create(ClockId::UTC).unwrap_err(), Status::INVALID_ARGS);
+ assert_eq!(Timer::create(ClockId::Thread), Err(Status::INVALID_ARGS));
+ }
+
+ #[test]
+ fn into_from_std() {
+ let std_dur = stdtime::Duration::new(25, 25);
+ assert_eq!(std_dur, stdtime::Duration::from(Duration::from(std_dur)));
+ }
+
+ #[test]
+ fn timer_basic() {
+ let slack = 0.millis();
+ let ten_ms = 10.millis();
+ let five_secs = 5.seconds();
+ let six_secs = 6.seconds();
+
+ // Create a timer
+ let timer = Timer::create(ClockId::Monotonic).unwrap();
+
+ // Should not signal yet.
+ assert_eq!(
+ timer.wait_handle(Signals::TIMER_SIGNALED, ten_ms.after_now()),
+ Err(Status::TIMED_OUT));
+
+ // Set it, and soon it should signal.
+ assert_eq!(timer.set(five_secs.after_now(), slack), Ok(()));
+ assert_eq!(
+ timer.wait_handle(Signals::TIMER_SIGNALED, six_secs.after_now()),
+ Ok(Signals::TIMER_SIGNALED));
+
+ // Cancel it, and it should stop signalling.
+ assert_eq!(timer.cancel(), Ok(()));
+ assert_eq!(
+ timer.wait_handle(Signals::TIMER_SIGNALED, ten_ms.after_now()),
+ Err(Status::TIMED_OUT));
+ }
+}
diff --git a/third_party/rust/fuchsia-zircon/src/vmar.rs b/third_party/rust/fuchsia-zircon/src/vmar.rs
new file mode 100644
index 0000000000..a828195df4
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/vmar.rs
@@ -0,0 +1,18 @@
+use sys;
+
+bitflags! {
+ /// Flags to VMAR routines
+ #[repr(C)]
+ pub struct VmarFlags: u32 {
+ const PERM_READ = sys::ZX_VM_FLAG_PERM_READ;
+ const PERM_WRITE = sys::ZX_VM_FLAG_PERM_WRITE;
+ const PERM_EXECUTE = sys::ZX_VM_FLAG_PERM_EXECUTE;
+ const COMPACT = sys::ZX_VM_FLAG_COMPACT;
+ const SPECIFIC = sys::ZX_VM_FLAG_SPECIFIC;
+ const SPECIFIC_OVERWRITE = sys::ZX_VM_FLAG_SPECIFIC_OVERWRITE;
+ const CAN_MAP_SPECIFIC = sys::ZX_VM_FLAG_CAN_MAP_SPECIFIC;
+ const CAN_MAP_READ = sys::ZX_VM_FLAG_CAN_MAP_READ;
+ const CAN_MAP_WRITE = sys::ZX_VM_FLAG_CAN_MAP_WRITE;
+ const CAN_MAP_EXECUTE = sys::ZX_VM_FLAG_CAN_MAP_EXECUTE;
+ }
+} \ No newline at end of file
diff --git a/third_party/rust/fuchsia-zircon/src/vmo.rs b/third_party/rust/fuchsia-zircon/src/vmo.rs
new file mode 100644
index 0000000000..68c86b5429
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/vmo.rs
@@ -0,0 +1,256 @@
+// 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 vmo objects.
+
+use {AsHandleRef, Cookied, HandleBased, Handle, HandleRef, Status};
+use {sys, ok};
+use std::{mem, ptr};
+
+/// An object representing a Zircon
+/// [virtual memory object](https://fuchsia.googlesource.com/zircon/+/master/docs/objects/vm_object.md).
+///
+/// As essentially a subtype of `Handle`, it can be freely interconverted.
+#[derive(Debug, Eq, PartialEq)]
+pub struct Vmo(Handle);
+impl_handle_based!(Vmo);
+impl Cookied for Vmo {}
+
+impl Vmo {
+ /// Create a virtual memory object.
+ ///
+ /// Wraps the
+ /// `zx_vmo_create`
+ /// syscall. See the
+ /// [Shared Memory: Virtual Memory Objects (VMOs)](https://fuchsia.googlesource.com/zircon/+/master/docs/concepts.md#Shared-Memory_Virtual-Memory-Objects-VMOs)
+ /// for more information.
+ pub fn create(size: u64) -> Result<Vmo, Status> {
+ let mut handle = 0;
+ let opts = 0;
+ let status = unsafe { sys::zx_vmo_create(size, opts, &mut handle) };
+ ok(status)?;
+ unsafe {
+ Ok(Vmo::from(Handle::from_raw(handle)))
+ }
+ }
+
+ /// Read from a virtual memory object.
+ ///
+ /// Wraps the `zx_vmo_read` syscall.
+ pub fn read(&self, data: &mut [u8], offset: u64) -> Result<usize, Status> {
+ unsafe {
+ let mut actual = 0;
+ let status = sys::zx_vmo_read(self.raw_handle(), data.as_mut_ptr(),
+ offset, data.len(), &mut actual);
+ ok(status).map(|()| actual)
+ }
+ }
+
+ /// Write to a virtual memory object.
+ ///
+ /// Wraps the `zx_vmo_write` syscall.
+ pub fn write(&self, data: &[u8], offset: u64) -> Result<usize, Status> {
+ unsafe {
+ let mut actual = 0;
+ let status = sys::zx_vmo_write(self.raw_handle(), data.as_ptr(),
+ offset, data.len(), &mut actual);
+ ok(status).map(|()| actual)
+ }
+ }
+
+ /// Get the size of a virtual memory object.
+ ///
+ /// Wraps the `zx_vmo_get_size` syscall.
+ pub fn get_size(&self) -> Result<u64, Status> {
+ let mut size = 0;
+ let status = unsafe { sys::zx_vmo_get_size(self.raw_handle(), &mut size) };
+ ok(status).map(|()| size)
+ }
+
+ /// Attempt to change the size of a virtual memory object.
+ ///
+ /// Wraps the `zx_vmo_set_size` syscall.
+ pub fn set_size(&self, size: u64) -> Result<(), Status> {
+ let status = unsafe { sys::zx_vmo_set_size(self.raw_handle(), size) };
+ ok(status)
+ }
+
+ /// Perform an operation on a range of a virtual memory object.
+ ///
+ /// Wraps the
+ /// [zx_vmo_op_range](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/vmo_op_range.md)
+ /// syscall.
+ pub fn op_range(&self, op: VmoOp, offset: u64, size: u64) -> Result<(), Status> {
+ let status = unsafe {
+ sys::zx_vmo_op_range(self.raw_handle(), op.into_raw(), offset, size, ptr::null_mut(), 0)
+ };
+ ok(status)
+ }
+
+ /// Look up a list of physical addresses corresponding to the pages held by the VMO from
+ /// `offset` to `offset`+`size`, and store them in `buffer`.
+ ///
+ /// Wraps the
+ /// [zx_vmo_op_range](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/vmo_op_range.md)
+ /// syscall with ZX_VMO_OP_LOOKUP.
+ pub fn lookup(&self, offset: u64, size: u64, buffer: &mut [sys::zx_paddr_t])
+ -> Result<(), Status>
+ {
+ let status = unsafe {
+ sys::zx_vmo_op_range(self.raw_handle(), VmoOp::LOOKUP.into_raw(), offset, size,
+ buffer.as_mut_ptr() as *mut u8, buffer.len() * mem::size_of::<sys::zx_paddr_t>())
+ };
+ ok(status)
+ }
+
+ /// Create a new virtual memory object that clones a range of this one.
+ ///
+ /// Wraps the
+ /// [zx_vmo_clone](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/vmo_clone.md)
+ /// syscall.
+ pub fn clone(&self, offset: u64, size: u64) -> Result<Vmo, Status> {
+ let mut out = 0;
+ let opts = sys::ZX_VMO_CLONE_COPY_ON_WRITE;
+ let status = unsafe {
+ sys::zx_vmo_clone(self.raw_handle(), opts, offset, size, &mut out)
+ };
+ ok(status)?;
+ unsafe { Ok(Vmo::from(Handle::from_raw(out))) }
+ }
+}
+
+/// VM Object opcodes
+#[repr(C)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub struct VmoOp(u32);
+impl VmoOp {
+ pub fn from_raw(raw: u32) -> VmoOp {
+ VmoOp(raw)
+ }
+ pub fn into_raw(self) -> u32 {
+ self.0
+ }
+}
+
+assoc_consts!(VmoOp, [
+ COMMIT = sys::ZX_VMO_OP_COMMIT;
+ DECOMMIT = sys::ZX_VMO_OP_DECOMMIT;
+ LOCK = sys::ZX_VMO_OP_LOCK;
+ UNLOCK = sys::ZX_VMO_OP_UNLOCK;
+ LOOKUP = sys::ZX_VMO_OP_LOOKUP;
+ CACHE_SYNC = sys::ZX_VMO_OP_CACHE_SYNC;
+ CACHE_INVALIDATE = sys::ZX_VMO_OP_CACHE_INVALIDATE;
+ CACHE_CLEAN = sys::ZX_VMO_OP_CACHE_CLEAN;
+ CACHE_CLEAN_INVALIDATE = sys::ZX_VMO_OP_CACHE_CLEAN_INVALIDATE;
+]);
+
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn vmo_get_size() {
+ let size = 16 * 1024 * 1024;
+ let vmo = Vmo::create(size).unwrap();
+ assert_eq!(size, vmo.get_size().unwrap());
+ }
+
+ #[test]
+ fn vmo_set_size() {
+ let start_size = 12;
+ let vmo = Vmo::create(start_size).unwrap();
+ assert_eq!(start_size, vmo.get_size().unwrap());
+
+ // Change the size and make sure the new size is reported
+ let new_size = 23;
+ assert!(vmo.set_size(new_size).is_ok());
+ assert_eq!(new_size, vmo.get_size().unwrap());
+ }
+
+ #[test]
+ fn vmo_read_write() {
+ let mut vec1 = vec![0; 16];
+ let vmo = Vmo::create(vec1.len() as u64).unwrap();
+ assert_eq!(vmo.write(b"abcdef", 0), Ok(6));
+ assert_eq!(16, vmo.read(&mut vec1, 0).unwrap());
+ assert_eq!(b"abcdef", &vec1[0..6]);
+ assert_eq!(vmo.write(b"123", 2), Ok(3));
+ assert_eq!(16, vmo.read(&mut vec1, 0).unwrap());
+ assert_eq!(b"ab123f", &vec1[0..6]);
+ assert_eq!(15, vmo.read(&mut vec1, 1).unwrap());
+ assert_eq!(b"b123f", &vec1[0..5]);
+ }
+
+ #[test]
+ fn vmo_op_range_unsupported() {
+ let vmo = Vmo::create(12).unwrap();
+ assert_eq!(vmo.op_range(VmoOp::LOCK, 0, 1), Err(Status::NOT_SUPPORTED));
+ assert_eq!(vmo.op_range(VmoOp::UNLOCK, 0, 1), Err(Status::NOT_SUPPORTED));
+ }
+
+ #[test]
+ fn vmo_lookup() {
+ let vmo = Vmo::create(12).unwrap();
+ let mut buffer = vec![0; 2];
+
+ // Lookup will fail as it is not committed yet.
+ assert_eq!(vmo.lookup(0, 12, &mut buffer), Err(Status::NO_MEMORY));
+
+ // COMMIT and try again.
+ assert_eq!(vmo.op_range(VmoOp::COMMIT, 0, 12), Ok(()));
+ assert_eq!(vmo.lookup(0, 12, &mut buffer), Ok(()));
+ assert_ne!(buffer[0], 0);
+ assert_eq!(buffer[1], 0);
+
+ // If we decommit then lookup should go back to failing.
+ assert_eq!(vmo.op_range(VmoOp::DECOMMIT, 0, 12), Ok(()));
+ assert_eq!(vmo.lookup(0, 12, &mut buffer), Err(Status::NO_MEMORY));
+ }
+
+ #[test]
+ fn vmo_cache() {
+ let vmo = Vmo::create(12).unwrap();
+
+ // Cache operations should all succeed.
+ assert_eq!(vmo.op_range(VmoOp::CACHE_SYNC, 0, 12), Ok(()));
+ assert_eq!(vmo.op_range(VmoOp::CACHE_INVALIDATE, 0, 12), Ok(()));
+ assert_eq!(vmo.op_range(VmoOp::CACHE_CLEAN, 0, 12), Ok(()));
+ assert_eq!(vmo.op_range(VmoOp::CACHE_CLEAN_INVALIDATE, 0, 12), Ok(()));
+ }
+
+ #[test]
+ fn vmo_clone() {
+ let original = Vmo::create(12).unwrap();
+ assert_eq!(original.write(b"one", 0), Ok(3));
+
+ // Clone the VMO, and make sure it contains what we expect.
+ let clone = original.clone(0, 10).unwrap();
+ let mut read_buffer = vec![0; 16];
+ assert_eq!(clone.read(&mut read_buffer, 0), Ok(10));
+ assert_eq!(&read_buffer[0..3], b"one");
+
+ // Writing to the original will affect the clone too, surprisingly.
+ assert_eq!(original.write(b"two", 0), Ok(3));
+ assert_eq!(original.read(&mut read_buffer, 0), Ok(12));
+ assert_eq!(&read_buffer[0..3], b"two");
+ assert_eq!(clone.read(&mut read_buffer, 0), Ok(10));
+ assert_eq!(&read_buffer[0..3], b"two");
+
+ // However, writing to the clone will not affect the original
+ assert_eq!(clone.write(b"three", 0), Ok(5));
+ assert_eq!(original.read(&mut read_buffer, 0), Ok(12));
+ assert_eq!(&read_buffer[0..3], b"two");
+ assert_eq!(clone.read(&mut read_buffer, 0), Ok(10));
+ assert_eq!(&read_buffer[0..5], b"three");
+
+ // And now that the copy-on-write has happened, writing to the original will not affect the
+ // clone. How bizarre.
+ assert_eq!(original.write(b"four", 0), Ok(4));
+ assert_eq!(original.read(&mut read_buffer, 0), Ok(12));
+ assert_eq!(&read_buffer[0..4], b"four");
+ assert_eq!(clone.read(&mut read_buffer, 0), Ok(10));
+ assert_eq!(&read_buffer[0..5], b"three");
+ }
+}
diff --git a/third_party/rust/fuchsia-zircon/tools/gen_status.py b/third_party/rust/fuchsia-zircon/tools/gen_status.py
new file mode 100755
index 0000000000..c2a954bdb1
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/tools/gen_status.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+
+# 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.
+
+# A tool for autogenerating the mapping between Status and zx_status_t
+# Usage: python gen_status.py zircon/system/public/zircon/errors.h {sys,enum,match}
+import re
+import sys
+
+status_re = re.compile('#define\s+(ZX_\w+)\s+\((\-?\d+)\)$')
+
+def parse(in_filename):
+ result = []
+ for line in file(in_filename):
+ m = status_re.match(line)
+ if m:
+ result.append((m.group(1), int(m.group(2))))
+ return result
+
+def to_snake_case(name):
+ result = []
+ for element in name.split('_'):
+ result.append(element[0] + element[1:].lower())
+ return ''.join(result)
+
+def out(style, l):
+ print('// Auto-generated using tools/gen_status.py')
+ longest = max(len(name) for (name, num) in l)
+ if style == 'sys':
+ for (name, num) in l:
+ print('pub const %s : zx_status_t = %d;' % (name.ljust(longest), num))
+ if style == 'enum':
+ print('pub enum Status {')
+ for (name, num) in l:
+ print(' %s = %d,' % (to_snake_case(name[3:]), num))
+ print('');
+ print(' /// Any zx_status_t not in the set above will map to the following:')
+ print(' UnknownOther = -32768,')
+ print('}')
+ if style == 'match':
+ for (name, num) in l:
+ print(' sys::%s => Status::%s,' % (name, to_snake_case(name[3:])))
+ print(' _ => Status::UnknownOther,')
+
+
+l = parse(sys.argv[1])
+out(sys.argv[2], l)