about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-01-14 08:49:10 +0000
committerbors <bors@rust-lang.org>2018-01-14 08:49:10 +0000
commit48ab4cde5460f9f7c57249e4e62ad569dc843dd8 (patch)
tree21ff4881b0ad83bbec006f25dc9a567073ca4a0e /src
parentfd0f29237c9562efef25fb30f03df24edb1e2042 (diff)
parent6a8d55a235e1ce6336dff162aae3feef9f7873b4 (diff)
downloadrust-48ab4cde5460f9f7c57249e4e62ad569dc843dd8.tar.gz
rust-48ab4cde5460f9f7c57249e4e62ad569dc843dd8.zip
Auto merge of #47268 - EdSchouten:cloudabi-libstd, r=alexcrichton
Implement libstd for CloudABI.

Though CloudABI is strongly inspired by POSIX, its absence of features that don't work well with capability-based sandboxing makes it different enough that adding bits to `sys/unix` will make things a mess. This change therefore adds CloudABI specific platform code under `sys/cloudabi`.

One of the goals of this implementation is to build as much as possible directly on top of CloudABI's system call layer, as opposed to using the C library. This is preferred, as the system call layer is supposed to be stable, whereas the C library ABI technically is not. An advantage of this approach is that it allows us to implement certain interfaces, such as mutexes and condition variables more optimally. They can be lighter than the ones provided by pthreads.

This change disables some modules that cannot realistically be implemented right now. For example, libstd's pathname abstraction is not designed with POSIX `*at()` (e.g., `openat()`) in mind. The `*at()` functions are the only set of file system APIs available on CloudABI. There is no global file system namespace, nor a process working directory. Discussions on how to port these modules over are outside the scope of this change.
Diffstat (limited to 'src')
-rw-r--r--src/libstd/env.rs11
-rw-r--r--src/libstd/fs.rs2
-rw-r--r--src/libstd/net/tcp.rs2
-rw-r--r--src/libstd/net/udp.rs2
-rw-r--r--src/libstd/process.rs2
-rw-r--r--src/libstd/sys/cloudabi/abi/bitflags.rs51
-rw-r--r--src/libstd/sys/cloudabi/abi/cloudabi.rs2847
-rw-r--r--src/libstd/sys/cloudabi/abi/mod.rs13
-rw-r--r--src/libstd/sys/cloudabi/args.rs17
-rw-r--r--src/libstd/sys/cloudabi/backtrace.rs121
-rw-r--r--src/libstd/sys/cloudabi/condvar.rs169
-rw-r--r--src/libstd/sys/cloudabi/mod.rs76
-rw-r--r--src/libstd/sys/cloudabi/mutex.rs158
-rw-r--r--src/libstd/sys/cloudabi/os.rs37
-rw-r--r--src/libstd/sys/cloudabi/rwlock.rs237
-rw-r--r--src/libstd/sys/cloudabi/shims/args.rs45
-rw-r--r--src/libstd/sys/cloudabi/shims/env.rs19
-rw-r--r--src/libstd/sys/cloudabi/shims/fs.rs302
-rw-r--r--src/libstd/sys/cloudabi/shims/mod.rs32
-rw-r--r--src/libstd/sys/cloudabi/shims/net.rs296
-rw-r--r--src/libstd/sys/cloudabi/shims/os.rs95
-rw-r--r--src/libstd/sys/cloudabi/shims/pipe.rs32
-rw-r--r--src/libstd/sys/cloudabi/shims/process.rs147
-rw-r--r--src/libstd/sys/cloudabi/stack_overflow.rs23
-rw-r--r--src/libstd/sys/cloudabi/stdio.rs79
-rw-r--r--src/libstd/sys/cloudabi/thread.rs124
-rw-r--r--src/libstd/sys/cloudabi/time.rs111
-rw-r--r--src/libstd/sys/mod.rs15
-rw-r--r--src/libstd/sys_common/mod.rs2
-rw-r--r--src/tools/tidy/src/pal.rs4
30 files changed, 5057 insertions, 14 deletions
diff --git a/src/libstd/env.rs b/src/libstd/env.rs
index ed34c1204b3..27bf326631f 100644
--- a/src/libstd/env.rs
+++ b/src/libstd/env.rs
@@ -956,8 +956,7 @@ mod arch {
 mod tests {
     use super::*;
 
-    use ffi::OsStr;
-    use path::{Path, PathBuf};
+    use path::Path;
 
     #[test]
     #[cfg_attr(target_os = "emscripten", ignore)]
@@ -980,6 +979,8 @@ mod tests {
     #[test]
     #[cfg(windows)]
     fn split_paths_windows() {
+        use path::PathBuf;
+
         fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
             split_paths(unparsed).collect::<Vec<_>>() ==
                 parsed.iter().map(|s| PathBuf::from(*s)).collect::<Vec<_>>()
@@ -1000,6 +1001,8 @@ mod tests {
     #[test]
     #[cfg(unix)]
     fn split_paths_unix() {
+        use path::PathBuf;
+
         fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
             split_paths(unparsed).collect::<Vec<_>>() ==
                 parsed.iter().map(|s| PathBuf::from(*s)).collect::<Vec<_>>()
@@ -1015,6 +1018,8 @@ mod tests {
     #[test]
     #[cfg(unix)]
     fn join_paths_unix() {
+        use ffi::OsStr;
+
         fn test_eq(input: &[&str], output: &str) -> bool {
             &*join_paths(input.iter().cloned()).unwrap() ==
                 OsStr::new(output)
@@ -1031,6 +1036,8 @@ mod tests {
     #[test]
     #[cfg(windows)]
     fn join_paths_windows() {
+        use ffi::OsStr;
+
         fn test_eq(input: &[&str], output: &str) -> bool {
             &*join_paths(input.iter().cloned()).unwrap() ==
                 OsStr::new(output)
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index 51cb9609120..4e0ff450cab 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -1989,7 +1989,7 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
     }
 }
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))]
 mod tests {
     use io::prelude::*;
 
diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs
index 539ff1df187..78235ea1b4b 100644
--- a/src/libstd/net/tcp.rs
+++ b/src/libstd/net/tcp.rs
@@ -885,7 +885,7 @@ impl fmt::Debug for TcpListener {
     }
 }
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))]
 mod tests {
     use io::ErrorKind;
     use io::prelude::*;
diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs
index 84ceaa65951..fc7f9205d06 100644
--- a/src/libstd/net/udp.rs
+++ b/src/libstd/net/udp.rs
@@ -786,7 +786,7 @@ impl fmt::Debug for UdpSocket {
     }
 }
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))]
 mod tests {
     use io::ErrorKind;
     use net::*;
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index 33e8a87a0b6..5c66ac6ddde 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -1392,7 +1392,7 @@ pub fn id() -> u32 {
     ::sys::os::getpid()
 }
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))]
 mod tests {
     use io::prelude::*;
 
diff --git a/src/libstd/sys/cloudabi/abi/bitflags.rs b/src/libstd/sys/cloudabi/abi/bitflags.rs
new file mode 100644
index 00000000000..f764cc1df5a
--- /dev/null
+++ b/src/libstd/sys/cloudabi/abi/bitflags.rs
@@ -0,0 +1,51 @@
+// Copyright (c) 2018 Nuxi (https://nuxi.nl/) and contributors.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. 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.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+
+// Appease Rust's tidy.
+// ignore-license
+
+#[cfg(feature = "bitflags")]
+#[macro_use]
+extern crate bitflags;
+
+// Minimal implementation of bitflags! in case we can't depend on the bitflags
+// crate. Only implements `bits()` and a `from_bits_truncate()` that doesn't
+// actually truncate.
+#[cfg(not(feature = "bitflags"))]
+macro_rules! bitflags {
+  (
+    $(#[$attr:meta])*
+    pub struct $name:ident: $type:ty {
+      $($(#[$const_attr:meta])* const $const:ident = $val:expr;)*
+    }
+  ) => {
+    $(#[$attr])*
+    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+    pub struct $name { bits: $type }
+    impl $name {
+      $($(#[$const_attr])* pub const $const: $name = $name{ bits: $val };)*
+      pub fn bits(&self) -> $type { self.bits }
+      pub fn from_bits_truncate(bits: $type) -> Self { $name{ bits } }
+    }
+  }
+}
diff --git a/src/libstd/sys/cloudabi/abi/cloudabi.rs b/src/libstd/sys/cloudabi/abi/cloudabi.rs
new file mode 100644
index 00000000000..2909db5098e
--- /dev/null
+++ b/src/libstd/sys/cloudabi/abi/cloudabi.rs
@@ -0,0 +1,2847 @@
+// Copyright (c) 2016-2017 Nuxi (https://nuxi.nl/) and contributors.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. 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.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+//
+// This file is automatically generated. Do not edit.
+//
+// Source: https://github.com/NuxiNL/cloudabi
+
+// Appease Rust's tidy.
+// ignore-license
+// ignore-tidy-linelength
+
+//! **PLEASE NOTE: This entire crate including this
+//! documentation is automatically generated from
+//! [`cloudabi.txt`](https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt)**
+//!
+//! # Nuxi CloudABI
+//!
+//! CloudABI is what you get if you take POSIX, add capability-based
+//! security, and remove everything that's incompatible with that. The
+//! result is a minimal ABI consisting of only 49 syscalls.
+//!
+//! CloudABI doesn't have its own kernel, but instead is implemented in existing
+//! kernels: FreeBSD has CloudABI support for x86-64 and arm64, and [a patch-set
+//! for NetBSD](https://github.com/NuxiNL/netbsd) and [a patch-set for
+//! Linux](https://github.com/NuxiNL/linux) are available as well. This means that
+//! CloudABI binaries can be executed on different operating systems, without any
+//! modification.
+//!
+//! ## Capability-Based Security
+//!
+//! Capability-based security means that processes can only perform
+//! actions that have no global impact. Processes cannot open files by
+//! their absolute path, cannot open network connections, and cannot
+//! observe global system state such as the process table.
+//!
+//! The capabilities of a process are fully determined by its set of open
+//! file descriptors (fds). For example, files can only be opened if the
+//! process already has a file descriptor to a directory the file is in.
+//!
+//! Unlike in POSIX, where processes are normally started with file
+//! descriptors 0, 1, and 2 reserved for standard input, output, and
+//! error, CloudABI does not reserve any file descriptor numbers for
+//! specific purposes.
+//!
+//! In CloudABI, a process depends on its parent process to launch it with
+//! the right set of resources, since the process will not be able to open
+//! any new resources. For example, a simple static web server would need
+//! to be started with a file descriptor to a [TCP
+//! listener](https://github.com/NuxiNL/flower), and a file descriptor to
+//! the directory for which to serve files. The web server will then be
+//! unable to do anything other than reading files in that directory, and
+//! process incoming network connections.
+//!
+//! So, unknown CloudABI binaries can safely be executed without the need
+//! for containers, virtual machines, or other sandboxing technologies.
+//!
+//! Watch [Ed Schouten's Talk at
+//! 32C3](https://www.youtube.com/watch?v=3N29vrPoDv8) for more
+//! information about what capability-based security for UNIX means.
+//!
+//! ## Cloudlibc
+//!
+//! [Cloudlibc](https://github.com/NuxiNL/cloudlibc) is an implementation
+//! of the C standard library, without all CloudABI-incompatible
+//! functions. For example, Cloudlibc does not have `printf`, but does
+//! have `fprintf`. It does not have `open`, but does have `openat`.
+//!
+//! ## CloudABI-Ports
+//!
+//! [CloudABI-Ports](https://github.com/NuxiNL/cloudabi-ports) is a
+//! collection of ports of commonly used libraries and applications to
+//! CloudABI. It contains software such as `zlib`, `libpng`, `boost`,
+//! `memcached`, and much more. The software is patched to not depend on
+//! any global state, such as files in `/etc` or `/dev`, using `open()`,
+//! etc.
+//!
+//! ## Using CloudABI
+//!
+//! Instructions for using CloudABI (including kernel modules/patches,
+//! toolchain, and ports) are available for several operating systems:
+//!
+//! - [Arch Linux](https://nuxi.nl/cloudabi/archlinux/)
+//! - [Debian, Ubuntu, and other Debian derivatives](https://nuxi.nl/cloudabi/debian/)
+//! - [FreeBSD, PC-BSD and DragonFly BSD](https://nuxi.nl/cloudabi/freebsd/)
+//! - [Mac OS X](https://nuxi.nl/cloudabi/mac/)
+//! - [NetBSD](https://nuxi.nl/cloudabi/netbsd/)
+//!
+//! ## Specification of the ABI
+//!
+//! The entire ABI is specified in a a file called
+//! [`cloudabi.txt`](https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt),
+//! from which all
+//! [headers](https://github.com/NuxiNL/cloudabi/tree/master/headers)
+//! and documentation (including the one you're reading now) is generated.
+
+#![no_std]
+#![allow(non_camel_case_types)]
+
+include!("bitflags.rs");
+
+/// File or memory access pattern advisory information.
+#[repr(u8)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub enum advice {
+  /// The application expects that it will not access the
+  /// specified data in the near future.
+  DONTNEED   = 1,
+  /// The application expects to access the specified data
+  /// once and then not reuse it thereafter.
+  NOREUSE    = 2,
+  /// The application has no advice to give on its behavior
+  /// with respect to the specified data.
+  NORMAL     = 3,
+  /// The application expects to access the specified data
+  /// in a random order.
+  RANDOM     = 4,
+  /// The application expects to access the specified data
+  /// sequentially from lower offsets to higher offsets.
+  SEQUENTIAL = 5,
+  /// The application expects to access the specified data
+  /// in the near future.
+  WILLNEED   = 6,
+  #[doc(hidden)] _NonExhaustive = -1 as isize as u8,
+}
+
+/// Enumeration describing the kind of value stored in [`auxv`](struct.auxv.html).
+#[repr(u32)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub enum auxtype {
+  /// Base address of the binary argument data provided to
+  /// [`proc_exec()`](fn.proc_exec.html).
+  ARGDATA      = 256,
+  /// Length of the binary argument data provided to
+  /// [`proc_exec()`](fn.proc_exec.html).
+  ARGDATALEN   = 257,
+  /// Base address at which the executable is placed in
+  /// memory.
+  BASE         =   7,
+  /// Base address of a buffer of random data that may be
+  /// used for non-cryptographic purposes, for example as a
+  /// canary for stack smashing protection.
+  CANARY       = 258,
+  /// Length of a buffer of random data that may be used
+  /// for non-cryptographic purposes, for example as a
+  /// canary for stack smashing protection.
+  CANARYLEN    = 259,
+  /// Number of CPUs that the system this process is running
+  /// on has.
+  NCPUS        = 260,
+  /// Terminator of the auxiliary vector.
+  NULL         =   0,
+  /// Smallest memory object size for which individual
+  /// memory protection controls can be configured.
+  PAGESZ       =   6,
+  /// Address of the first ELF program header of the
+  /// executable.
+  PHDR         =   3,
+  /// Number of ELF program headers of the executable.
+  PHNUM        =   4,
+  /// Identifier of the process.
+  ///
+  /// This environment does not provide any simple numerical
+  /// process identifiers, for the reason that these are not
+  /// useful in distributed contexts. Instead, processes are
+  /// identified by a UUID.
+  ///
+  /// This record should point to sixteen bytes of binary
+  /// data, containing a version 4 UUID (fully random).
+  PID          = 263,
+  /// Address of the ELF header of the vDSO.
+  ///
+  /// The vDSO is a shared library that is mapped in the
+  /// address space of the process. It provides entry points
+  /// for every system call supported by the environment,
+  /// all having a corresponding symbol that is prefixed
+  /// with `cloudabi_sys_`. System calls should be invoked
+  /// through these entry points.
+  ///
+  /// The first advantage of letting processes call into a
+  /// vDSO to perform system calls instead of raising
+  /// hardware traps is that it allows for easy emulation of
+  /// executables on top of existing operating systems. The
+  /// second advantage is that in cases where an operating
+  /// system provides native support for CloudABI executables,
+  /// it may still implement partial userspace
+  /// implementations of these system calls to improve
+  /// performance (e.g., [`clock_time_get()`](fn.clock_time_get.html)). It also provides
+  /// a more dynamic way of adding, removing or replacing
+  /// system calls.
+  SYSINFO_EHDR = 262,
+  /// Thread ID of the initial thread of the process.
+  TID          = 261,
+  #[doc(hidden)] _NonExhaustive = -1 as isize as u32,
+}
+
+/// Identifiers for clocks.
+#[repr(u32)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub enum clockid {
+  /// The system-wide monotonic clock, which is defined as a
+  /// clock measuring real time, whose value cannot be
+  /// adjusted and which cannot have negative clock jumps.
+  ///
+  /// The epoch of this clock is undefined. The absolute
+  /// time value of this clock therefore has no meaning.
+  MONOTONIC          = 1,
+  /// The CPU-time clock associated with the current
+  /// process.
+  PROCESS_CPUTIME_ID = 2,
+  /// The system-wide clock measuring real time. Time value
+  /// zero corresponds with 1970-01-01T00:00:00Z.
+  REALTIME           = 3,
+  /// The CPU-time clock associated with the current thread.
+  THREAD_CPUTIME_ID  = 4,
+  #[doc(hidden)] _NonExhaustive = -1 as isize as u32,
+}
+
+/// A userspace condition variable.
+#[repr(C)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub struct condvar(pub u32);
+/// The condition variable is in its initial state. There
+/// are no threads waiting to be woken up. If the
+/// condition variable has any other value, the kernel
+/// must be called to wake up any sleeping threads.
+pub const CONDVAR_HAS_NO_WAITERS: condvar = condvar(0);
+
+/// Identifier for a device containing a file system. Can be used
+/// in combination with [`inode`](struct.inode.html) to uniquely identify a file on the
+/// local system.
+#[repr(C)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub struct device(pub u64);
+
+/// A reference to the offset of a directory entry.
+#[repr(C)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub struct dircookie(pub u64);
+/// Permanent reference to the first directory entry
+/// within a directory.
+pub const DIRCOOKIE_START: dircookie = dircookie(0);
+
+/// Error codes returned by system calls.
+///
+/// Not all of these error codes are returned by the system calls
+/// provided by this environment, but are either used in userspace
+/// exclusively or merely provided for alignment with POSIX.
+#[repr(u16)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub enum errno {
+  /// No error occurred. System call completed successfully.
+  SUCCESS        =  0,
+  /// Argument list too long.
+  TOOBIG         =  1,
+  /// Permission denied.
+  ACCES          =  2,
+  /// Address in use.
+  ADDRINUSE      =  3,
+  /// Address not available.
+  ADDRNOTAVAIL   =  4,
+  /// Address family not supported.
+  AFNOSUPPORT    =  5,
+  /// Resource unavailable, or operation would block.
+  AGAIN          =  6,
+  /// Connection already in progress.
+  ALREADY        =  7,
+  /// Bad file descriptor.
+  BADF           =  8,
+  /// Bad message.
+  BADMSG         =  9,
+  /// Device or resource busy.
+  BUSY           = 10,
+  /// Operation canceled.
+  CANCELED       = 11,
+  /// No child processes.
+  CHILD          = 12,
+  /// Connection aborted.
+  CONNABORTED    = 13,
+  /// Connection refused.
+  CONNREFUSED    = 14,
+  /// Connection reset.
+  CONNRESET      = 15,
+  /// Resource deadlock would occur.
+  DEADLK         = 16,
+  /// Destination address required.
+  DESTADDRREQ    = 17,
+  /// Mathematics argument out of domain of function.
+  DOM            = 18,
+  /// Reserved.
+  DQUOT          = 19,
+  /// File exists.
+  EXIST          = 20,
+  /// Bad address.
+  FAULT          = 21,
+  /// File too large.
+  FBIG           = 22,
+  /// Host is unreachable.
+  HOSTUNREACH    = 23,
+  /// Identifier removed.
+  IDRM           = 24,
+  /// Illegal byte sequence.
+  ILSEQ          = 25,
+  /// Operation in progress.
+  INPROGRESS     = 26,
+  /// Interrupted function.
+  INTR           = 27,
+  /// Invalid argument.
+  INVAL          = 28,
+  /// I/O error.
+  IO             = 29,
+  /// Socket is connected.
+  ISCONN         = 30,
+  /// Is a directory.
+  ISDIR          = 31,
+  /// Too many levels of symbolic links.
+  LOOP           = 32,
+  /// File descriptor value too large.
+  MFILE          = 33,
+  /// Too many links.
+  MLINK          = 34,
+  /// Message too large.
+  MSGSIZE        = 35,
+  /// Reserved.
+  MULTIHOP       = 36,
+  /// Filename too long.
+  NAMETOOLONG    = 37,
+  /// Network is down.
+  NETDOWN        = 38,
+  /// Connection aborted by network.
+  NETRESET       = 39,
+  /// Network unreachable.
+  NETUNREACH     = 40,
+  /// Too many files open in system.
+  NFILE          = 41,
+  /// No buffer space available.
+  NOBUFS         = 42,
+  /// No such device.
+  NODEV          = 43,
+  /// No such file or directory.
+  NOENT          = 44,
+  /// Executable file format error.
+  NOEXEC         = 45,
+  /// No locks available.
+  NOLCK          = 46,
+  /// Reserved.
+  NOLINK         = 47,
+  /// Not enough space.
+  NOMEM          = 48,
+  /// No message of the desired type.
+  NOMSG          = 49,
+  /// Protocol not available.
+  NOPROTOOPT     = 50,
+  /// No space left on device.
+  NOSPC          = 51,
+  /// Function not supported.
+  NOSYS          = 52,
+  /// The socket is not connected.
+  NOTCONN        = 53,
+  /// Not a directory or a symbolic link to a directory.
+  NOTDIR         = 54,
+  /// Directory not empty.
+  NOTEMPTY       = 55,
+  /// State not recoverable.
+  NOTRECOVERABLE = 56,
+  /// Not a socket.
+  NOTSOCK        = 57,
+  /// Not supported, or operation not supported on socket.
+  NOTSUP         = 58,
+  /// Inappropriate I/O control operation.
+  NOTTY          = 59,
+  /// No such device or address.
+  NXIO           = 60,
+  /// Value too large to be stored in data type.
+  OVERFLOW       = 61,
+  /// Previous owner died.
+  OWNERDEAD      = 62,
+  /// Operation not permitted.
+  PERM           = 63,
+  /// Broken pipe.
+  PIPE           = 64,
+  /// Protocol error.
+  PROTO          = 65,
+  /// Protocol not supported.
+  PROTONOSUPPORT = 66,
+  /// Protocol wrong type for socket.
+  PROTOTYPE      = 67,
+  /// Result too large.
+  RANGE          = 68,
+  /// Read-only file system.
+  ROFS           = 69,
+  /// Invalid seek.
+  SPIPE          = 70,
+  /// No such process.
+  SRCH           = 71,
+  /// Reserved.
+  STALE          = 72,
+  /// Connection timed out.
+  TIMEDOUT       = 73,
+  /// Text file busy.
+  TXTBSY         = 74,
+  /// Cross-device link.
+  XDEV           = 75,
+  /// Extension: Capabilities insufficient.
+  NOTCAPABLE     = 76,
+  #[doc(hidden)] _NonExhaustive = -1 as isize as u16,
+}
+
+bitflags! {
+  /// The state of the file descriptor subscribed to with
+  /// [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE).
+  #[repr(C)]
+  pub struct eventrwflags: u16 {
+    /// The peer of this socket has closed or disconnected.
+    const HANGUP = 0x0001;
+  }
+}
+
+/// Type of a subscription to an event or its occurrence.
+#[repr(u8)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub enum eventtype {
+  /// The time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id)
+  /// has reached timestamp [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout).
+  CLOCK          = 1,
+  /// Condition variable [`subscription.union.condvar.condvar`](struct.subscription_condvar.html#structfield.condvar) has
+  /// been woken up and [`subscription.union.condvar.lock`](struct.subscription_condvar.html#structfield.lock) has been
+  /// acquired for writing.
+  CONDVAR        = 2,
+  /// File descriptor [`subscription.union.fd_readwrite.fd`](struct.subscription_fd_readwrite.html#structfield.fd) has
+  /// data available for reading. This event always triggers
+  /// for regular files.
+  FD_READ        = 3,
+  /// File descriptor [`subscription.union.fd_readwrite.fd`](struct.subscription_fd_readwrite.html#structfield.fd) has
+  /// capacity available for writing. This event always
+  /// triggers for regular files.
+  FD_WRITE       = 4,
+  /// Lock [`subscription.union.lock.lock`](struct.subscription_lock.html#structfield.lock) has been acquired for
+  /// reading.
+  LOCK_RDLOCK    = 5,
+  /// Lock [`subscription.union.lock.lock`](struct.subscription_lock.html#structfield.lock) has been acquired for
+  /// writing.
+  LOCK_WRLOCK    = 6,
+  /// The process associated with process descriptor
+  /// [`subscription.union.proc_terminate.fd`](struct.subscription_proc_terminate.html#structfield.fd) has terminated.
+  PROC_TERMINATE = 7,
+  #[doc(hidden)] _NonExhaustive = -1 as isize as u8,
+}
+
+/// Exit code generated by a process when exiting.
+pub type exitcode = u32;
+
+/// A file descriptor number.
+///
+/// Unlike on POSIX-compliant systems, none of the file descriptor
+/// numbers are reserved for a purpose (e.g., stdin, stdout,
+/// stderr). Operating systems are not required to allocate new
+/// file descriptors in ascending order.
+#[repr(C)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub struct fd(pub u32);
+/// Returned to the child process by [`proc_fork()`](fn.proc_fork.html).
+pub const PROCESS_CHILD: fd = fd(0xffffffff);
+/// Passed to [`mem_map()`](fn.mem_map.html) when creating a mapping to
+/// anonymous memory.
+pub const MAP_ANON_FD  : fd = fd(0xffffffff);
+
+bitflags! {
+  /// File descriptor flags.
+  #[repr(C)]
+  pub struct fdflags: u16 {
+    /// Append mode: Data written to the file is always
+    /// appended to the file's end.
+    const APPEND   = 0x0001;
+    /// Write according to synchronized I/O data integrity
+    /// completion. Only the data stored in the file is
+    /// synchronized.
+    const DSYNC    = 0x0002;
+    /// Non-blocking mode.
+    const NONBLOCK = 0x0004;
+    /// Synchronized read I/O operations.
+    const RSYNC    = 0x0008;
+    /// Write according to synchronized I/O file integrity
+    /// completion. In addition to synchronizing the data
+    /// stored in the file, the system may also synchronously
+    /// update the file's metadata.
+    const SYNC     = 0x0010;
+  }
+}
+
+bitflags! {
+  /// Which file descriptor attributes to adjust.
+  #[repr(C)]
+  pub struct fdsflags: u16 {
+    /// Adjust the file descriptor flags stored in
+    /// [`fdstat.fs_flags`](struct.fdstat.html#structfield.fs_flags).
+    const FLAGS  = 0x0001;
+    /// Restrict the rights of the file descriptor to the
+    /// rights stored in [`fdstat.fs_rights_base`](struct.fdstat.html#structfield.fs_rights_base) and
+    /// [`fdstat.fs_rights_inheriting`](struct.fdstat.html#structfield.fs_rights_inheriting).
+    const RIGHTS = 0x0002;
+  }
+}
+
+/// Relative offset within a file.
+pub type filedelta = i64;
+
+/// Non-negative file size or length of a region within a file.
+pub type filesize = u64;
+
+/// The type of a file descriptor or file.
+#[repr(u8)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub enum filetype {
+  /// The type of the file descriptor or file is unknown or
+  /// is different from any of the other types specified.
+  UNKNOWN          =   0,
+  /// The file descriptor or file refers to a block device
+  /// inode.
+  BLOCK_DEVICE     =  16,
+  /// The file descriptor or file refers to a character
+  /// device inode.
+  CHARACTER_DEVICE =  17,
+  /// The file descriptor or file refers to a directory
+  /// inode.
+  DIRECTORY        =  32,
+  /// The file descriptor refers to a process handle.
+  PROCESS          =  80,
+  /// The file descriptor or file refers to a regular file
+  /// inode.
+  REGULAR_FILE     =  96,
+  /// The file descriptor refers to a shared memory object.
+  SHARED_MEMORY    = 112,
+  /// The file descriptor or file refers to a datagram
+  /// socket.
+  SOCKET_DGRAM     = 128,
+  /// The file descriptor or file refers to a byte-stream
+  /// socket.
+  SOCKET_STREAM    = 130,
+  /// The file refers to a symbolic link inode.
+  SYMBOLIC_LINK    = 144,
+  #[doc(hidden)] _NonExhaustive = -1 as isize as u8,
+}
+
+bitflags! {
+  /// Which file attributes to adjust.
+  #[repr(C)]
+  pub struct fsflags: u16 {
+    /// Adjust the last data access timestamp to the value
+    /// stored in [`filestat.st_atim`](struct.filestat.html#structfield.st_atim).
+    const ATIM     = 0x0001;
+    /// Adjust the last data access timestamp to the time
+    /// of clock [`REALTIME`](enum.clockid.html#variant.REALTIME).
+    const ATIM_NOW = 0x0002;
+    /// Adjust the last data modification timestamp to the
+    /// value stored in [`filestat.st_mtim`](struct.filestat.html#structfield.st_mtim).
+    const MTIM     = 0x0004;
+    /// Adjust the last data modification timestamp to the
+    /// time of clock [`REALTIME`](enum.clockid.html#variant.REALTIME).
+    const MTIM_NOW = 0x0008;
+    /// Truncate or extend the file to the size stored in
+    /// [`filestat.st_size`](struct.filestat.html#structfield.st_size).
+    const SIZE     = 0x0010;
+  }
+}
+
+/// File serial number that is unique within its file system.
+#[repr(C)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub struct inode(pub u64);
+
+/// Number of hard links to an inode.
+pub type linkcount = u32;
+
+/// A userspace read-recursive readers-writer lock, similar to a
+/// Linux futex or a FreeBSD umtx.
+#[repr(C)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub struct lock(pub u32);
+/// Value indicating that the lock is in its initial
+/// unlocked state.
+pub const LOCK_UNLOCKED      : lock = lock(0x00000000);
+/// Bitmask indicating that the lock is write-locked. If
+/// set, the lower 30 bits of the lock contain the
+/// identifier of the thread that owns the write lock.
+/// Otherwise, the lower 30 bits of the lock contain the
+/// number of acquired read locks.
+pub const LOCK_WRLOCKED      : lock = lock(0x40000000);
+/// Bitmask indicating that the lock is either read locked
+/// or write locked, and that one or more threads have
+/// their execution suspended, waiting to acquire the
+/// lock. The last owner of the lock must call the
+/// kernel to unlock.
+///
+/// When the lock is acquired for reading and this bit is
+/// set, it means that one or more threads are attempting
+/// to acquire this lock for writing. In that case, other
+/// threads should only acquire additional read locks if
+/// suspending execution would cause a deadlock. It is
+/// preferred to suspend execution, as this prevents
+/// starvation of writers.
+pub const LOCK_KERNEL_MANAGED: lock = lock(0x80000000);
+/// Value indicating that the lock is in an incorrect
+/// state. A lock cannot be in its initial unlocked state,
+/// while also managed by the kernel.
+pub const LOCK_BOGUS         : lock = lock(0x80000000);
+
+bitflags! {
+  /// Flags determining the method of how paths are resolved.
+  #[repr(C)]
+  pub struct lookupflags: u32 {
+    /// As long as the resolved path corresponds to a symbolic
+    /// link, it is expanded.
+    const SYMLINK_FOLLOW = 0x00000001;
+  }
+}
+
+bitflags! {
+  /// Memory mapping flags.
+  #[repr(C)]
+  pub struct mflags: u8 {
+    /// Instead of mapping the contents of the file provided,
+    /// create a mapping to anonymous memory. The file
+    /// descriptor argument must be set to [`MAP_ANON_FD`](constant.MAP_ANON_FD.html),
+    /// and the offset must be set to zero.
+    const ANON    = 0x01;
+    /// Require that the mapping is performed at the base
+    /// address provided.
+    const FIXED   = 0x02;
+    /// Changes are private.
+    const PRIVATE = 0x04;
+    /// Changes are shared.
+    const SHARED  = 0x08;
+  }
+}
+
+bitflags! {
+  /// Memory page protection options.
+  ///
+  /// This implementation enforces the `W^X` property: Pages cannot be
+  /// mapped for execution while also mapped for writing.
+  #[repr(C)]
+  pub struct mprot: u8 {
+    /// Page can be executed.
+    const EXEC  = 0x01;
+    /// Page can be written.
+    const WRITE = 0x02;
+    /// Page can be read.
+    const READ  = 0x04;
+  }
+}
+
+bitflags! {
+  /// Methods of synchronizing memory with physical storage.
+  #[repr(C)]
+  pub struct msflags: u8 {
+    /// Perform asynchronous writes.
+    const ASYNC      = 0x01;
+    /// Invalidate cached data.
+    const INVALIDATE = 0x02;
+    /// Perform synchronous writes.
+    const SYNC       = 0x04;
+  }
+}
+
+/// Specifies the number of threads sleeping on a condition
+/// variable that should be woken up.
+pub type nthreads = u32;
+
+bitflags! {
+  /// Open flags used by [`file_open()`](fn.file_open.html).
+  #[repr(C)]
+  pub struct oflags: u16 {
+    /// Create file if it does not exist.
+    const CREAT     = 0x0001;
+    /// Fail if not a directory.
+    const DIRECTORY = 0x0002;
+    /// Fail if file already exists.
+    const EXCL      = 0x0004;
+    /// Truncate file to size 0.
+    const TRUNC     = 0x0008;
+  }
+}
+
+bitflags! {
+  /// Flags provided to [`sock_recv()`](fn.sock_recv.html).
+  #[repr(C)]
+  pub struct riflags: u16 {
+    /// Returns the message without removing it from the
+    /// socket's receive queue.
+    const PEEK    = 0x0004;
+    /// On byte-stream sockets, block until the full amount
+    /// of data can be returned.
+    const WAITALL = 0x0010;
+  }
+}
+
+bitflags! {
+  /// File descriptor rights, determining which actions may be
+  /// performed.
+  #[repr(C)]
+  pub struct rights: u64 {
+    /// The right to invoke [`fd_datasync()`](fn.fd_datasync.html).
+    ///
+    /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to
+    /// invoke [`file_open()`](fn.file_open.html) with [`DSYNC`](struct.fdflags.html#associatedconstant.DSYNC).
+    const FD_DATASYNC           = 0x0000000000000001;
+    /// The right to invoke [`fd_read()`](fn.fd_read.html) and [`sock_recv()`](fn.sock_recv.html).
+    ///
+    /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, includes the right to
+    /// invoke [`mem_map()`](fn.mem_map.html) with memory protection option
+    /// [`READ`](struct.mprot.html#associatedconstant.READ).
+    ///
+    /// If [`FD_SEEK`](struct.rights.html#associatedconstant.FD_SEEK) is set, includes the right to invoke
+    /// [`fd_pread()`](fn.fd_pread.html).
+    const FD_READ               = 0x0000000000000002;
+    /// The right to invoke [`fd_seek()`](fn.fd_seek.html). This flag implies
+    /// [`FD_TELL`](struct.rights.html#associatedconstant.FD_TELL).
+    const FD_SEEK               = 0x0000000000000004;
+    /// The right to invoke [`fd_stat_put()`](fn.fd_stat_put.html) with
+    /// [`FLAGS`](struct.fdsflags.html#associatedconstant.FLAGS).
+    const FD_STAT_PUT_FLAGS     = 0x0000000000000008;
+    /// The right to invoke [`fd_sync()`](fn.fd_sync.html).
+    ///
+    /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to
+    /// invoke [`file_open()`](fn.file_open.html) with [`RSYNC`](struct.fdflags.html#associatedconstant.RSYNC) and
+    /// [`DSYNC`](struct.fdflags.html#associatedconstant.DSYNC).
+    const FD_SYNC               = 0x0000000000000010;
+    /// The right to invoke [`fd_seek()`](fn.fd_seek.html) in such a way that the
+    /// file offset remains unaltered (i.e., [`CUR`](enum.whence.html#variant.CUR) with
+    /// offset zero).
+    const FD_TELL               = 0x0000000000000020;
+    /// The right to invoke [`fd_write()`](fn.fd_write.html) and [`sock_send()`](fn.sock_send.html).
+    ///
+    /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, includes the right to
+    /// invoke [`mem_map()`](fn.mem_map.html) with memory protection option
+    /// [`WRITE`](struct.mprot.html#associatedconstant.WRITE).
+    ///
+    /// If [`FD_SEEK`](struct.rights.html#associatedconstant.FD_SEEK) is set, includes the right to
+    /// invoke [`fd_pwrite()`](fn.fd_pwrite.html).
+    const FD_WRITE              = 0x0000000000000040;
+    /// The right to invoke [`file_advise()`](fn.file_advise.html).
+    const FILE_ADVISE           = 0x0000000000000080;
+    /// The right to invoke [`file_allocate()`](fn.file_allocate.html).
+    const FILE_ALLOCATE         = 0x0000000000000100;
+    /// The right to invoke [`file_create()`](fn.file_create.html) with
+    /// [`DIRECTORY`](enum.filetype.html#variant.DIRECTORY).
+    const FILE_CREATE_DIRECTORY = 0x0000000000000200;
+    /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, the right to invoke
+    /// [`file_open()`](fn.file_open.html) with [`CREAT`](struct.oflags.html#associatedconstant.CREAT).
+    const FILE_CREATE_FILE      = 0x0000000000000400;
+    /// The right to invoke [`file_link()`](fn.file_link.html) with the file
+    /// descriptor as the source directory.
+    const FILE_LINK_SOURCE      = 0x0000000000001000;
+    /// The right to invoke [`file_link()`](fn.file_link.html) with the file
+    /// descriptor as the target directory.
+    const FILE_LINK_TARGET      = 0x0000000000002000;
+    /// The right to invoke [`file_open()`](fn.file_open.html).
+    const FILE_OPEN             = 0x0000000000004000;
+    /// The right to invoke [`file_readdir()`](fn.file_readdir.html).
+    const FILE_READDIR          = 0x0000000000008000;
+    /// The right to invoke [`file_readlink()`](fn.file_readlink.html).
+    const FILE_READLINK         = 0x0000000000010000;
+    /// The right to invoke [`file_rename()`](fn.file_rename.html) with the file
+    /// descriptor as the source directory.
+    const FILE_RENAME_SOURCE    = 0x0000000000020000;
+    /// The right to invoke [`file_rename()`](fn.file_rename.html) with the file
+    /// descriptor as the target directory.
+    const FILE_RENAME_TARGET    = 0x0000000000040000;
+    /// The right to invoke [`file_stat_fget()`](fn.file_stat_fget.html).
+    const FILE_STAT_FGET        = 0x0000000000080000;
+    /// The right to invoke [`file_stat_fput()`](fn.file_stat_fput.html) with
+    /// [`SIZE`](struct.fsflags.html#associatedconstant.SIZE).
+    ///
+    /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to
+    /// invoke [`file_open()`](fn.file_open.html) with [`TRUNC`](struct.oflags.html#associatedconstant.TRUNC).
+    const FILE_STAT_FPUT_SIZE   = 0x0000000000100000;
+    /// The right to invoke [`file_stat_fput()`](fn.file_stat_fput.html) with
+    /// [`ATIM`](struct.fsflags.html#associatedconstant.ATIM), [`ATIM_NOW`](struct.fsflags.html#associatedconstant.ATIM_NOW), [`MTIM`](struct.fsflags.html#associatedconstant.MTIM),
+    /// and [`MTIM_NOW`](struct.fsflags.html#associatedconstant.MTIM_NOW).
+    const FILE_STAT_FPUT_TIMES  = 0x0000000000200000;
+    /// The right to invoke [`file_stat_get()`](fn.file_stat_get.html).
+    const FILE_STAT_GET         = 0x0000000000400000;
+    /// The right to invoke [`file_stat_put()`](fn.file_stat_put.html) with
+    /// [`ATIM`](struct.fsflags.html#associatedconstant.ATIM), [`ATIM_NOW`](struct.fsflags.html#associatedconstant.ATIM_NOW), [`MTIM`](struct.fsflags.html#associatedconstant.MTIM),
+    /// and [`MTIM_NOW`](struct.fsflags.html#associatedconstant.MTIM_NOW).
+    const FILE_STAT_PUT_TIMES   = 0x0000000000800000;
+    /// The right to invoke [`file_symlink()`](fn.file_symlink.html).
+    const FILE_SYMLINK          = 0x0000000001000000;
+    /// The right to invoke [`file_unlink()`](fn.file_unlink.html).
+    const FILE_UNLINK           = 0x0000000002000000;
+    /// The right to invoke [`mem_map()`](fn.mem_map.html) with [`mprot`](struct.mprot.html) set to
+    /// zero.
+    const MEM_MAP               = 0x0000000004000000;
+    /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, the right to invoke
+    /// [`mem_map()`](fn.mem_map.html) with [`EXEC`](struct.mprot.html#associatedconstant.EXEC).
+    const MEM_MAP_EXEC          = 0x0000000008000000;
+    /// If [`FD_READ`](struct.rights.html#associatedconstant.FD_READ) is set, includes the right to
+    /// invoke [`poll()`](fn.poll.html) to subscribe to [`FD_READ`](enum.eventtype.html#variant.FD_READ).
+    ///
+    /// If [`FD_WRITE`](struct.rights.html#associatedconstant.FD_WRITE) is set, includes the right to
+    /// invoke [`poll()`](fn.poll.html) to subscribe to [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE).
+    const POLL_FD_READWRITE     = 0x0000000010000000;
+    /// The right to invoke [`poll()`](fn.poll.html) to subscribe to
+    /// [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE).
+    const POLL_PROC_TERMINATE   = 0x0000000040000000;
+    /// The right to invoke [`proc_exec()`](fn.proc_exec.html).
+    const PROC_EXEC             = 0x0000000100000000;
+    /// The right to invoke [`sock_shutdown()`](fn.sock_shutdown.html).
+    const SOCK_SHUTDOWN         = 0x0000008000000000;
+  }
+}
+
+bitflags! {
+  /// Flags returned by [`sock_recv()`](fn.sock_recv.html).
+  #[repr(C)]
+  pub struct roflags: u16 {
+    /// Returned by [`sock_recv()`](fn.sock_recv.html): List of file descriptors
+    /// has been truncated.
+    const FDS_TRUNCATED  = 0x0001;
+    /// Returned by [`sock_recv()`](fn.sock_recv.html): Message data has been
+    /// truncated.
+    const DATA_TRUNCATED = 0x0008;
+  }
+}
+
+/// Indicates whether an object is stored in private or shared
+/// memory.
+#[repr(u8)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub enum scope {
+  /// The object is stored in private memory.
+  PRIVATE = 4,
+  /// The object is stored in shared memory.
+  SHARED  = 8,
+  #[doc(hidden)] _NonExhaustive = -1 as isize as u8,
+}
+
+bitflags! {
+  /// Which channels on a socket need to be shut down.
+  #[repr(C)]
+  pub struct sdflags: u8 {
+    /// Disables further receive operations.
+    const RD = 0x01;
+    /// Disables further send operations.
+    const WR = 0x02;
+  }
+}
+
+bitflags! {
+  /// Flags provided to [`sock_send()`](fn.sock_send.html). As there are currently no flags
+  /// defined, it must be set to zero.
+  #[repr(C)]
+  pub struct siflags: u16 {
+    const DEFAULT = 0;
+  }
+}
+
+/// Signal condition.
+#[repr(u8)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub enum signal {
+  /// Process abort signal.
+  ///
+  /// Action: Terminates the process.
+  ABRT   =  1,
+  /// Alarm clock.
+  ///
+  /// Action: Terminates the process.
+  ALRM   =  2,
+  /// Access to an undefined portion of a memory object.
+  ///
+  /// Action: Terminates the process.
+  BUS    =  3,
+  /// Child process terminated, stopped, or continued.
+  ///
+  /// Action: Ignored.
+  CHLD   =  4,
+  /// Continue executing, if stopped.
+  ///
+  /// Action: Continues executing, if stopped.
+  CONT   =  5,
+  /// Erroneous arithmetic operation.
+  ///
+  /// Action: Terminates the process.
+  FPE    =  6,
+  /// Hangup.
+  ///
+  /// Action: Terminates the process.
+  HUP    =  7,
+  /// Illegal instruction.
+  ///
+  /// Action: Terminates the process.
+  ILL    =  8,
+  /// Terminate interrupt signal.
+  ///
+  /// Action: Terminates the process.
+  INT    =  9,
+  /// Kill.
+  ///
+  /// Action: Terminates the process.
+  KILL   = 10,
+  /// Write on a pipe with no one to read it.
+  ///
+  /// Action: Ignored.
+  PIPE   = 11,
+  /// Terminal quit signal.
+  ///
+  /// Action: Terminates the process.
+  QUIT   = 12,
+  /// Invalid memory reference.
+  ///
+  /// Action: Terminates the process.
+  SEGV   = 13,
+  /// Stop executing.
+  ///
+  /// Action: Stops executing.
+  STOP   = 14,
+  /// Bad system call.
+  ///
+  /// Action: Terminates the process.
+  SYS    = 15,
+  /// Termination signal.
+  ///
+  /// Action: Terminates the process.
+  TERM   = 16,
+  /// Trace/breakpoint trap.
+  ///
+  /// Action: Terminates the process.
+  TRAP   = 17,
+  /// Terminal stop signal.
+  ///
+  /// Action: Stops executing.
+  TSTP   = 18,
+  /// Background process attempting read.
+  ///
+  /// Action: Stops executing.
+  TTIN   = 19,
+  /// Background process attempting write.
+  ///
+  /// Action: Stops executing.
+  TTOU   = 20,
+  /// High bandwidth data is available at a socket.
+  ///
+  /// Action: Ignored.
+  URG    = 21,
+  /// User-defined signal 1.
+  ///
+  /// Action: Terminates the process.
+  USR1   = 22,
+  /// User-defined signal 2.
+  ///
+  /// Action: Terminates the process.
+  USR2   = 23,
+  /// Virtual timer expired.
+  ///
+  /// Action: Terminates the process.
+  VTALRM = 24,
+  /// CPU time limit exceeded.
+  ///
+  /// Action: Terminates the process.
+  XCPU   = 25,
+  /// File size limit exceeded.
+  ///
+  /// Action: Terminates the process.
+  XFSZ   = 26,
+  #[doc(hidden)] _NonExhaustive = -1 as isize as u8,
+}
+
+bitflags! {
+  /// Flags determining how the timestamp provided in
+  /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) should be interpreted.
+  #[repr(C)]
+  pub struct subclockflags: u16 {
+    /// If set, treat the timestamp provided in
+    /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) as an absolute timestamp
+    /// of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id).
+    ///
+    /// If clear, treat the timestamp provided in
+    /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) relative to the current
+    /// time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id).
+    const ABSTIME = 0x0001;
+  }
+}
+
+bitflags! {
+  /// Flags influencing the method of polling for read or writing on
+  /// a file descriptor.
+  #[repr(C)]
+  pub struct subrwflags: u16 {
+    /// Deprecated. Must be set by callers and ignored by
+    /// implementations.
+    const POLL = 0x0001;
+  }
+}
+
+/// Unique system-local identifier of a thread. This identifier is
+/// only valid during the lifetime of the thread.
+///
+/// Threads must be aware of their thread identifier, as it is
+/// written it into locks when acquiring them for writing. It is
+/// not advised to use these identifiers for any other purpose.
+///
+/// As the thread identifier is also stored in [`lock`](struct.lock.html) when
+/// [`LOCK_WRLOCKED`](constant.LOCK_WRLOCKED.html) is set, the top two bits of the thread
+/// must always be set to zero.
+#[repr(C)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub struct tid(pub u32);
+
+/// Timestamp in nanoseconds.
+pub type timestamp = u64;
+
+bitflags! {
+  /// Specifies whether files are unlinked or directories are
+  /// removed.
+  #[repr(C)]
+  pub struct ulflags: u8 {
+    /// If set, removes a directory. Otherwise, unlinks any
+    /// non-directory file.
+    const REMOVEDIR = 0x01;
+  }
+}
+
+/// User-provided value that can be attached to objects that is
+/// retained when extracted from the kernel.
+pub type userdata = u64;
+
+/// Relative to which position the offset of the file descriptor
+/// should be set.
+#[repr(u8)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub enum whence {
+  /// Seek relative to current position.
+  CUR = 1,
+  /// Seek relative to end-of-file.
+  END = 2,
+  /// Seek relative to start-of-file.
+  SET = 3,
+  #[doc(hidden)] _NonExhaustive = -1 as isize as u8,
+}
+
+/// Auxiliary vector entry.
+///
+/// The auxiliary vector is a list of key-value pairs that is
+/// provided to the process on startup. Unlike structures, it is
+/// extensible, as it is possible to add new records later on.
+/// The auxiliary vector is always terminated by an entry having
+/// type [`NULL`](enum.auxtype.html#variant.NULL).
+///
+/// The auxiliary vector is part of the x86-64 ABI, but is used by
+/// this environment on all architectures.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct auxv {
+  /// The type of the auxiliary vector entry.
+  pub a_type: auxtype,
+  pub union: auxv_union
+}
+/// A union inside `auxv`.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union auxv_union {
+  /// Used when `a_type` is [`ARGDATALEN`](enum.auxtype.html#variant.ARGDATALEN), [`CANARYLEN`](enum.auxtype.html#variant.CANARYLEN), [`NCPUS`](enum.auxtype.html#variant.NCPUS), [`PAGESZ`](enum.auxtype.html#variant.PAGESZ), [`PHNUM`](enum.auxtype.html#variant.PHNUM), or [`TID`](enum.auxtype.html#variant.TID).
+/// A numerical value.
+  pub a_val: usize,
+  /// Used when `a_type` is [`ARGDATA`](enum.auxtype.html#variant.ARGDATA), [`BASE`](enum.auxtype.html#variant.BASE), [`CANARY`](enum.auxtype.html#variant.CANARY), [`PHDR`](enum.auxtype.html#variant.PHDR), [`PID`](enum.auxtype.html#variant.PID), or [`SYSINFO_EHDR`](enum.auxtype.html#variant.SYSINFO_EHDR).
+/// A pointer value.
+  pub a_ptr: *mut (),
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn auxv_layout_test_32() {
+  assert_eq!(::core::mem::size_of::<auxv>(), 8);
+  assert_eq!(::core::mem::align_of::<auxv>(), 4);
+  unsafe {
+    let obj: auxv = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.a_type as *const _ as usize - base, 0);
+    assert_eq!(&obj.union.a_val as *const _ as usize - base, 4);
+    assert_eq!(&obj.union.a_ptr as *const _ as usize - base, 4);
+  }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn auxv_layout_test_64() {
+  assert_eq!(::core::mem::size_of::<auxv>(), 16);
+  assert_eq!(::core::mem::align_of::<auxv>(), 8);
+  unsafe {
+    let obj: auxv = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.a_type as *const _ as usize - base, 0);
+    assert_eq!(&obj.union.a_val as *const _ as usize - base, 8);
+    assert_eq!(&obj.union.a_ptr as *const _ as usize - base, 8);
+  }
+}
+
+/// A region of memory for scatter/gather writes.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct ciovec {
+  /// The address and length of the buffer to be written.
+  pub buf: (*const (), usize),
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn ciovec_layout_test_32() {
+  assert_eq!(::core::mem::size_of::<ciovec>(), 8);
+  assert_eq!(::core::mem::align_of::<ciovec>(), 4);
+  unsafe {
+    let obj: ciovec = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.buf.0 as *const _ as usize - base, 0);
+    assert_eq!(&obj.buf.1 as *const _ as usize - base, 4);
+  }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn ciovec_layout_test_64() {
+  assert_eq!(::core::mem::size_of::<ciovec>(), 16);
+  assert_eq!(::core::mem::align_of::<ciovec>(), 8);
+  unsafe {
+    let obj: ciovec = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.buf.0 as *const _ as usize - base, 0);
+    assert_eq!(&obj.buf.1 as *const _ as usize - base, 8);
+  }
+}
+
+/// A directory entry.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct dirent {
+  /// The offset of the next directory entry stored in this
+  /// directory.
+  pub d_next: dircookie,
+  /// The serial number of the file referred to by this
+  /// directory entry.
+  pub d_ino: inode,
+  /// The length of the name of the directory entry.
+  pub d_namlen: u32,
+  /// The type of the file referred to by this directory
+  /// entry.
+  pub d_type: filetype,
+}
+#[test]
+fn dirent_layout_test() {
+  assert_eq!(::core::mem::size_of::<dirent>(), 24);
+  assert_eq!(::core::mem::align_of::<dirent>(), 8);
+  unsafe {
+    let obj: dirent = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.d_next as *const _ as usize - base, 0);
+    assert_eq!(&obj.d_ino as *const _ as usize - base, 8);
+    assert_eq!(&obj.d_namlen as *const _ as usize - base, 16);
+    assert_eq!(&obj.d_type as *const _ as usize - base, 20);
+  }
+}
+
+/// An event that occurred.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct event {
+  /// User-provided value that got attached to
+  /// [`subscription.userdata`](struct.subscription.html#structfield.userdata).
+  pub userdata: userdata,
+  /// If non-zero, an error that occurred while processing
+  /// the subscription request.
+  pub error: errno,
+  /// The type of the event that occurred.
+  pub type_: eventtype,
+  pub union: event_union
+}
+/// A union inside `event`.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union event_union {
+  /// Used when `type_` is [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE).
+  pub fd_readwrite: event_fd_readwrite,
+  /// Used when `type_` is [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE).
+  pub proc_terminate: event_proc_terminate,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct event_fd_readwrite {
+  /// The number of bytes available
+  /// for reading or writing.
+  pub nbytes: filesize,
+  /// Obsolete.
+  pub unused: [u8; 4],
+  /// The state of the file
+  /// descriptor.
+  pub flags: eventrwflags,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct event_proc_terminate {
+  /// Obsolete.
+  pub unused: [u8; 4],
+  /// If zero, the process has
+  /// exited.
+  /// Otherwise, the signal
+  /// condition causing it to
+  /// terminated.
+  pub signal: signal,
+  /// If exited, the exit code of
+  /// the process.
+  pub exitcode: exitcode,
+}
+#[test]
+fn event_layout_test() {
+  assert_eq!(::core::mem::size_of::<event>(), 32);
+  assert_eq!(::core::mem::align_of::<event>(), 8);
+  unsafe {
+    let obj: event = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.userdata as *const _ as usize - base, 0);
+    assert_eq!(&obj.error as *const _ as usize - base, 8);
+    assert_eq!(&obj.type_ as *const _ as usize - base, 10);
+    assert_eq!(&obj.union.fd_readwrite.nbytes as *const _ as usize - base, 16);
+    assert_eq!(&obj.union.fd_readwrite.unused as *const _ as usize - base, 24);
+    assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 28);
+    assert_eq!(&obj.union.proc_terminate.unused as *const _ as usize - base, 16);
+    assert_eq!(&obj.union.proc_terminate.signal as *const _ as usize - base, 20);
+    assert_eq!(&obj.union.proc_terminate.exitcode as *const _ as usize - base, 24);
+  }
+}
+
+/// File descriptor attributes.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct fdstat {
+  /// File type.
+  pub fs_filetype: filetype,
+  /// File descriptor flags.
+  pub fs_flags: fdflags,
+  /// Rights that apply to this file descriptor.
+  pub fs_rights_base: rights,
+  /// Maximum set of rights that can be installed on new
+  /// file descriptors that are created through this file
+  /// descriptor, e.g., through [`file_open()`](fn.file_open.html).
+  pub fs_rights_inheriting: rights,
+}
+#[test]
+fn fdstat_layout_test() {
+  assert_eq!(::core::mem::size_of::<fdstat>(), 24);
+  assert_eq!(::core::mem::align_of::<fdstat>(), 8);
+  unsafe {
+    let obj: fdstat = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.fs_filetype as *const _ as usize - base, 0);
+    assert_eq!(&obj.fs_flags as *const _ as usize - base, 2);
+    assert_eq!(&obj.fs_rights_base as *const _ as usize - base, 8);
+    assert_eq!(&obj.fs_rights_inheriting as *const _ as usize - base, 16);
+  }
+}
+
+/// File attributes.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct filestat {
+  /// Device ID of device containing the file.
+  pub st_dev: device,
+  /// File serial number.
+  pub st_ino: inode,
+  /// File type.
+  pub st_filetype: filetype,
+  /// Number of hard links to the file.
+  pub st_nlink: linkcount,
+  /// For regular files, the file size in bytes. For
+  /// symbolic links, the length in bytes of the pathname
+  /// contained in the symbolic link.
+  pub st_size: filesize,
+  /// Last data access timestamp.
+  pub st_atim: timestamp,
+  /// Last data modification timestamp.
+  pub st_mtim: timestamp,
+  /// Last file status change timestamp.
+  pub st_ctim: timestamp,
+}
+#[test]
+fn filestat_layout_test() {
+  assert_eq!(::core::mem::size_of::<filestat>(), 56);
+  assert_eq!(::core::mem::align_of::<filestat>(), 8);
+  unsafe {
+    let obj: filestat = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.st_dev as *const _ as usize - base, 0);
+    assert_eq!(&obj.st_ino as *const _ as usize - base, 8);
+    assert_eq!(&obj.st_filetype as *const _ as usize - base, 16);
+    assert_eq!(&obj.st_nlink as *const _ as usize - base, 20);
+    assert_eq!(&obj.st_size as *const _ as usize - base, 24);
+    assert_eq!(&obj.st_atim as *const _ as usize - base, 32);
+    assert_eq!(&obj.st_mtim as *const _ as usize - base, 40);
+    assert_eq!(&obj.st_ctim as *const _ as usize - base, 48);
+  }
+}
+
+/// A region of memory for scatter/gather reads.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct iovec {
+  /// The address and length of the buffer to be filled.
+  pub buf: (*mut (), usize),
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn iovec_layout_test_32() {
+  assert_eq!(::core::mem::size_of::<iovec>(), 8);
+  assert_eq!(::core::mem::align_of::<iovec>(), 4);
+  unsafe {
+    let obj: iovec = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.buf.0 as *const _ as usize - base, 0);
+    assert_eq!(&obj.buf.1 as *const _ as usize - base, 4);
+  }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn iovec_layout_test_64() {
+  assert_eq!(::core::mem::size_of::<iovec>(), 16);
+  assert_eq!(::core::mem::align_of::<iovec>(), 8);
+  unsafe {
+    let obj: iovec = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.buf.0 as *const _ as usize - base, 0);
+    assert_eq!(&obj.buf.1 as *const _ as usize - base, 8);
+  }
+}
+
+/// Path lookup properties.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct lookup {
+  /// The working directory at which the resolution of the
+  /// path starts.
+  pub fd: fd,
+  /// Flags determining the method of how the path is
+  /// resolved.
+  pub flags: lookupflags,
+}
+#[test]
+fn lookup_layout_test() {
+  assert_eq!(::core::mem::size_of::<lookup>(), 8);
+  assert_eq!(::core::mem::align_of::<lookup>(), 4);
+  unsafe {
+    let obj: lookup = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.fd as *const _ as usize - base, 0);
+    assert_eq!(&obj.flags as *const _ as usize - base, 4);
+  }
+}
+
+/// Entry point for a process (`_start`).
+///
+/// **auxv**:
+/// The auxiliary vector. See [`auxv`](struct.auxv.html).
+pub type processentry = unsafe extern "C" fn(
+  auxv: *const auxv,
+) -> ();
+
+/// Arguments of [`sock_recv()`](fn.sock_recv.html).
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct recv_in {
+  /// List of scatter/gather vectors where message data
+  /// should be stored.
+  pub ri_data: (*const iovec, usize),
+  /// Buffer where numbers of incoming file descriptors
+  /// should be stored.
+  pub ri_fds: (*mut fd, usize),
+  /// Message flags.
+  pub ri_flags: riflags,
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn recv_in_layout_test_32() {
+  assert_eq!(::core::mem::size_of::<recv_in>(), 20);
+  assert_eq!(::core::mem::align_of::<recv_in>(), 4);
+  unsafe {
+    let obj: recv_in = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.ri_data.0 as *const _ as usize - base, 0);
+    assert_eq!(&obj.ri_data.1 as *const _ as usize - base, 4);
+    assert_eq!(&obj.ri_fds.0 as *const _ as usize - base, 8);
+    assert_eq!(&obj.ri_fds.1 as *const _ as usize - base, 12);
+    assert_eq!(&obj.ri_flags as *const _ as usize - base, 16);
+  }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn recv_in_layout_test_64() {
+  assert_eq!(::core::mem::size_of::<recv_in>(), 40);
+  assert_eq!(::core::mem::align_of::<recv_in>(), 8);
+  unsafe {
+    let obj: recv_in = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.ri_data.0 as *const _ as usize - base, 0);
+    assert_eq!(&obj.ri_data.1 as *const _ as usize - base, 8);
+    assert_eq!(&obj.ri_fds.0 as *const _ as usize - base, 16);
+    assert_eq!(&obj.ri_fds.1 as *const _ as usize - base, 24);
+    assert_eq!(&obj.ri_flags as *const _ as usize - base, 32);
+  }
+}
+
+/// Results of [`sock_recv()`](fn.sock_recv.html).
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct recv_out {
+  /// Number of bytes stored in [`recv_in.ri_data`](struct.recv_in.html#structfield.ri_data).
+  pub ro_datalen: usize,
+  /// Number of file descriptors stored in [`recv_in.ri_fds`](struct.recv_in.html#structfield.ri_fds).
+  pub ro_fdslen: usize,
+  /// Fields that were used by previous implementations.
+  pub ro_unused: [u8; 40],
+  /// Message flags.
+  pub ro_flags: roflags,
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn recv_out_layout_test_32() {
+  assert_eq!(::core::mem::size_of::<recv_out>(), 52);
+  assert_eq!(::core::mem::align_of::<recv_out>(), 4);
+  unsafe {
+    let obj: recv_out = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.ro_datalen as *const _ as usize - base, 0);
+    assert_eq!(&obj.ro_fdslen as *const _ as usize - base, 4);
+    assert_eq!(&obj.ro_unused as *const _ as usize - base, 8);
+    assert_eq!(&obj.ro_flags as *const _ as usize - base, 48);
+  }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn recv_out_layout_test_64() {
+  assert_eq!(::core::mem::size_of::<recv_out>(), 64);
+  assert_eq!(::core::mem::align_of::<recv_out>(), 8);
+  unsafe {
+    let obj: recv_out = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.ro_datalen as *const _ as usize - base, 0);
+    assert_eq!(&obj.ro_fdslen as *const _ as usize - base, 8);
+    assert_eq!(&obj.ro_unused as *const _ as usize - base, 16);
+    assert_eq!(&obj.ro_flags as *const _ as usize - base, 56);
+  }
+}
+
+/// Arguments of [`sock_send()`](fn.sock_send.html).
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct send_in {
+  /// List of scatter/gather vectors where message data
+  /// should be retrieved.
+  pub si_data: (*const ciovec, usize),
+  /// File descriptors that need to be attached to the
+  /// message.
+  pub si_fds: (*const fd, usize),
+  /// Message flags.
+  pub si_flags: siflags,
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn send_in_layout_test_32() {
+  assert_eq!(::core::mem::size_of::<send_in>(), 20);
+  assert_eq!(::core::mem::align_of::<send_in>(), 4);
+  unsafe {
+    let obj: send_in = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.si_data.0 as *const _ as usize - base, 0);
+    assert_eq!(&obj.si_data.1 as *const _ as usize - base, 4);
+    assert_eq!(&obj.si_fds.0 as *const _ as usize - base, 8);
+    assert_eq!(&obj.si_fds.1 as *const _ as usize - base, 12);
+    assert_eq!(&obj.si_flags as *const _ as usize - base, 16);
+  }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn send_in_layout_test_64() {
+  assert_eq!(::core::mem::size_of::<send_in>(), 40);
+  assert_eq!(::core::mem::align_of::<send_in>(), 8);
+  unsafe {
+    let obj: send_in = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.si_data.0 as *const _ as usize - base, 0);
+    assert_eq!(&obj.si_data.1 as *const _ as usize - base, 8);
+    assert_eq!(&obj.si_fds.0 as *const _ as usize - base, 16);
+    assert_eq!(&obj.si_fds.1 as *const _ as usize - base, 24);
+    assert_eq!(&obj.si_flags as *const _ as usize - base, 32);
+  }
+}
+
+/// Results of [`sock_send()`](fn.sock_send.html).
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct send_out {
+  /// Number of bytes transmitted.
+  pub so_datalen: usize,
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn send_out_layout_test_32() {
+  assert_eq!(::core::mem::size_of::<send_out>(), 4);
+  assert_eq!(::core::mem::align_of::<send_out>(), 4);
+  unsafe {
+    let obj: send_out = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.so_datalen as *const _ as usize - base, 0);
+  }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn send_out_layout_test_64() {
+  assert_eq!(::core::mem::size_of::<send_out>(), 8);
+  assert_eq!(::core::mem::align_of::<send_out>(), 8);
+  unsafe {
+    let obj: send_out = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.so_datalen as *const _ as usize - base, 0);
+  }
+}
+
+/// Subscription to an event.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct subscription {
+  /// User-provided value that is attached to the
+  /// subscription in the kernel and returned through
+  /// [`event.userdata`](struct.event.html#structfield.userdata).
+  pub userdata: userdata,
+  /// Used by previous implementations. Ignored.
+  pub unused: u16,
+  /// The type of the event to which to subscribe.
+  ///
+  /// Currently, [`CONDVAR`](enum.eventtype.html#variant.CONDVAR),
+  /// [`LOCK_RDLOCK`](enum.eventtype.html#variant.LOCK_RDLOCK), and [`LOCK_WRLOCK`](enum.eventtype.html#variant.LOCK_WRLOCK)
+  /// must be provided as the first subscription and may
+  /// only be followed by up to one other subscription,
+  /// having type [`CLOCK`](enum.eventtype.html#variant.CLOCK).
+  pub type_: eventtype,
+  pub union: subscription_union
+}
+/// A union inside `subscription`.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union subscription_union {
+  /// Used when `type_` is [`CLOCK`](enum.eventtype.html#variant.CLOCK).
+  pub clock: subscription_clock,
+  /// Used when `type_` is [`CONDVAR`](enum.eventtype.html#variant.CONDVAR).
+  pub condvar: subscription_condvar,
+  /// Used when `type_` is [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE).
+  pub fd_readwrite: subscription_fd_readwrite,
+  /// Used when `type_` is [`LOCK_RDLOCK`](enum.eventtype.html#variant.LOCK_RDLOCK) or [`LOCK_WRLOCK`](enum.eventtype.html#variant.LOCK_WRLOCK).
+  pub lock: subscription_lock,
+  /// Used when `type_` is [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE).
+  pub proc_terminate: subscription_proc_terminate,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct subscription_clock {
+  /// The user-defined unique
+  /// identifier of the clock.
+  pub identifier: userdata,
+  /// The clock against which the
+  /// timestamp should be compared.
+  pub clock_id: clockid,
+  /// The absolute or relative
+  /// timestamp.
+  pub timeout: timestamp,
+  /// The amount of time that the
+  /// kernel may wait additionally
+  /// to coalesce with other events.
+  pub precision: timestamp,
+  /// Flags specifying whether the
+  /// timeout is absolute or
+  /// relative.
+  pub flags: subclockflags,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct subscription_condvar {
+  /// The condition variable on
+  /// which to wait to be woken up.
+  pub condvar: *mut condvar,
+  /// The lock that will be
+  /// released while waiting.
+  ///
+  /// The lock will be reacquired
+  /// for writing when the condition
+  /// variable triggers.
+  pub lock: *mut lock,
+  /// Whether the condition variable
+  /// is stored in private or shared
+  /// memory.
+  pub condvar_scope: scope,
+  /// Whether the lock is stored in
+  /// private or shared memory.
+  pub lock_scope: scope,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct subscription_fd_readwrite {
+  /// The file descriptor on which
+  /// to wait for it to become ready
+  /// for reading or writing.
+  pub fd: fd,
+  /// Under which conditions to
+  /// trigger.
+  pub flags: subrwflags,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct subscription_lock {
+  /// The lock that will be acquired
+  /// for reading or writing.
+  pub lock: *mut lock,
+  /// Whether the lock is stored in
+  /// private or shared memory.
+  pub lock_scope: scope,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct subscription_proc_terminate {
+  /// The process descriptor on
+  /// which to wait for process
+  /// termination.
+  pub fd: fd,
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn subscription_layout_test_32() {
+  assert_eq!(::core::mem::size_of::<subscription>(), 56);
+  assert_eq!(::core::mem::align_of::<subscription>(), 8);
+  unsafe {
+    let obj: subscription = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.userdata as *const _ as usize - base, 0);
+    assert_eq!(&obj.unused as *const _ as usize - base, 8);
+    assert_eq!(&obj.type_ as *const _ as usize - base, 10);
+    assert_eq!(&obj.union.clock.identifier as *const _ as usize - base, 16);
+    assert_eq!(&obj.union.clock.clock_id as *const _ as usize - base, 24);
+    assert_eq!(&obj.union.clock.timeout as *const _ as usize - base, 32);
+    assert_eq!(&obj.union.clock.precision as *const _ as usize - base, 40);
+    assert_eq!(&obj.union.clock.flags as *const _ as usize - base, 48);
+    assert_eq!(&obj.union.condvar.condvar as *const _ as usize - base, 16);
+    assert_eq!(&obj.union.condvar.lock as *const _ as usize - base, 20);
+    assert_eq!(&obj.union.condvar.condvar_scope as *const _ as usize - base, 24);
+    assert_eq!(&obj.union.condvar.lock_scope as *const _ as usize - base, 25);
+    assert_eq!(&obj.union.fd_readwrite.fd as *const _ as usize - base, 16);
+    assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 20);
+    assert_eq!(&obj.union.lock.lock as *const _ as usize - base, 16);
+    assert_eq!(&obj.union.lock.lock_scope as *const _ as usize - base, 20);
+    assert_eq!(&obj.union.proc_terminate.fd as *const _ as usize - base, 16);
+  }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn subscription_layout_test_64() {
+  assert_eq!(::core::mem::size_of::<subscription>(), 56);
+  assert_eq!(::core::mem::align_of::<subscription>(), 8);
+  unsafe {
+    let obj: subscription = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.userdata as *const _ as usize - base, 0);
+    assert_eq!(&obj.unused as *const _ as usize - base, 8);
+    assert_eq!(&obj.type_ as *const _ as usize - base, 10);
+    assert_eq!(&obj.union.clock.identifier as *const _ as usize - base, 16);
+    assert_eq!(&obj.union.clock.clock_id as *const _ as usize - base, 24);
+    assert_eq!(&obj.union.clock.timeout as *const _ as usize - base, 32);
+    assert_eq!(&obj.union.clock.precision as *const _ as usize - base, 40);
+    assert_eq!(&obj.union.clock.flags as *const _ as usize - base, 48);
+    assert_eq!(&obj.union.condvar.condvar as *const _ as usize - base, 16);
+    assert_eq!(&obj.union.condvar.lock as *const _ as usize - base, 24);
+    assert_eq!(&obj.union.condvar.condvar_scope as *const _ as usize - base, 32);
+    assert_eq!(&obj.union.condvar.lock_scope as *const _ as usize - base, 33);
+    assert_eq!(&obj.union.fd_readwrite.fd as *const _ as usize - base, 16);
+    assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 20);
+    assert_eq!(&obj.union.lock.lock as *const _ as usize - base, 16);
+    assert_eq!(&obj.union.lock.lock_scope as *const _ as usize - base, 24);
+    assert_eq!(&obj.union.proc_terminate.fd as *const _ as usize - base, 16);
+  }
+}
+
+/// The Thread Control Block (TCB).
+///
+/// After a thread begins execution (at program startup or when
+/// created through [`thread_create()`](fn.thread_create.html)), the CPU's registers
+/// controlling Thread-Local Storage (TLS) will already be
+/// initialized. They will point to an area only containing the
+/// TCB.
+///
+/// If the thread needs space for storing thread-specific
+/// variables, the thread may allocate a larger area and adjust
+/// the CPU's registers to point to that area instead. However, it
+/// does need to make sure that the TCB is copied over to the new
+/// TLS area.
+///
+/// The purpose of the TCB is that it allows light-weight
+/// emulators to store information related to individual threads.
+/// For example, it may be used to store a copy of the CPU
+/// registers prior emulation, so that TLS for the host system
+/// can be restored if needed.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct tcb {
+  /// Pointer that may be freely assigned by the system. Its
+  /// value cannot be interpreted by the application.
+  pub parent: *mut (),
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn tcb_layout_test_32() {
+  assert_eq!(::core::mem::size_of::<tcb>(), 4);
+  assert_eq!(::core::mem::align_of::<tcb>(), 4);
+  unsafe {
+    let obj: tcb = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.parent as *const _ as usize - base, 0);
+  }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn tcb_layout_test_64() {
+  assert_eq!(::core::mem::size_of::<tcb>(), 8);
+  assert_eq!(::core::mem::align_of::<tcb>(), 8);
+  unsafe {
+    let obj: tcb = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.parent as *const _ as usize - base, 0);
+  }
+}
+
+/// Entry point for additionally created threads.
+///
+/// **tid**:
+/// Thread ID of the current thread.
+///
+/// **aux**:
+/// Copy of the value stored in
+/// [`threadattr.argument`](struct.threadattr.html#structfield.argument).
+pub type threadentry = unsafe extern "C" fn(
+  tid: tid,
+  aux: *mut (),
+) -> ();
+
+/// Attributes for thread creation.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct threadattr {
+  /// Initial program counter value.
+  pub entry_point: threadentry,
+  /// Region allocated to serve as stack space.
+  pub stack: (*mut (), usize),
+  /// Argument to be forwarded to the entry point function.
+  pub argument: *mut (),
+}
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn threadattr_layout_test_32() {
+  assert_eq!(::core::mem::size_of::<threadattr>(), 16);
+  assert_eq!(::core::mem::align_of::<threadattr>(), 4);
+  unsafe {
+    let obj: threadattr = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.entry_point as *const _ as usize - base, 0);
+    assert_eq!(&obj.stack.0 as *const _ as usize - base, 4);
+    assert_eq!(&obj.stack.1 as *const _ as usize - base, 8);
+    assert_eq!(&obj.argument as *const _ as usize - base, 12);
+  }
+}
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn threadattr_layout_test_64() {
+  assert_eq!(::core::mem::size_of::<threadattr>(), 32);
+  assert_eq!(::core::mem::align_of::<threadattr>(), 8);
+  unsafe {
+    let obj: threadattr = ::core::mem::uninitialized();
+    let base = &obj as *const _ as usize;
+    assert_eq!(&obj.entry_point as *const _ as usize - base, 0);
+    assert_eq!(&obj.stack.0 as *const _ as usize - base, 8);
+    assert_eq!(&obj.stack.1 as *const _ as usize - base, 16);
+    assert_eq!(&obj.argument as *const _ as usize - base, 24);
+  }
+}
+
+/// The table with pointers to all syscall implementations.
+#[allow(improper_ctypes)]
+extern "C" {
+  fn cloudabi_sys_clock_res_get(_: clockid, _: *mut timestamp) -> errno;
+  fn cloudabi_sys_clock_time_get(_: clockid, _: timestamp, _: *mut timestamp) -> errno;
+  fn cloudabi_sys_condvar_signal(_: *mut condvar, _: scope, _: nthreads) -> errno;
+  fn cloudabi_sys_fd_close(_: fd) -> errno;
+  fn cloudabi_sys_fd_create1(_: filetype, _: *mut fd) -> errno;
+  fn cloudabi_sys_fd_create2(_: filetype, _: *mut fd, _: *mut fd) -> errno;
+  fn cloudabi_sys_fd_datasync(_: fd) -> errno;
+  fn cloudabi_sys_fd_dup(_: fd, _: *mut fd) -> errno;
+  fn cloudabi_sys_fd_pread(_: fd, _: *const iovec, _: usize, _: filesize, _: *mut usize) -> errno;
+  fn cloudabi_sys_fd_pwrite(_: fd, _: *const ciovec, _: usize, _: filesize, _: *mut usize) -> errno;
+  fn cloudabi_sys_fd_read(_: fd, _: *const iovec, _: usize, _: *mut usize) -> errno;
+  fn cloudabi_sys_fd_replace(_: fd, _: fd) -> errno;
+  fn cloudabi_sys_fd_seek(_: fd, _: filedelta, _: whence, _: *mut filesize) -> errno;
+  fn cloudabi_sys_fd_stat_get(_: fd, _: *mut fdstat) -> errno;
+  fn cloudabi_sys_fd_stat_put(_: fd, _: *const fdstat, _: fdsflags) -> errno;
+  fn cloudabi_sys_fd_sync(_: fd) -> errno;
+  fn cloudabi_sys_fd_write(_: fd, _: *const ciovec, _: usize, _: *mut usize) -> errno;
+  fn cloudabi_sys_file_advise(_: fd, _: filesize, _: filesize, _: advice) -> errno;
+  fn cloudabi_sys_file_allocate(_: fd, _: filesize, _: filesize) -> errno;
+  fn cloudabi_sys_file_create(_: fd, _: *const u8, _: usize, _: filetype) -> errno;
+  fn cloudabi_sys_file_link(_: lookup, _: *const u8, _: usize, _: fd, _: *const u8, _: usize) -> errno;
+  fn cloudabi_sys_file_open(_: lookup, _: *const u8, _: usize, _: oflags, _: *const fdstat, _: *mut fd) -> errno;
+  fn cloudabi_sys_file_readdir(_: fd, _: *mut (), _: usize, _: dircookie, _: *mut usize) -> errno;
+  fn cloudabi_sys_file_readlink(_: fd, _: *const u8, _: usize, _: *mut u8, _: usize, _: *mut usize) -> errno;
+  fn cloudabi_sys_file_rename(_: fd, _: *const u8, _: usize, _: fd, _: *const u8, _: usize) -> errno;
+  fn cloudabi_sys_file_stat_fget(_: fd, _: *mut filestat) -> errno;
+  fn cloudabi_sys_file_stat_fput(_: fd, _: *const filestat, _: fsflags) -> errno;
+  fn cloudabi_sys_file_stat_get(_: lookup, _: *const u8, _: usize, _: *mut filestat) -> errno;
+  fn cloudabi_sys_file_stat_put(_: lookup, _: *const u8, _: usize, _: *const filestat, _: fsflags) -> errno;
+  fn cloudabi_sys_file_symlink(_: *const u8, _: usize, _: fd, _: *const u8, _: usize) -> errno;
+  fn cloudabi_sys_file_unlink(_: fd, _: *const u8, _: usize, _: ulflags) -> errno;
+  fn cloudabi_sys_lock_unlock(_: *mut lock, _: scope) -> errno;
+  fn cloudabi_sys_mem_advise(_: *mut (), _: usize, _: advice) -> errno;
+  fn cloudabi_sys_mem_map(_: *mut (), _: usize, _: mprot, _: mflags, _: fd, _: filesize, _: *mut *mut ()) -> errno;
+  fn cloudabi_sys_mem_protect(_: *mut (), _: usize, _: mprot) -> errno;
+  fn cloudabi_sys_mem_sync(_: *mut (), _: usize, _: msflags) -> errno;
+  fn cloudabi_sys_mem_unmap(_: *mut (), _: usize) -> errno;
+  fn cloudabi_sys_poll(_: *const subscription, _: *mut event, _: usize, _: *mut usize) -> errno;
+  fn cloudabi_sys_proc_exec(_: fd, _: *const (), _: usize, _: *const fd, _: usize) -> errno;
+  fn cloudabi_sys_proc_exit(_: exitcode) -> !;
+  fn cloudabi_sys_proc_fork(_: *mut fd, _: *mut tid) -> errno;
+  fn cloudabi_sys_proc_raise(_: signal) -> errno;
+  fn cloudabi_sys_random_get(_: *mut (), _: usize) -> errno;
+  fn cloudabi_sys_sock_recv(_: fd, _: *const recv_in, _: *mut recv_out) -> errno;
+  fn cloudabi_sys_sock_send(_: fd, _: *const send_in, _: *mut send_out) -> errno;
+  fn cloudabi_sys_sock_shutdown(_: fd, _: sdflags) -> errno;
+  fn cloudabi_sys_thread_create(_: *mut threadattr, _: *mut tid) -> errno;
+  fn cloudabi_sys_thread_exit(_: *mut lock, _: scope) -> !;
+  fn cloudabi_sys_thread_yield() -> errno;
+}
+
+/// Obtains the resolution of a clock.
+///
+/// ## Parameters
+///
+/// **clock_id**:
+/// The clock for which the resolution needs to be
+/// returned.
+///
+/// **resolution**:
+/// The resolution of the clock.
+#[inline]
+pub unsafe fn clock_res_get(clock_id_: clockid, resolution_: &mut timestamp) -> errno {
+  cloudabi_sys_clock_res_get(clock_id_, resolution_)
+}
+
+/// Obtains the time value of a clock.
+///
+/// ## Parameters
+///
+/// **clock_id**:
+/// The clock for which the time needs to be
+/// returned.
+///
+/// **precision**:
+/// The maximum lag (exclusive) that the returned
+/// time value may have, compared to its actual
+/// value.
+///
+/// **time**:
+/// The time value of the clock.
+#[inline]
+pub unsafe fn clock_time_get(clock_id_: clockid, precision_: timestamp, time_: &mut timestamp) -> errno {
+  cloudabi_sys_clock_time_get(clock_id_, precision_, time_)
+}
+
+/// Wakes up threads waiting on a userspace condition variable.
+///
+/// If an invocation of this system call causes all waiting
+/// threads to be woken up, the value of the condition variable
+/// is set to [`CONDVAR_HAS_NO_WAITERS`](constant.CONDVAR_HAS_NO_WAITERS.html). As long as the condition
+/// variable is set to this value, it is not needed to invoke this
+/// system call.
+///
+/// ## Parameters
+///
+/// **condvar**:
+/// The userspace condition variable that has
+/// waiting threads.
+///
+/// **scope**:
+/// Whether the condition variable is stored in
+/// private or shared memory.
+///
+/// **nwaiters**:
+/// The number of threads that need to be woken
+/// up. If it exceeds the number of waiting
+/// threads, all threads are woken up.
+#[inline]
+pub unsafe fn condvar_signal(condvar_: *mut condvar, scope_: scope, nwaiters_: nthreads) -> errno {
+  cloudabi_sys_condvar_signal(condvar_, scope_, nwaiters_)
+}
+
+/// Closes a file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor that needs to be closed.
+#[inline]
+pub unsafe fn fd_close(fd_: fd) -> errno {
+  cloudabi_sys_fd_close(fd_)
+}
+
+/// Creates a file descriptor.
+///
+/// ## Parameters
+///
+/// **type**:
+/// Possible values:
+///
+///   - [`SHARED_MEMORY`](enum.filetype.html#variant.SHARED_MEMORY):
+///     Creates an anonymous shared memory
+///     object.
+///
+/// **fd**:
+/// The file descriptor that has been created.
+#[inline]
+pub unsafe fn fd_create1(type_: filetype, fd_: &mut fd) -> errno {
+  cloudabi_sys_fd_create1(type_, fd_)
+}
+
+/// Creates a pair of file descriptors.
+///
+/// ## Parameters
+///
+/// **type**:
+/// Possible values:
+///
+///   - [`SOCKET_DGRAM`](enum.filetype.html#variant.SOCKET_DGRAM):
+///     Creates a UNIX datagram socket pair.
+///   - [`SOCKET_STREAM`](enum.filetype.html#variant.SOCKET_STREAM):
+///     Creates a UNIX byte-stream socket
+///     pair.
+///
+/// **fd1**:
+/// The first file descriptor of the pair.
+///
+/// **fd2**:
+/// The second file descriptor of the pair.
+#[inline]
+pub unsafe fn fd_create2(type_: filetype, fd1_: &mut fd, fd2_: &mut fd) -> errno {
+  cloudabi_sys_fd_create2(type_, fd1_, fd2_)
+}
+
+/// Synchronizes the data of a file to disk.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor of the file whose data
+/// needs to be synchronized to disk.
+#[inline]
+pub unsafe fn fd_datasync(fd_: fd) -> errno {
+  cloudabi_sys_fd_datasync(fd_)
+}
+
+/// Duplicates a file descriptor.
+///
+/// ## Parameters
+///
+/// **from**:
+/// The file descriptor that needs to be
+/// duplicated.
+///
+/// **fd**:
+/// The new file descriptor.
+#[inline]
+pub unsafe fn fd_dup(from_: fd, fd_: &mut fd) -> errno {
+  cloudabi_sys_fd_dup(from_, fd_)
+}
+
+/// Reads from a file descriptor, without using and updating the
+/// file descriptor's offset.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor from which data should be
+/// read.
+///
+/// **iovs**:
+/// List of scatter/gather vectors where data
+/// should be stored.
+///
+/// **offset**:
+/// The offset within the file at which reading
+/// should start.
+///
+/// **nread**:
+/// The number of bytes read.
+#[inline]
+pub unsafe fn fd_pread(fd_: fd, iovs_: &[iovec], offset_: filesize, nread_: &mut usize) -> errno {
+  cloudabi_sys_fd_pread(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nread_)
+}
+
+/// Writes to a file descriptor, without using and updating the
+/// file descriptor's offset.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor to which data should be
+/// written.
+///
+/// **iovs**:
+/// List of scatter/gather vectors where data
+/// should be retrieved.
+///
+/// **offset**:
+/// The offset within the file at which writing
+/// should start.
+///
+/// **nwritten**:
+/// The number of bytes written.
+#[inline]
+pub unsafe fn fd_pwrite(fd_: fd, iovs_: &[ciovec], offset_: filesize, nwritten_: &mut usize) -> errno {
+  cloudabi_sys_fd_pwrite(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nwritten_)
+}
+
+/// Reads from a file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor from which data should be
+/// read.
+///
+/// **iovs**:
+/// List of scatter/gather vectors where data
+/// should be stored.
+///
+/// **nread**:
+/// The number of bytes read.
+#[inline]
+pub unsafe fn fd_read(fd_: fd, iovs_: &[iovec], nread_: &mut usize) -> errno {
+  cloudabi_sys_fd_read(fd_, iovs_.as_ptr(), iovs_.len(), nread_)
+}
+
+/// Atomically replaces a file descriptor by a copy of another
+/// file descriptor.
+///
+/// Due to the strong focus on thread safety, this environment
+/// does not provide a mechanism to duplicate a file descriptor to
+/// an arbitrary number, like dup2(). This would be prone to race
+/// conditions, as an actual file descriptor with the same number
+/// could be allocated by a different thread at the same time.
+///
+/// This system call provides a way to atomically replace file
+/// descriptors, which would disappear if dup2() were to be
+/// removed entirely.
+///
+/// ## Parameters
+///
+/// **from**:
+/// The file descriptor that needs to be copied.
+///
+/// **to**:
+/// The file descriptor that needs to be
+/// overwritten.
+#[inline]
+pub unsafe fn fd_replace(from_: fd, to_: fd) -> errno {
+  cloudabi_sys_fd_replace(from_, to_)
+}
+
+/// Moves the offset of the file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor whose offset has to be
+/// moved.
+///
+/// **offset**:
+/// The number of bytes to move.
+///
+/// **whence**:
+/// Relative to which position the move should
+/// take place.
+///
+/// **newoffset**:
+/// The new offset of the file descriptor,
+/// relative to the start of the file.
+#[inline]
+pub unsafe fn fd_seek(fd_: fd, offset_: filedelta, whence_: whence, newoffset_: &mut filesize) -> errno {
+  cloudabi_sys_fd_seek(fd_, offset_, whence_, newoffset_)
+}
+
+/// Gets attributes of a file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor whose attributes have to
+/// be obtained.
+///
+/// **buf**:
+/// The buffer where the file descriptor's
+/// attributes are stored.
+#[inline]
+pub unsafe fn fd_stat_get(fd_: fd, buf_: *mut fdstat) -> errno {
+  cloudabi_sys_fd_stat_get(fd_, buf_)
+}
+
+/// Adjusts attributes of a file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor whose attributes have to
+/// be adjusted.
+///
+/// **buf**:
+/// The desired values of the file descriptor
+/// attributes that are adjusted.
+///
+/// **flags**:
+/// A bitmask indicating which attributes have to
+/// be adjusted.
+#[inline]
+pub unsafe fn fd_stat_put(fd_: fd, buf_: *const fdstat, flags_: fdsflags) -> errno {
+  cloudabi_sys_fd_stat_put(fd_, buf_, flags_)
+}
+
+/// Synchronizes the data and metadata of a file to disk.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor of the file whose data
+/// and metadata needs to be synchronized to disk.
+#[inline]
+pub unsafe fn fd_sync(fd_: fd) -> errno {
+  cloudabi_sys_fd_sync(fd_)
+}
+
+/// Writes to a file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor to which data should be
+/// written.
+///
+/// **iovs**:
+/// List of scatter/gather vectors where data
+/// should be retrieved.
+///
+/// **nwritten**:
+/// The number of bytes written.
+#[inline]
+pub unsafe fn fd_write(fd_: fd, iovs_: &[ciovec], nwritten_: &mut usize) -> errno {
+  cloudabi_sys_fd_write(fd_, iovs_.as_ptr(), iovs_.len(), nwritten_)
+}
+
+/// Provides file advisory information on a file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor for which to provide file
+/// advisory information.
+///
+/// **offset**:
+/// The offset within the file to which the
+/// advisory applies.
+///
+/// **len**:
+/// The length of the region to which the advisory
+/// applies.
+///
+/// **advice**:
+/// The advice.
+#[inline]
+pub unsafe fn file_advise(fd_: fd, offset_: filesize, len_: filesize, advice_: advice) -> errno {
+  cloudabi_sys_file_advise(fd_, offset_, len_, advice_)
+}
+
+/// Forces the allocation of space in a file.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file in which the space should be
+/// allocated.
+///
+/// **offset**:
+/// The offset at which the allocation should
+/// start.
+///
+/// **len**:
+/// The length of the area that is allocated.
+#[inline]
+pub unsafe fn file_allocate(fd_: fd, offset_: filesize, len_: filesize) -> errno {
+  cloudabi_sys_file_allocate(fd_, offset_, len_)
+}
+
+/// Creates a file of a specified type.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The working directory at which the resolution
+/// of the file to be created starts.
+///
+/// **path**:
+/// The path at which the file should be created.
+///
+/// **type**:
+/// Possible values:
+///
+///   - [`DIRECTORY`](enum.filetype.html#variant.DIRECTORY):
+///     Creates a directory.
+#[inline]
+pub unsafe fn file_create(fd_: fd, path_: &[u8], type_: filetype) -> errno {
+  cloudabi_sys_file_create(fd_, path_.as_ptr(), path_.len(), type_)
+}
+
+/// Creates a hard link.
+///
+/// ## Parameters
+///
+/// **fd1**:
+/// The working directory at which the resolution
+/// of the source path starts.
+///
+/// **path1**:
+/// The source path of the file that should be
+/// hard linked.
+///
+/// **fd2**:
+/// The working directory at which the resolution
+/// of the destination path starts.
+///
+/// **path2**:
+/// The destination path at which the hard link
+/// should be created.
+#[inline]
+pub unsafe fn file_link(fd1_: lookup, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno {
+  cloudabi_sys_file_link(fd1_, path1_.as_ptr(), path1_.len(), fd2_, path2_.as_ptr(), path2_.len())
+}
+
+/// Opens a file.
+///
+/// ## Parameters
+///
+/// **dirfd**:
+/// The working directory at which the resolution
+/// of the file to be opened starts.
+///
+/// **path**:
+/// The path of the file that should be opened.
+///
+/// **oflags**:
+/// The method at which the file should be opened.
+///
+/// **fds**:
+/// [`fdstat.fs_rights_base`](struct.fdstat.html#structfield.fs_rights_base) and
+/// [`fdstat.fs_rights_inheriting`](struct.fdstat.html#structfield.fs_rights_inheriting) specify the
+/// initial rights of the newly created file
+/// descriptor. The operating system is allowed to
+/// return a file descriptor with fewer rights
+/// than specified, if and only if those rights do
+/// not apply to the type of file being opened.
+///
+/// [`fdstat.fs_flags`](struct.fdstat.html#structfield.fs_flags) specifies the initial flags
+/// of the file descriptor.
+///
+/// [`fdstat.fs_filetype`](struct.fdstat.html#structfield.fs_filetype) is ignored.
+///
+/// **fd**:
+/// The file descriptor of the file that has been
+/// opened.
+#[inline]
+pub unsafe fn file_open(dirfd_: lookup, path_: &[u8], oflags_: oflags, fds_: *const fdstat, fd_: &mut fd) -> errno {
+  cloudabi_sys_file_open(dirfd_, path_.as_ptr(), path_.len(), oflags_, fds_, fd_)
+}
+
+/// Reads directory entries from a directory.
+///
+/// When successful, the contents of the output buffer consist of
+/// a sequence of directory entries. Each directory entry consists
+/// of a [`dirent`](struct.dirent.html) object, followed by [`dirent.d_namlen`](struct.dirent.html#structfield.d_namlen) bytes
+/// holding the name of the directory entry.
+///
+/// This system call fills the output buffer as much as possible,
+/// potentially truncating the last directory entry. This allows
+/// the caller to grow its read buffer size in case it's too small
+/// to fit a single large directory entry, or skip the oversized
+/// directory entry.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The directory from which to read the directory
+/// entries.
+///
+/// **buf**:
+/// The buffer where directory entries are stored.
+///
+/// **cookie**:
+/// The location within the directory to start
+/// reading.
+///
+/// **bufused**:
+/// The number of bytes stored in the read buffer.
+/// If less than the size of the read buffer, the
+/// end of the directory has been reached.
+#[inline]
+pub unsafe fn file_readdir(fd_: fd, buf_: &mut [u8], cookie_: dircookie, bufused_: &mut usize) -> errno {
+  cloudabi_sys_file_readdir(fd_, buf_.as_mut_ptr() as *mut (), buf_.len(), cookie_, bufused_)
+}
+
+/// Reads the contents of a symbolic link.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The working directory at which the resolution
+/// of the path of the symbolic starts.
+///
+/// **path**:
+/// The path of the symbolic link whose contents
+/// should be read.
+///
+/// **buf**:
+/// The buffer where the contents of the symbolic
+/// link should be stored.
+///
+/// **bufused**:
+/// The number of bytes placed in the buffer.
+#[inline]
+pub unsafe fn file_readlink(fd_: fd, path_: &[u8], buf_: &mut [u8], bufused_: &mut usize) -> errno {
+  cloudabi_sys_file_readlink(fd_, path_.as_ptr(), path_.len(), buf_.as_mut_ptr(), buf_.len(), bufused_)
+}
+
+/// Renames a file.
+///
+/// ## Parameters
+///
+/// **fd1**:
+/// The working directory at which the resolution
+/// of the source path starts.
+///
+/// **path1**:
+/// The source path of the file that should be
+/// renamed.
+///
+/// **fd2**:
+/// The working directory at which the resolution
+/// of the destination path starts.
+///
+/// **path2**:
+/// The destination path to which the file should
+/// be renamed.
+#[inline]
+pub unsafe fn file_rename(fd1_: fd, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno {
+  cloudabi_sys_file_rename(fd1_, path1_.as_ptr(), path1_.len(), fd2_, path2_.as_ptr(), path2_.len())
+}
+
+/// Gets attributes of a file by file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor whose attributes have to
+/// be obtained.
+///
+/// **buf**:
+/// The buffer where the file's attributes are
+/// stored.
+#[inline]
+pub unsafe fn file_stat_fget(fd_: fd, buf_: *mut filestat) -> errno {
+  cloudabi_sys_file_stat_fget(fd_, buf_)
+}
+
+/// Adjusts attributes of a file by file descriptor.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The file descriptor whose attributes have to
+/// be adjusted.
+///
+/// **buf**:
+/// The desired values of the file attributes that
+/// are adjusted.
+///
+/// **flags**:
+/// A bitmask indicating which attributes have to
+/// be adjusted.
+#[inline]
+pub unsafe fn file_stat_fput(fd_: fd, buf_: *const filestat, flags_: fsflags) -> errno {
+  cloudabi_sys_file_stat_fput(fd_, buf_, flags_)
+}
+
+/// Gets attributes of a file by path.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The working directory at which the resolution
+/// of the path whose attributes have to be
+/// obtained starts.
+///
+/// **path**:
+/// The path of the file whose attributes have to
+/// be obtained.
+///
+/// **buf**:
+/// The buffer where the file's attributes are
+/// stored.
+#[inline]
+pub unsafe fn file_stat_get(fd_: lookup, path_: &[u8], buf_: *mut filestat) -> errno {
+  cloudabi_sys_file_stat_get(fd_, path_.as_ptr(), path_.len(), buf_)
+}
+
+/// Adjusts attributes of a file by path.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The working directory at which the resolution
+/// of the path whose attributes have to be
+/// adjusted starts.
+///
+/// **path**:
+/// The path of the file whose attributes have to
+/// be adjusted.
+///
+/// **buf**:
+/// The desired values of the file attributes that
+/// are adjusted.
+///
+/// **flags**:
+/// A bitmask indicating which attributes have to
+/// be adjusted.
+#[inline]
+pub unsafe fn file_stat_put(fd_: lookup, path_: &[u8], buf_: *const filestat, flags_: fsflags) -> errno {
+  cloudabi_sys_file_stat_put(fd_, path_.as_ptr(), path_.len(), buf_, flags_)
+}
+
+/// Creates a symbolic link.
+///
+/// ## Parameters
+///
+/// **path1**:
+/// The contents of the symbolic link.
+///
+/// **fd**:
+/// The working directory at which the resolution
+/// of the destination path starts.
+///
+/// **path2**:
+/// The destination path at which the symbolic
+/// link should be created.
+#[inline]
+pub unsafe fn file_symlink(path1_: &[u8], fd_: fd, path2_: &[u8]) -> errno {
+  cloudabi_sys_file_symlink(path1_.as_ptr(), path1_.len(), fd_, path2_.as_ptr(), path2_.len())
+}
+
+/// Unlinks a file, or removes a directory.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// The working directory at which the resolution
+/// of the path starts.
+///
+/// **path**:
+/// The path that needs to be unlinked or removed.
+///
+/// **flags**:
+/// Possible values:
+///
+///   - [`REMOVEDIR`](struct.ulflags.html#associatedconstant.REMOVEDIR):
+///     If set, attempt to remove a directory.
+///     Otherwise, unlink a file.
+#[inline]
+pub unsafe fn file_unlink(fd_: fd, path_: &[u8], flags_: ulflags) -> errno {
+  cloudabi_sys_file_unlink(fd_, path_.as_ptr(), path_.len(), flags_)
+}
+
+/// Unlocks a write-locked userspace lock.
+///
+/// If a userspace lock is unlocked while having its
+/// [`LOCK_KERNEL_MANAGED`](constant.LOCK_KERNEL_MANAGED.html) flag set, the lock cannot be unlocked in
+/// userspace directly. This system call needs to be performed
+/// instead, so that any waiting threads can be woken up.
+///
+/// To prevent spurious invocations of this system call, the lock
+/// must be locked for writing. This prevents other threads from
+/// acquiring additional read locks while the system call is in
+/// progress. If the lock is acquired for reading, it must first
+/// be upgraded to a write lock.
+///
+/// ## Parameters
+///
+/// **lock**:
+/// The userspace lock that is locked for writing
+/// by the calling thread.
+///
+/// **scope**:
+/// Whether the lock is stored in private or
+/// shared memory.
+#[inline]
+pub unsafe fn lock_unlock(lock_: *mut lock, scope_: scope) -> errno {
+  cloudabi_sys_lock_unlock(lock_, scope_)
+}
+
+/// Provides memory advisory information on a region of memory.
+///
+/// ## Parameters
+///
+/// **mapping**:
+/// The pages for which to provide memory advisory
+/// information.
+///
+/// **advice**:
+/// The advice.
+#[inline]
+pub unsafe fn mem_advise(mapping_: &mut [u8], advice_: advice) -> errno {
+  cloudabi_sys_mem_advise(mapping_.as_mut_ptr() as *mut (), mapping_.len(), advice_)
+}
+
+/// Creates a memory mapping, making the contents of a file
+/// accessible through memory.
+///
+/// ## Parameters
+///
+/// **addr**:
+/// If [`FIXED`](struct.mflags.html#associatedconstant.FIXED) is set, specifies to which
+/// address the file region is mapped. Otherwise,
+/// the mapping is performed at an unused
+/// location.
+///
+/// **len**:
+/// The length of the memory mapping to be
+/// created.
+///
+/// **prot**:
+/// Initial memory protection options for the
+/// memory mapping.
+///
+/// **flags**:
+/// Memory mapping flags.
+///
+/// **fd**:
+/// If [`ANON`](struct.mflags.html#associatedconstant.ANON) is set, this argument must be
+/// [`MAP_ANON_FD`](constant.MAP_ANON_FD.html). Otherwise, this argument
+/// specifies the file whose contents need to be
+/// mapped.
+///
+/// **off**:
+/// If [`ANON`](struct.mflags.html#associatedconstant.ANON) is set, this argument must be
+/// zero. Otherwise, this argument specifies the
+/// offset within the file at which the mapping
+/// starts.
+///
+/// **mem**:
+/// The starting address of the memory mapping.
+#[inline]
+pub unsafe fn mem_map(addr_: *mut (), len_: usize, prot_: mprot, flags_: mflags, fd_: fd, off_: filesize, mem_: &mut *mut ()) -> errno {
+  cloudabi_sys_mem_map(addr_, len_, prot_, flags_, fd_, off_, mem_)
+}
+
+/// Change the protection of a memory mapping.
+///
+/// ## Parameters
+///
+/// **mapping**:
+/// The pages that need their protection changed.
+///
+/// **prot**:
+/// New protection options.
+#[inline]
+pub unsafe fn mem_protect(mapping_: &mut [u8], prot_: mprot) -> errno {
+  cloudabi_sys_mem_protect(mapping_.as_mut_ptr() as *mut (), mapping_.len(), prot_)
+}
+
+/// Synchronize a region of memory with its physical storage.
+///
+/// ## Parameters
+///
+/// **mapping**:
+/// The pages that need to be synchronized.
+///
+/// **flags**:
+/// The method of synchronization.
+#[inline]
+pub unsafe fn mem_sync(mapping_: &mut [u8], flags_: msflags) -> errno {
+  cloudabi_sys_mem_sync(mapping_.as_mut_ptr() as *mut (), mapping_.len(), flags_)
+}
+
+/// Unmaps a region of memory.
+///
+/// ## Parameters
+///
+/// **mapping**:
+/// The pages that needs to be unmapped.
+#[inline]
+pub unsafe fn mem_unmap(mapping_: &mut [u8]) -> errno {
+  cloudabi_sys_mem_unmap(mapping_.as_mut_ptr() as *mut (), mapping_.len())
+}
+
+/// Concurrently polls for the occurrence of a set of events.
+///
+/// ## Parameters
+///
+/// **in**:
+/// The events to which to subscribe.
+///
+/// **out**:
+/// The events that have occurred.
+///
+/// **nsubscriptions**:
+/// Both the number of subscriptions and events.
+///
+/// **nevents**:
+/// The number of events stored.
+#[inline]
+pub unsafe fn poll(in_: *const subscription, out_: *mut event, nsubscriptions_: usize, nevents_: &mut usize) -> errno {
+  cloudabi_sys_poll(in_, out_, nsubscriptions_, nevents_)
+}
+
+/// Replaces the process by a new executable.
+///
+/// Process execution in CloudABI differs from POSIX in two ways:
+/// handling of arguments and inheritance of file descriptors.
+///
+/// CloudABI does not use string command line arguments. Instead,
+/// a buffer with binary data is copied into the address space of
+/// the new executable. The kernel does not enforce any specific
+/// structure to this data, although CloudABI's C library uses it
+/// to store a tree structure that is semantically identical to
+/// YAML.
+///
+/// Due to the strong focus on thread safety, file descriptors
+/// aren't inherited through close-on-exec flags. An explicit
+/// list of file descriptors that need to be retained needs to be
+/// provided. After execution, file descriptors are placed in the
+/// order in which they are stored in the array. This not only
+/// makes the execution process deterministic. It also prevents
+/// potential information disclosures about the layout of the
+/// original process.
+///
+/// ## Parameters
+///
+/// **fd**:
+/// A file descriptor of the new executable.
+///
+/// **data**:
+/// Binary argument data that is passed on to the
+/// new executable.
+///
+/// **fds**:
+/// The layout of the file descriptor table after
+/// execution.
+#[inline]
+pub unsafe fn proc_exec(fd_: fd, data_: &[u8], fds_: &[fd]) -> errno {
+  cloudabi_sys_proc_exec(fd_, data_.as_ptr() as *const (), data_.len(), fds_.as_ptr(), fds_.len())
+}
+
+/// Terminates the process normally.
+///
+/// ## Parameters
+///
+/// **rval**:
+/// The exit code returned by the process. The
+/// exit code can be obtained by other processes
+/// through [`event.union.proc_terminate.exitcode`](struct.event_proc_terminate.html#structfield.exitcode).
+#[inline]
+pub unsafe fn proc_exit(rval_: exitcode) -> ! {
+  cloudabi_sys_proc_exit(rval_)
+}
+
+/// Forks the process of the calling thread.
+///
+/// After forking, a new process shall be created, having only a
+/// copy of the calling thread. The parent process will obtain a
+/// process descriptor. When closed, the child process is
+/// automatically signaled with [`KILL`](enum.signal.html#variant.KILL).
+///
+/// ## Parameters
+///
+/// **fd**:
+/// In the parent process: the file descriptor
+/// number of the process descriptor.
+///
+/// In the child process: [`PROCESS_CHILD`](constant.PROCESS_CHILD.html).
+///
+/// **tid**:
+/// In the parent process: undefined.
+///
+/// In the child process: the thread ID of the
+/// initial thread of the child process.
+#[inline]
+pub unsafe fn proc_fork(fd_: &mut fd, tid_: &mut tid) -> errno {
+  cloudabi_sys_proc_fork(fd_, tid_)
+}
+
+/// Sends a signal to the process of the calling thread.
+///
+/// ## Parameters
+///
+/// **sig**:
+/// The signal condition that should be triggered.
+/// If the signal causes the process to terminate,
+/// its condition can be obtained by other
+/// processes through
+/// [`event.union.proc_terminate.signal`](struct.event_proc_terminate.html#structfield.signal).
+#[inline]
+pub unsafe fn proc_raise(sig_: signal) -> errno {
+  cloudabi_sys_proc_raise(sig_)
+}
+
+/// Obtains random data from the kernel random number generator.
+///
+/// As this interface is not guaranteed to be fast, it is advised
+/// that the random data obtained through this system call is used
+/// as the seed for a userspace pseudo-random number generator.
+///
+/// ## Parameters
+///
+/// **buf**:
+/// The buffer that needs to be filled with random
+/// data.
+#[inline]
+pub unsafe fn random_get(buf_: &mut [u8]) -> errno {
+  cloudabi_sys_random_get(buf_.as_mut_ptr() as *mut (), buf_.len())
+}
+
+/// Receives a message on a socket.
+///
+/// ## Parameters
+///
+/// **sock**:
+/// The socket on which a message should be
+/// received.
+///
+/// **in**:
+/// Input parameters.
+///
+/// **out**:
+/// Output parameters.
+#[inline]
+pub unsafe fn sock_recv(sock_: fd, in_: *const recv_in, out_: *mut recv_out) -> errno {
+  cloudabi_sys_sock_recv(sock_, in_, out_)
+}
+
+/// Sends a message on a socket.
+///
+/// ## Parameters
+///
+/// **sock**:
+/// The socket on which a message should be sent.
+///
+/// **in**:
+/// Input parameters.
+///
+/// **out**:
+/// Output parameters.
+#[inline]
+pub unsafe fn sock_send(sock_: fd, in_: *const send_in, out_: *mut send_out) -> errno {
+  cloudabi_sys_sock_send(sock_, in_, out_)
+}
+
+/// Shuts down socket send and receive channels.
+///
+/// ## Parameters
+///
+/// **sock**:
+/// The socket that needs its channels shut down.
+///
+/// **how**:
+/// Which channels on the socket need to be shut
+/// down.
+#[inline]
+pub unsafe fn sock_shutdown(sock_: fd, how_: sdflags) -> errno {
+  cloudabi_sys_sock_shutdown(sock_, how_)
+}
+
+/// Creates a new thread within the current process.
+///
+/// ## Parameters
+///
+/// **attr**:
+/// The desired attributes of the new thread.
+///
+/// **tid**:
+/// The thread ID of the new thread.
+#[inline]
+pub unsafe fn thread_create(attr_: *mut threadattr, tid_: &mut tid) -> errno {
+  cloudabi_sys_thread_create(attr_, tid_)
+}
+
+/// Terminates the calling thread.
+///
+/// This system call can also unlock a single userspace lock
+/// after termination, which can be used to implement thread
+/// joining.
+///
+/// ## Parameters
+///
+/// **lock**:
+/// Userspace lock that is locked for writing by
+/// the calling thread.
+///
+/// **scope**:
+/// Whether the lock is stored in private or
+/// shared memory.
+#[inline]
+pub unsafe fn thread_exit(lock_: *mut lock, scope_: scope) -> ! {
+  cloudabi_sys_thread_exit(lock_, scope_)
+}
+
+/// Temporarily yields execution of the calling thread.
+#[inline]
+pub unsafe fn thread_yield() -> errno {
+  cloudabi_sys_thread_yield()
+}
diff --git a/src/libstd/sys/cloudabi/abi/mod.rs b/src/libstd/sys/cloudabi/abi/mod.rs
new file mode 100644
index 00000000000..81a4d293423
--- /dev/null
+++ b/src/libstd/sys/cloudabi/abi/mod.rs
@@ -0,0 +1,13 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[allow(warnings)]
+mod cloudabi;
+pub use self::cloudabi::*;
diff --git a/src/libstd/sys/cloudabi/args.rs b/src/libstd/sys/cloudabi/args.rs
new file mode 100644
index 00000000000..7b62cc6adc9
--- /dev/null
+++ b/src/libstd/sys/cloudabi/args.rs
@@ -0,0 +1,17 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use sys::cloudabi::shims::args::*;
+
+#[allow(dead_code)]
+pub fn init(_: isize, _: *const *const u8) {}
+
+#[allow(dead_code)]
+pub fn cleanup() {}
diff --git a/src/libstd/sys/cloudabi/backtrace.rs b/src/libstd/sys/cloudabi/backtrace.rs
new file mode 100644
index 00000000000..33d93179237
--- /dev/null
+++ b/src/libstd/sys/cloudabi/backtrace.rs
@@ -0,0 +1,121 @@
+// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use error::Error;
+use ffi::CStr;
+use intrinsics;
+use io;
+use libc;
+use sys_common::backtrace::Frame;
+use unwind as uw;
+
+pub struct BacktraceContext;
+
+struct Context<'a> {
+    idx: usize,
+    frames: &'a mut [Frame],
+}
+
+#[derive(Debug)]
+struct UnwindError(uw::_Unwind_Reason_Code);
+
+impl Error for UnwindError {
+    fn description(&self) -> &'static str {
+        "unexpected return value while unwinding"
+    }
+}
+
+impl ::fmt::Display for UnwindError {
+    fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
+        write!(f, "{}: {:?}", self.description(), self.0)
+    }
+}
+
+#[inline(never)] // if we know this is a function call, we can skip it when
+                 // tracing
+pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
+    let mut cx = Context { idx: 0, frames };
+    let result_unwind =
+        unsafe { uw::_Unwind_Backtrace(trace_fn, &mut cx as *mut Context as *mut libc::c_void) };
+    // See libunwind:src/unwind/Backtrace.c for the return values.
+    // No, there is no doc.
+    match result_unwind {
+        // These return codes seem to be benign and need to be ignored for backtraces
+        // to show up properly on all tested platforms.
+        uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
+            Ok((cx.idx, BacktraceContext))
+        }
+        _ => Err(io::Error::new(
+            io::ErrorKind::Other,
+            UnwindError(result_unwind),
+        )),
+    }
+}
+
+extern "C" fn trace_fn(
+    ctx: *mut uw::_Unwind_Context,
+    arg: *mut libc::c_void,
+) -> uw::_Unwind_Reason_Code {
+    let cx = unsafe { &mut *(arg as *mut Context) };
+    let mut ip_before_insn = 0;
+    let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void };
+    if !ip.is_null() && ip_before_insn == 0 {
+        // this is a non-signaling frame, so `ip` refers to the address
+        // after the calling instruction. account for that.
+        ip = (ip as usize - 1) as *mut _;
+    }
+
+    let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) };
+    if cx.idx < cx.frames.len() {
+        cx.frames[cx.idx] = Frame {
+            symbol_addr: symaddr as *mut u8,
+            exact_position: ip as *mut u8,
+        };
+        cx.idx += 1;
+    }
+
+    uw::_URC_NO_REASON
+}
+
+pub fn foreach_symbol_fileline<F>(_: Frame, _: F, _: &BacktraceContext) -> io::Result<bool>
+where
+    F: FnMut(&[u8], u32) -> io::Result<()>,
+{
+    // No way to obtain this information on CloudABI.
+    Ok(false)
+}
+
+pub fn resolve_symname<F>(frame: Frame, callback: F, _: &BacktraceContext) -> io::Result<()>
+where
+    F: FnOnce(Option<&str>) -> io::Result<()>,
+{
+    unsafe {
+        let mut info: Dl_info = intrinsics::init();
+        let symname =
+            if dladdr(frame.exact_position as *mut _, &mut info) == 0 || info.dli_sname.is_null() {
+                None
+            } else {
+                CStr::from_ptr(info.dli_sname).to_str().ok()
+            };
+        callback(symname)
+    }
+}
+
+#[repr(C)]
+struct Dl_info {
+    dli_fname: *const libc::c_char,
+    dli_fbase: *mut libc::c_void,
+    dli_sname: *const libc::c_char,
+    dli_saddr: *mut libc::c_void,
+}
+
+extern "C" {
+    fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int;
+}
diff --git a/src/libstd/sys/cloudabi/condvar.rs b/src/libstd/sys/cloudabi/condvar.rs
new file mode 100644
index 00000000000..c05c837ade2
--- /dev/null
+++ b/src/libstd/sys/cloudabi/condvar.rs
@@ -0,0 +1,169 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use cell::UnsafeCell;
+use mem;
+use sync::atomic::{AtomicU32, Ordering};
+use sys::cloudabi::abi;
+use sys::mutex::{self, Mutex};
+use sys::time::dur2intervals;
+use time::Duration;
+
+extern "C" {
+    #[thread_local]
+    static __pthread_thread_id: abi::tid;
+}
+
+pub struct Condvar {
+    condvar: UnsafeCell<AtomicU32>,
+}
+
+unsafe impl Send for Condvar {}
+unsafe impl Sync for Condvar {}
+
+impl Condvar {
+    pub const fn new() -> Condvar {
+        Condvar {
+            condvar: UnsafeCell::new(AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0)),
+        }
+    }
+
+    pub unsafe fn init(&mut self) {}
+
+    pub unsafe fn notify_one(&self) {
+        let condvar = self.condvar.get();
+        if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
+            let ret = abi::condvar_signal(condvar as *mut abi::condvar, abi::scope::PRIVATE, 1);
+            assert_eq!(
+                ret,
+                abi::errno::SUCCESS,
+                "Failed to signal on condition variable"
+            );
+        }
+    }
+
+    pub unsafe fn notify_all(&self) {
+        let condvar = self.condvar.get();
+        if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
+            let ret = abi::condvar_signal(
+                condvar as *mut abi::condvar,
+                abi::scope::PRIVATE,
+                abi::nthreads::max_value(),
+            );
+            assert_eq!(
+                ret,
+                abi::errno::SUCCESS,
+                "Failed to broadcast on condition variable"
+            );
+        }
+    }
+
+    pub unsafe fn wait(&self, mutex: &Mutex) {
+        let mutex = mutex::raw(mutex);
+        assert_eq!(
+            (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+            __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+            "This lock is not write-locked by this thread"
+        );
+
+        // Call into the kernel to wait on the condition variable.
+        let condvar = self.condvar.get();
+        let subscription = abi::subscription {
+            type_: abi::eventtype::CONDVAR,
+            union: abi::subscription_union {
+                condvar: abi::subscription_condvar {
+                    condvar: condvar as *mut abi::condvar,
+                    condvar_scope: abi::scope::PRIVATE,
+                    lock: mutex as *mut abi::lock,
+                    lock_scope: abi::scope::PRIVATE,
+                },
+            },
+            ..mem::zeroed()
+        };
+        let mut event: abi::event = mem::uninitialized();
+        let mut nevents: usize = mem::uninitialized();
+        let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
+        assert_eq!(
+            ret,
+            abi::errno::SUCCESS,
+            "Failed to wait on condition variable"
+        );
+        assert_eq!(
+            event.error,
+            abi::errno::SUCCESS,
+            "Failed to wait on condition variable"
+        );
+    }
+
+    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+        let mutex = mutex::raw(mutex);
+        assert_eq!(
+            (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+            __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+            "This lock is not write-locked by this thread"
+        );
+
+        // Call into the kernel to wait on the condition variable.
+        let condvar = self.condvar.get();
+        let subscriptions = [
+            abi::subscription {
+                type_: abi::eventtype::CONDVAR,
+                union: abi::subscription_union {
+                    condvar: abi::subscription_condvar {
+                        condvar: condvar as *mut abi::condvar,
+                        condvar_scope: abi::scope::PRIVATE,
+                        lock: mutex as *mut abi::lock,
+                        lock_scope: abi::scope::PRIVATE,
+                    },
+                },
+                ..mem::zeroed()
+            },
+            abi::subscription {
+                type_: abi::eventtype::CLOCK,
+                union: abi::subscription_union {
+                    clock: abi::subscription_clock {
+                        clock_id: abi::clockid::MONOTONIC,
+                        timeout: dur2intervals(&dur),
+                        ..mem::zeroed()
+                    },
+                },
+                ..mem::zeroed()
+            },
+        ];
+        let mut events: [abi::event; 2] = mem::uninitialized();
+        let mut nevents: usize = mem::uninitialized();
+        let ret = abi::poll(subscriptions.as_ptr(), events.as_mut_ptr(), 2, &mut nevents);
+        assert_eq!(
+            ret,
+            abi::errno::SUCCESS,
+            "Failed to wait on condition variable"
+        );
+        for i in 0..nevents {
+            assert_eq!(
+                events[i].error,
+                abi::errno::SUCCESS,
+                "Failed to wait on condition variable"
+            );
+            if events[i].type_ == abi::eventtype::CONDVAR {
+                return true;
+            }
+        }
+        false
+    }
+
+    pub unsafe fn destroy(&self) {
+        let condvar = self.condvar.get();
+        assert_eq!(
+            (*condvar).load(Ordering::Relaxed),
+            abi::CONDVAR_HAS_NO_WAITERS.0,
+            "Attempted to destroy a condition variable with blocked threads"
+        );
+    }
+}
diff --git a/src/libstd/sys/cloudabi/mod.rs b/src/libstd/sys/cloudabi/mod.rs
new file mode 100644
index 00000000000..9e943c17fc8
--- /dev/null
+++ b/src/libstd/sys/cloudabi/mod.rs
@@ -0,0 +1,76 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use io;
+use libc;
+use mem;
+
+pub mod args;
+#[cfg(feature = "backtrace")]
+pub mod backtrace;
+#[path = "../unix/cmath.rs"]
+pub mod cmath;
+pub mod condvar;
+#[path = "../unix/memchr.rs"]
+pub mod memchr;
+pub mod mutex;
+pub mod os;
+#[path = "../unix/os_str.rs"]
+pub mod os_str;
+pub mod rwlock;
+pub mod stack_overflow;
+pub mod stdio;
+pub mod thread;
+#[path = "../unix/thread_local.rs"]
+pub mod thread_local;
+pub mod time;
+
+mod abi;
+
+mod shims;
+pub use self::shims::*;
+
+#[allow(dead_code)]
+pub fn init() {}
+
+pub fn decode_error_kind(errno: i32) -> io::ErrorKind {
+    match errno {
+        x if x == abi::errno::ACCES as i32 => io::ErrorKind::PermissionDenied,
+        x if x == abi::errno::ADDRINUSE as i32 => io::ErrorKind::AddrInUse,
+        x if x == abi::errno::ADDRNOTAVAIL as i32 => io::ErrorKind::AddrNotAvailable,
+        x if x == abi::errno::AGAIN as i32 => io::ErrorKind::WouldBlock,
+        x if x == abi::errno::CONNABORTED as i32 => io::ErrorKind::ConnectionAborted,
+        x if x == abi::errno::CONNREFUSED as i32 => io::ErrorKind::ConnectionRefused,
+        x if x == abi::errno::CONNRESET as i32 => io::ErrorKind::ConnectionReset,
+        x if x == abi::errno::EXIST as i32 => io::ErrorKind::AlreadyExists,
+        x if x == abi::errno::INTR as i32 => io::ErrorKind::Interrupted,
+        x if x == abi::errno::INVAL as i32 => io::ErrorKind::InvalidInput,
+        x if x == abi::errno::NOENT as i32 => io::ErrorKind::NotFound,
+        x if x == abi::errno::NOTCONN as i32 => io::ErrorKind::NotConnected,
+        x if x == abi::errno::PERM as i32 => io::ErrorKind::PermissionDenied,
+        x if x == abi::errno::PIPE as i32 => io::ErrorKind::BrokenPipe,
+        x if x == abi::errno::TIMEDOUT as i32 => io::ErrorKind::TimedOut,
+        _ => io::ErrorKind::Other,
+    }
+}
+
+pub unsafe fn abort_internal() -> ! {
+    ::core::intrinsics::abort();
+}
+
+pub use libc::strlen;
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+    unsafe {
+        let mut v = mem::uninitialized();
+        libc::arc4random_buf(&mut v as *mut _ as *mut libc::c_void, mem::size_of_val(&v));
+        v
+    }
+}
diff --git a/src/libstd/sys/cloudabi/mutex.rs b/src/libstd/sys/cloudabi/mutex.rs
new file mode 100644
index 00000000000..d4ba6bcfc80
--- /dev/null
+++ b/src/libstd/sys/cloudabi/mutex.rs
@@ -0,0 +1,158 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use cell::UnsafeCell;
+use mem;
+use sync::atomic::{AtomicU32, Ordering};
+use sys::cloudabi::abi;
+use sys::rwlock::{self, RWLock};
+
+extern "C" {
+    #[thread_local]
+    static __pthread_thread_id: abi::tid;
+}
+
+// Implement Mutex using an RWLock. This doesn't introduce any
+// performance overhead in this environment, as the operations would be
+// implemented identically.
+pub struct Mutex(RWLock);
+
+pub unsafe fn raw(m: &Mutex) -> *mut AtomicU32 {
+    rwlock::raw(&m.0)
+}
+
+impl Mutex {
+    pub const fn new() -> Mutex {
+        Mutex(RWLock::new())
+    }
+
+    pub unsafe fn init(&mut self) {
+        // This function should normally reinitialize the mutex after
+        // moving it to a different memory address. This implementation
+        // does not require adjustments after moving.
+    }
+
+    pub unsafe fn try_lock(&self) -> bool {
+        self.0.try_write()
+    }
+
+    pub unsafe fn lock(&self) {
+        self.0.write()
+    }
+
+    pub unsafe fn unlock(&self) {
+        self.0.write_unlock()
+    }
+
+    pub unsafe fn destroy(&self) {
+        self.0.destroy()
+    }
+}
+
+pub struct ReentrantMutex {
+    lock: UnsafeCell<AtomicU32>,
+    recursion: UnsafeCell<u32>,
+}
+
+impl ReentrantMutex {
+    pub unsafe fn uninitialized() -> ReentrantMutex {
+        mem::uninitialized()
+    }
+
+    pub unsafe fn init(&mut self) {
+        self.lock = UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0));
+        self.recursion = UnsafeCell::new(0);
+    }
+
+    pub unsafe fn try_lock(&self) -> bool {
+        // Attempt to acquire the lock.
+        let lock = self.lock.get();
+        let recursion = self.recursion.get();
+        if let Err(old) = (*lock).compare_exchange(
+            abi::LOCK_UNLOCKED.0,
+            __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+            Ordering::Acquire,
+            Ordering::Relaxed,
+        ) {
+            // If we fail to acquire the lock, it may be the case
+            // that we've already acquired it and may need to recurse.
+            if old & !abi::LOCK_KERNEL_MANAGED.0 == __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 {
+                *recursion += 1;
+                true
+            } else {
+                false
+            }
+        } else {
+            // Success.
+            assert_eq!(*recursion, 0, "Mutex has invalid recursion count");
+            true
+        }
+    }
+
+    pub unsafe fn lock(&self) {
+        if !self.try_lock() {
+            // Call into the kernel to acquire a write lock.
+            let lock = self.lock.get();
+            let subscription = abi::subscription {
+                type_: abi::eventtype::LOCK_WRLOCK,
+                union: abi::subscription_union {
+                    lock: abi::subscription_lock {
+                        lock: lock as *mut abi::lock,
+                        lock_scope: abi::scope::PRIVATE,
+                    },
+                },
+                ..mem::zeroed()
+            };
+            let mut event: abi::event = mem::uninitialized();
+            let mut nevents: usize = mem::uninitialized();
+            let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
+            assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire mutex");
+            assert_eq!(event.error, abi::errno::SUCCESS, "Failed to acquire mutex");
+        }
+    }
+
+    pub unsafe fn unlock(&self) {
+        let lock = self.lock.get();
+        let recursion = self.recursion.get();
+        assert_eq!(
+            (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+            __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+            "This mutex is locked by a different thread"
+        );
+
+        if *recursion > 0 {
+            *recursion -= 1;
+        } else if !(*lock)
+            .compare_exchange(
+                __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+                abi::LOCK_UNLOCKED.0,
+                Ordering::Release,
+                Ordering::Relaxed,
+            )
+            .is_ok()
+        {
+            // Lock is managed by kernelspace. Call into the kernel
+            // to unblock waiting threads.
+            let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
+            assert_eq!(ret, abi::errno::SUCCESS, "Failed to unlock a mutex");
+        }
+    }
+
+    pub unsafe fn destroy(&self) {
+        let lock = self.lock.get();
+        let recursion = self.recursion.get();
+        assert_eq!(
+            (*lock).load(Ordering::Relaxed),
+            abi::LOCK_UNLOCKED.0,
+            "Attempted to destroy locked mutex"
+        );
+        assert_eq!(*recursion, 0, "Recursion counter invalid");
+    }
+}
diff --git a/src/libstd/sys/cloudabi/os.rs b/src/libstd/sys/cloudabi/os.rs
new file mode 100644
index 00000000000..7e506b84df1
--- /dev/null
+++ b/src/libstd/sys/cloudabi/os.rs
@@ -0,0 +1,37 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ffi::CStr;
+use libc::{self, c_int};
+use str;
+
+pub use sys::cloudabi::shims::os::*;
+
+pub fn errno() -> i32 {
+    extern "C" {
+        #[thread_local]
+        static errno: c_int;
+    }
+
+    unsafe { errno as i32 }
+}
+
+/// Gets a detailed string description for the given error number.
+pub fn error_string(errno: i32) -> String {
+    // cloudlibc's strerror() is guaranteed to be thread-safe. There is
+    // thus no need to use strerror_r().
+    str::from_utf8(unsafe { CStr::from_ptr(libc::strerror(errno)) }.to_bytes())
+        .unwrap()
+        .to_owned()
+}
+
+pub fn exit(code: i32) -> ! {
+    unsafe { libc::exit(code as c_int) }
+}
diff --git a/src/libstd/sys/cloudabi/rwlock.rs b/src/libstd/sys/cloudabi/rwlock.rs
new file mode 100644
index 00000000000..8539aec5e2c
--- /dev/null
+++ b/src/libstd/sys/cloudabi/rwlock.rs
@@ -0,0 +1,237 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use cell::UnsafeCell;
+use mem;
+use sync::atomic::{AtomicU32, Ordering};
+use sys::cloudabi::abi;
+
+extern "C" {
+    #[thread_local]
+    static __pthread_thread_id: abi::tid;
+}
+
+#[thread_local]
+static mut RDLOCKS_ACQUIRED: u32 = 0;
+
+pub struct RWLock {
+    lock: UnsafeCell<AtomicU32>,
+}
+
+pub unsafe fn raw(r: &RWLock) -> *mut AtomicU32 {
+    r.lock.get()
+}
+
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {}
+
+impl RWLock {
+    pub const fn new() -> RWLock {
+        RWLock {
+            lock: UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)),
+        }
+    }
+
+    pub unsafe fn try_read(&self) -> bool {
+        let lock = self.lock.get();
+        let mut old = abi::LOCK_UNLOCKED.0;
+        while let Err(cur) =
+            (*lock).compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed)
+        {
+            if (cur & abi::LOCK_WRLOCKED.0) != 0 {
+                // Another thread already has a write lock.
+                assert_ne!(
+                    old & !abi::LOCK_KERNEL_MANAGED.0,
+                    __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+                    "Attempted to acquire a read lock while holding a write lock"
+                );
+                return false;
+            } else if (old & abi::LOCK_KERNEL_MANAGED.0) != 0 && RDLOCKS_ACQUIRED == 0 {
+                // Lock has threads waiting for the lock. Only acquire
+                // the lock if we have already acquired read locks. In
+                // that case, it is justified to acquire this lock to
+                // prevent a deadlock.
+                return false;
+            }
+            old = cur;
+        }
+
+        RDLOCKS_ACQUIRED += 1;
+        true
+    }
+
+    pub unsafe fn read(&self) {
+        if !self.try_read() {
+            // Call into the kernel to acquire a read lock.
+            let lock = self.lock.get();
+            let subscription = abi::subscription {
+                type_: abi::eventtype::LOCK_RDLOCK,
+                union: abi::subscription_union {
+                    lock: abi::subscription_lock {
+                        lock: lock as *mut abi::lock,
+                        lock_scope: abi::scope::PRIVATE,
+                    },
+                },
+                ..mem::zeroed()
+            };
+            let mut event: abi::event = mem::uninitialized();
+            let mut nevents: usize = mem::uninitialized();
+            let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
+            assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire read lock");
+            assert_eq!(
+                event.error,
+                abi::errno::SUCCESS,
+                "Failed to acquire read lock"
+            );
+
+            RDLOCKS_ACQUIRED += 1;
+        }
+    }
+
+    pub unsafe fn read_unlock(&self) {
+        // Perform a read unlock. We can do this in userspace, except when
+        // other threads are blocked and we are performing the last unlock.
+        // In that case, call into the kernel.
+        //
+        // Other threads may attempt to increment the read lock count,
+        // meaning that the call into the kernel could be spurious. To
+        // prevent this from happening, upgrade to a write lock first. This
+        // allows us to call into the kernel, having the guarantee that the
+        // lock value will not change in the meantime.
+        assert!(RDLOCKS_ACQUIRED > 0, "Bad lock count");
+        let mut old = 1;
+        loop {
+            let lock = self.lock.get();
+            if old == 1 | abi::LOCK_KERNEL_MANAGED.0 {
+                // Last read lock while threads are waiting. Attempt to upgrade
+                // to a write lock before calling into the kernel to unlock.
+                if let Err(cur) = (*lock).compare_exchange_weak(
+                    old,
+                    __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 | abi::LOCK_KERNEL_MANAGED.0,
+                    Ordering::Acquire,
+                    Ordering::Relaxed,
+                ) {
+                    old = cur;
+                } else {
+                    // Call into the kernel to unlock.
+                    let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
+                    assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock");
+                    break;
+                }
+            } else {
+                // No threads waiting or not the last read lock. Just decrement
+                // the read lock count.
+                assert_ne!(
+                    old & !abi::LOCK_KERNEL_MANAGED.0,
+                    0,
+                    "This rwlock is not locked"
+                );
+                assert_eq!(
+                    old & abi::LOCK_WRLOCKED.0,
+                    0,
+                    "Attempted to read-unlock a write-locked rwlock"
+                );
+                if let Err(cur) = (*lock).compare_exchange_weak(
+                    old,
+                    old - 1,
+                    Ordering::Acquire,
+                    Ordering::Relaxed,
+                ) {
+                    old = cur;
+                } else {
+                    break;
+                }
+            }
+        }
+
+        RDLOCKS_ACQUIRED -= 1;
+    }
+
+    pub unsafe fn try_write(&self) -> bool {
+        // Attempt to acquire the lock.
+        let lock = self.lock.get();
+        if let Err(old) = (*lock).compare_exchange(
+            abi::LOCK_UNLOCKED.0,
+            __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+            Ordering::Acquire,
+            Ordering::Relaxed,
+        ) {
+            // Failure. Crash upon recursive acquisition.
+            assert_ne!(
+                old & !abi::LOCK_KERNEL_MANAGED.0,
+                __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+                "Attempted to recursive write-lock a rwlock",
+            );
+            false
+        } else {
+            // Success.
+            true
+        }
+    }
+
+    pub unsafe fn write(&self) {
+        if !self.try_write() {
+            // Call into the kernel to acquire a write lock.
+            let lock = self.lock.get();
+            let subscription = abi::subscription {
+                type_: abi::eventtype::LOCK_WRLOCK,
+                union: abi::subscription_union {
+                    lock: abi::subscription_lock {
+                        lock: lock as *mut abi::lock,
+                        lock_scope: abi::scope::PRIVATE,
+                    },
+                },
+                ..mem::zeroed()
+            };
+            let mut event: abi::event = mem::uninitialized();
+            let mut nevents: usize = mem::uninitialized();
+            let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
+            assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire write lock");
+            assert_eq!(
+                event.error,
+                abi::errno::SUCCESS,
+                "Failed to acquire write lock"
+            );
+        }
+    }
+
+    pub unsafe fn write_unlock(&self) {
+        let lock = self.lock.get();
+        assert_eq!(
+            (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+            __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+            "This rwlock is not write-locked by this thread"
+        );
+
+        if !(*lock)
+            .compare_exchange(
+                __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+                abi::LOCK_UNLOCKED.0,
+                Ordering::Release,
+                Ordering::Relaxed,
+            )
+            .is_ok()
+        {
+            // Lock is managed by kernelspace. Call into the kernel
+            // to unblock waiting threads.
+            let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
+            assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock");
+        }
+    }
+
+    pub unsafe fn destroy(&self) {
+        let lock = self.lock.get();
+        assert_eq!(
+            (*lock).load(Ordering::Relaxed),
+            abi::LOCK_UNLOCKED.0,
+            "Attempted to destroy locked rwlock"
+        );
+    }
+}
diff --git a/src/libstd/sys/cloudabi/shims/args.rs b/src/libstd/sys/cloudabi/shims/args.rs
new file mode 100644
index 00000000000..1b5785adc8a
--- /dev/null
+++ b/src/libstd/sys/cloudabi/shims/args.rs
@@ -0,0 +1,45 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ffi::OsString;
+
+pub struct Args(());
+
+impl Args {
+    pub fn inner_debug(&self) -> &[OsString] {
+        &[]
+    }
+}
+
+impl Iterator for Args {
+    type Item = OsString;
+    fn next(&mut self) -> Option<OsString> {
+        None
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (0, Some(0))
+    }
+}
+
+impl ExactSizeIterator for Args {
+    fn len(&self) -> usize {
+        0
+    }
+}
+
+impl DoubleEndedIterator for Args {
+    fn next_back(&mut self) -> Option<OsString> {
+        None
+    }
+}
+
+pub fn args() -> Args {
+    Args(())
+}
diff --git a/src/libstd/sys/cloudabi/shims/env.rs b/src/libstd/sys/cloudabi/shims/env.rs
new file mode 100644
index 00000000000..31777aa94bc
--- /dev/null
+++ b/src/libstd/sys/cloudabi/shims/env.rs
@@ -0,0 +1,19 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub mod os {
+    pub const FAMILY: &'static str = "cloudabi";
+    pub const OS: &'static str = "cloudabi";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
diff --git a/src/libstd/sys/cloudabi/shims/fs.rs b/src/libstd/sys/cloudabi/shims/fs.rs
new file mode 100644
index 00000000000..d3da0fbc371
--- /dev/null
+++ b/src/libstd/sys/cloudabi/shims/fs.rs
@@ -0,0 +1,302 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ffi::OsString;
+use fmt;
+use hash::{Hash, Hasher};
+use io::{self, SeekFrom};
+use path::{Path, PathBuf};
+use sys::time::SystemTime;
+use sys::{unsupported, Void};
+
+pub struct File(Void);
+
+pub struct FileAttr(Void);
+
+pub struct ReadDir(Void);
+
+pub struct DirEntry(Void);
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions {}
+
+pub struct FilePermissions(Void);
+
+pub struct FileType(Void);
+
+#[derive(Debug)]
+pub struct DirBuilder {}
+
+impl FileAttr {
+    pub fn size(&self) -> u64 {
+        match self.0 {}
+    }
+
+    pub fn perm(&self) -> FilePermissions {
+        match self.0 {}
+    }
+
+    pub fn file_type(&self) -> FileType {
+        match self.0 {}
+    }
+
+    pub fn modified(&self) -> io::Result<SystemTime> {
+        match self.0 {}
+    }
+
+    pub fn accessed(&self) -> io::Result<SystemTime> {
+        match self.0 {}
+    }
+
+    pub fn created(&self) -> io::Result<SystemTime> {
+        match self.0 {}
+    }
+}
+
+impl Clone for FileAttr {
+    fn clone(&self) -> FileAttr {
+        match self.0 {}
+    }
+}
+
+impl FilePermissions {
+    pub fn readonly(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn set_readonly(&mut self, _readonly: bool) {
+        match self.0 {}
+    }
+}
+
+impl Clone for FilePermissions {
+    fn clone(&self) -> FilePermissions {
+        match self.0 {}
+    }
+}
+
+impl PartialEq for FilePermissions {
+    fn eq(&self, _other: &FilePermissions) -> bool {
+        match self.0 {}
+    }
+}
+
+impl Eq for FilePermissions {}
+
+impl fmt::Debug for FilePermissions {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+impl FileType {
+    pub fn is_dir(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn is_file(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn is_symlink(&self) -> bool {
+        match self.0 {}
+    }
+}
+
+impl Clone for FileType {
+    fn clone(&self) -> FileType {
+        match self.0 {}
+    }
+}
+
+impl Copy for FileType {}
+
+impl PartialEq for FileType {
+    fn eq(&self, _other: &FileType) -> bool {
+        match self.0 {}
+    }
+}
+
+impl Eq for FileType {}
+
+impl Hash for FileType {
+    fn hash<H: Hasher>(&self, _h: &mut H) {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for FileType {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for ReadDir {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+impl Iterator for ReadDir {
+    type Item = io::Result<DirEntry>;
+
+    fn next(&mut self) -> Option<io::Result<DirEntry>> {
+        match self.0 {}
+    }
+}
+
+impl DirEntry {
+    pub fn path(&self) -> PathBuf {
+        match self.0 {}
+    }
+
+    pub fn file_name(&self) -> OsString {
+        match self.0 {}
+    }
+
+    pub fn metadata(&self) -> io::Result<FileAttr> {
+        match self.0 {}
+    }
+
+    pub fn file_type(&self) -> io::Result<FileType> {
+        match self.0 {}
+    }
+}
+
+impl OpenOptions {
+    pub fn new() -> OpenOptions {
+        OpenOptions {}
+    }
+
+    pub fn read(&mut self, _read: bool) {}
+    pub fn write(&mut self, _write: bool) {}
+    pub fn append(&mut self, _append: bool) {}
+    pub fn truncate(&mut self, _truncate: bool) {}
+    pub fn create(&mut self, _create: bool) {}
+    pub fn create_new(&mut self, _create_new: bool) {}
+}
+
+impl File {
+    pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> {
+        unsupported()
+    }
+
+    pub fn file_attr(&self) -> io::Result<FileAttr> {
+        match self.0 {}
+    }
+
+    pub fn fsync(&self) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn datasync(&self) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn truncate(&self, _size: u64) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn flush(&self) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
+        match self.0 {}
+    }
+
+    pub fn duplicate(&self) -> io::Result<File> {
+        match self.0 {}
+    }
+
+    pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn diverge(&self) -> ! {
+        match self.0 {}
+    }
+}
+
+impl DirBuilder {
+    pub fn new() -> DirBuilder {
+        DirBuilder {}
+    }
+
+    pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
+        unsupported()
+    }
+}
+
+impl fmt::Debug for File {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
+    unsupported()
+}
+
+pub fn unlink(_p: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
+    match perm.0 {}
+}
+
+pub fn rmdir(_p: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn stat(_p: &Path) -> io::Result<FileAttr> {
+    unsupported()
+}
+
+pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
+    unsupported()
+}
+
+pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> {
+    unsupported()
+}
diff --git a/src/libstd/sys/cloudabi/shims/mod.rs b/src/libstd/sys/cloudabi/shims/mod.rs
new file mode 100644
index 00000000000..407c2b90511
--- /dev/null
+++ b/src/libstd/sys/cloudabi/shims/mod.rs
@@ -0,0 +1,32 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use io;
+
+pub mod args;
+pub mod env;
+pub mod fs;
+pub mod net;
+#[path = "../../unix/path.rs"]
+pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod os;
+
+// This enum is used as the storage for a bunch of types which can't actually exist.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub enum Void {}
+
+pub fn unsupported<T>() -> io::Result<T> {
+    Err(io::Error::new(
+        io::ErrorKind::Other,
+        "This function is not available on CloudABI.",
+    ))
+}
diff --git a/src/libstd/sys/cloudabi/shims/net.rs b/src/libstd/sys/cloudabi/shims/net.rs
new file mode 100644
index 00000000000..93eaf6a9e7d
--- /dev/null
+++ b/src/libstd/sys/cloudabi/shims/net.rs
@@ -0,0 +1,296 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use fmt;
+use io;
+use net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
+use time::Duration;
+use sys::{unsupported, Void};
+
+pub extern crate libc as netc;
+
+pub struct TcpStream(Void);
+
+impl TcpStream {
+    pub fn connect(_: &SocketAddr) -> io::Result<TcpStream> {
+        unsupported()
+    }
+
+    pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
+        unsupported()
+    }
+
+    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        match self.0 {}
+    }
+
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        match self.0 {}
+    }
+
+    pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpStream> {
+        match self.0 {}
+    }
+
+    pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn nodelay(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        match self.0 {}
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        match self.0 {}
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for TcpStream {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+pub struct TcpListener(Void);
+
+impl TcpListener {
+    pub fn bind(_: &SocketAddr) -> io::Result<TcpListener> {
+        unsupported()
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+        match self.0 {}
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpListener> {
+        match self.0 {}
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        match self.0 {}
+    }
+
+    pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn only_v6(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        match self.0 {}
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for TcpListener {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+pub struct UdpSocket(Void);
+
+impl UdpSocket {
+    pub fn bind(_: &SocketAddr) -> io::Result<UdpSocket> {
+        unsupported()
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        match self.0 {}
+    }
+
+    pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        match self.0 {}
+    }
+
+    pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn duplicate(&self) -> io::Result<UdpSocket> {
+        match self.0 {}
+    }
+
+    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        match self.0 {}
+    }
+
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        match self.0 {}
+    }
+
+    pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn broadcast(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+        match self.0 {}
+    }
+
+    pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        match self.0 {}
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        match self.0 {}
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn send(&self, _: &[u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn connect(&self, _: &SocketAddr) -> io::Result<()> {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for UdpSocket {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+pub struct LookupHost(Void);
+
+impl Iterator for LookupHost {
+    type Item = SocketAddr;
+    fn next(&mut self) -> Option<SocketAddr> {
+        match self.0 {}
+    }
+}
+
+pub fn lookup_host(_: &str) -> io::Result<LookupHost> {
+    unsupported()
+}
diff --git a/src/libstd/sys/cloudabi/shims/os.rs b/src/libstd/sys/cloudabi/shims/os.rs
new file mode 100644
index 00000000000..1e355d9ad04
--- /dev/null
+++ b/src/libstd/sys/cloudabi/shims/os.rs
@@ -0,0 +1,95 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use error::Error as StdError;
+use ffi::{OsStr, OsString};
+use fmt;
+use io;
+use iter;
+use path::{self, PathBuf};
+use sys::{unsupported, Void};
+
+pub fn getcwd() -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub fn chdir(_: &path::Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub type Env = iter::Empty<(OsString, OsString)>;
+
+pub fn env() -> Env {
+    iter::empty()
+}
+
+pub fn getenv(_: &OsStr) -> io::Result<Option<OsString>> {
+    Ok(None)
+}
+
+pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn unsetenv(_: &OsStr) -> io::Result<()> {
+    unsupported()
+}
+
+pub struct SplitPaths<'a>(&'a Void);
+
+pub fn split_paths(_unparsed: &OsStr) -> SplitPaths {
+    panic!("unsupported")
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+    type Item = PathBuf;
+    fn next(&mut self) -> Option<PathBuf> {
+        match *self.0 {}
+    }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
+where
+    I: Iterator<Item = T>,
+    T: AsRef<OsStr>,
+{
+    Err(JoinPathsError)
+}
+
+impl fmt::Display for JoinPathsError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        "not supported on CloudABI yet".fmt(f)
+    }
+}
+
+impl StdError for JoinPathsError {
+    fn description(&self) -> &str {
+        "not supported on CloudABI yet"
+    }
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+    None
+}
+
+pub fn temp_dir() -> PathBuf {
+    PathBuf::from("/tmp")
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub fn getpid() -> u32 {
+    1
+}
diff --git a/src/libstd/sys/cloudabi/shims/pipe.rs b/src/libstd/sys/cloudabi/shims/pipe.rs
new file mode 100644
index 00000000000..77a9cd62590
--- /dev/null
+++ b/src/libstd/sys/cloudabi/shims/pipe.rs
@@ -0,0 +1,32 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use io;
+use sys::Void;
+
+pub struct AnonPipe(Void);
+
+impl AnonPipe {
+    pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn diverge(&self) -> ! {
+        match self.0 {}
+    }
+}
+
+pub fn read2(p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> {
+    match p1.0 {}
+}
diff --git a/src/libstd/sys/cloudabi/shims/process.rs b/src/libstd/sys/cloudabi/shims/process.rs
new file mode 100644
index 00000000000..52e8c82e2b2
--- /dev/null
+++ b/src/libstd/sys/cloudabi/shims/process.rs
@@ -0,0 +1,147 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ffi::OsStr;
+use fmt;
+use io;
+use sys::fs::File;
+use sys::pipe::AnonPipe;
+use sys::{unsupported, Void};
+use sys_common::process::{CommandEnv, DefaultEnvKey};
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+    env: CommandEnv<DefaultEnvKey>,
+}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+    pub stdin: Option<AnonPipe>,
+    pub stdout: Option<AnonPipe>,
+    pub stderr: Option<AnonPipe>,
+}
+
+pub enum Stdio {
+    Inherit,
+    Null,
+    MakePipe,
+}
+
+impl Command {
+    pub fn new(_program: &OsStr) -> Command {
+        Command {
+            env: Default::default(),
+        }
+    }
+
+    pub fn arg(&mut self, _arg: &OsStr) {}
+
+    pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+        &mut self.env
+    }
+
+    pub fn cwd(&mut self, _dir: &OsStr) {}
+
+    pub fn stdin(&mut self, _stdin: Stdio) {}
+
+    pub fn stdout(&mut self, _stdout: Stdio) {}
+
+    pub fn stderr(&mut self, _stderr: Stdio) {}
+
+    pub fn spawn(
+        &mut self,
+        _default: Stdio,
+        _needs_stdin: bool,
+    ) -> io::Result<(Process, StdioPipes)> {
+        unsupported()
+    }
+}
+
+impl From<AnonPipe> for Stdio {
+    fn from(pipe: AnonPipe) -> Stdio {
+        pipe.diverge()
+    }
+}
+
+impl From<File> for Stdio {
+    fn from(file: File) -> Stdio {
+        file.diverge()
+    }
+}
+
+impl fmt::Debug for Command {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        Ok(())
+    }
+}
+
+pub struct ExitStatus(Void);
+
+impl ExitStatus {
+    pub fn success(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn code(&self) -> Option<i32> {
+        match self.0 {}
+    }
+}
+
+impl Clone for ExitStatus {
+    fn clone(&self) -> ExitStatus {
+        match self.0 {}
+    }
+}
+
+impl Copy for ExitStatus {}
+
+impl PartialEq for ExitStatus {
+    fn eq(&self, _other: &ExitStatus) -> bool {
+        match self.0 {}
+    }
+}
+
+impl Eq for ExitStatus {}
+
+impl fmt::Debug for ExitStatus {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+impl fmt::Display for ExitStatus {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+pub struct Process(Void);
+
+impl Process {
+    pub fn id(&self) -> u32 {
+        match self.0 {}
+    }
+
+    pub fn kill(&mut self) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn wait(&mut self) -> io::Result<ExitStatus> {
+        match self.0 {}
+    }
+
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+        match self.0 {}
+    }
+}
diff --git a/src/libstd/sys/cloudabi/stack_overflow.rs b/src/libstd/sys/cloudabi/stack_overflow.rs
new file mode 100644
index 00000000000..5c0b1e5671e
--- /dev/null
+++ b/src/libstd/sys/cloudabi/stack_overflow.rs
@@ -0,0 +1,23 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![cfg_attr(test, allow(dead_code))]
+
+pub struct Handler;
+
+impl Handler {
+    pub unsafe fn new() -> Handler {
+        Handler
+    }
+}
+
+pub unsafe fn init() {}
+
+pub unsafe fn cleanup() {}
diff --git a/src/libstd/sys/cloudabi/stdio.rs b/src/libstd/sys/cloudabi/stdio.rs
new file mode 100644
index 00000000000..9519a926471
--- /dev/null
+++ b/src/libstd/sys/cloudabi/stdio.rs
@@ -0,0 +1,79 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use io;
+use sys::cloudabi::abi;
+
+pub struct Stdin(());
+pub struct Stdout(());
+pub struct Stderr(());
+
+impl Stdin {
+    pub fn new() -> io::Result<Stdin> {
+        Ok(Stdin(()))
+    }
+
+    pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+        Ok(0)
+    }
+}
+
+impl Stdout {
+    pub fn new() -> io::Result<Stdout> {
+        Ok(Stdout(()))
+    }
+
+    pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+        Err(io::Error::new(
+            io::ErrorKind::BrokenPipe,
+            "Stdout is not connected to any output in this environment",
+        ))
+    }
+
+    pub fn flush(&self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+impl Stderr {
+    pub fn new() -> io::Result<Stderr> {
+        Ok(Stderr(()))
+    }
+
+    pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+        Err(io::Error::new(
+            io::ErrorKind::BrokenPipe,
+            "Stderr is not connected to any output in this environment",
+        ))
+    }
+
+    pub fn flush(&self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+// FIXME: right now this raw stderr handle is used in a few places because
+//        std::io::stderr_raw isn't exposed, but once that's exposed this impl
+//        should go away
+impl io::Write for Stderr {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+        Stderr::write(self, data)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Stderr::flush(self)
+    }
+}
+
+pub fn is_ebadf(err: &io::Error) -> bool {
+    err.raw_os_error() == Some(abi::errno::BADF as i32)
+}
+
+pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
diff --git a/src/libstd/sys/cloudabi/thread.rs b/src/libstd/sys/cloudabi/thread.rs
new file mode 100644
index 00000000000..c980ae75261
--- /dev/null
+++ b/src/libstd/sys/cloudabi/thread.rs
@@ -0,0 +1,124 @@
+// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use alloc::boxed::FnBox;
+use cmp;
+use ffi::CStr;
+use io;
+use libc;
+use mem;
+use ptr;
+use sys::cloudabi::abi;
+use sys::time::dur2intervals;
+use sys_common::thread::*;
+use time::Duration;
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
+
+pub struct Thread {
+    id: libc::pthread_t,
+}
+
+// CloudABI has pthread_t as a pointer in which case we still want
+// a thread to be Send/Sync
+unsafe impl Send for Thread {}
+unsafe impl Sync for Thread {}
+
+impl Thread {
+    pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>) -> io::Result<Thread> {
+        let p = box p;
+        let mut native: libc::pthread_t = mem::zeroed();
+        let mut attr: libc::pthread_attr_t = mem::zeroed();
+        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
+
+        let stack_size = cmp::max(stack, min_stack_size(&attr));
+        assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0);
+
+        let ret = libc::pthread_create(&mut native, &attr, thread_start, &*p as *const _ as *mut _);
+        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
+
+        return if ret != 0 {
+            Err(io::Error::from_raw_os_error(ret))
+        } else {
+            mem::forget(p); // ownership passed to pthread_create
+            Ok(Thread { id: native })
+        };
+
+        extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
+            unsafe {
+                start_thread(main as *mut u8);
+            }
+            ptr::null_mut()
+        }
+    }
+
+    pub fn yield_now() {
+        let ret = unsafe { abi::thread_yield() };
+        debug_assert_eq!(ret, abi::errno::SUCCESS);
+    }
+
+    pub fn set_name(_name: &CStr) {
+        // CloudABI has no way to set a thread name.
+    }
+
+    pub fn sleep(dur: Duration) {
+        unsafe {
+            let subscription = abi::subscription {
+                type_: abi::eventtype::CLOCK,
+                union: abi::subscription_union {
+                    clock: abi::subscription_clock {
+                        clock_id: abi::clockid::MONOTONIC,
+                        timeout: dur2intervals(&dur),
+                        ..mem::zeroed()
+                    },
+                },
+                ..mem::zeroed()
+            };
+            let mut event: abi::event = mem::uninitialized();
+            let mut nevents: usize = mem::uninitialized();
+            let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
+            assert_eq!(ret, abi::errno::SUCCESS);
+            assert_eq!(event.error, abi::errno::SUCCESS);
+        }
+    }
+
+    pub fn join(self) {
+        unsafe {
+            let ret = libc::pthread_join(self.id, ptr::null_mut());
+            mem::forget(self);
+            assert!(
+                ret == 0,
+                "failed to join thread: {}",
+                io::Error::from_raw_os_error(ret)
+            );
+        }
+    }
+}
+
+impl Drop for Thread {
+    fn drop(&mut self) {
+        let ret = unsafe { libc::pthread_detach(self.id) };
+        debug_assert_eq!(ret, 0);
+    }
+}
+
+#[cfg_attr(test, allow(dead_code))]
+pub mod guard {
+    pub unsafe fn current() -> Option<usize> {
+        None
+    }
+    pub unsafe fn init() -> Option<usize> {
+        None
+    }
+}
+
+fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
+    libc::PTHREAD_STACK_MIN
+}
diff --git a/src/libstd/sys/cloudabi/time.rs b/src/libstd/sys/cloudabi/time.rs
new file mode 100644
index 00000000000..ee12731619a
--- /dev/null
+++ b/src/libstd/sys/cloudabi/time.rs
@@ -0,0 +1,111 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use mem;
+use sys::cloudabi::abi;
+use time::Duration;
+
+const NSEC_PER_SEC: abi::timestamp = 1_000_000_000;
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct Instant {
+    t: abi::timestamp,
+}
+
+pub fn dur2intervals(dur: &Duration) -> abi::timestamp {
+    dur.as_secs()
+        .checked_mul(NSEC_PER_SEC)
+        .and_then(|nanos| nanos.checked_add(dur.subsec_nanos() as abi::timestamp))
+        .expect("overflow converting duration to nanoseconds")
+}
+
+impl Instant {
+    pub fn now() -> Instant {
+        unsafe {
+            let mut t = mem::uninitialized();
+            let ret = abi::clock_time_get(abi::clockid::MONOTONIC, 0, &mut t);
+            assert_eq!(ret, abi::errno::SUCCESS);
+            Instant { t: t }
+        }
+    }
+
+    pub fn sub_instant(&self, other: &Instant) -> Duration {
+        let diff = self.t
+            .checked_sub(other.t)
+            .expect("second instant is later than self");
+        Duration::new(diff / NSEC_PER_SEC, (diff % NSEC_PER_SEC) as u32)
+    }
+
+    pub fn add_duration(&self, other: &Duration) -> Instant {
+        Instant {
+            t: self.t
+                .checked_add(dur2intervals(other))
+                .expect("overflow when adding duration to instant"),
+        }
+    }
+
+    pub fn sub_duration(&self, other: &Duration) -> Instant {
+        Instant {
+            t: self.t
+                .checked_sub(dur2intervals(other))
+                .expect("overflow when subtracting duration from instant"),
+        }
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct SystemTime {
+    t: abi::timestamp,
+}
+
+impl SystemTime {
+    pub fn now() -> SystemTime {
+        unsafe {
+            let mut t = mem::uninitialized();
+            let ret = abi::clock_time_get(abi::clockid::REALTIME, 0, &mut t);
+            assert_eq!(ret, abi::errno::SUCCESS);
+            SystemTime { t: t }
+        }
+    }
+
+    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+        if self.t >= other.t {
+            let diff = self.t - other.t;
+            Ok(Duration::new(
+                diff / NSEC_PER_SEC,
+                (diff % NSEC_PER_SEC) as u32,
+            ))
+        } else {
+            let diff = other.t - self.t;
+            Err(Duration::new(
+                diff / NSEC_PER_SEC,
+                (diff % NSEC_PER_SEC) as u32,
+            ))
+        }
+    }
+
+    pub fn add_duration(&self, other: &Duration) -> SystemTime {
+        SystemTime {
+            t: self.t
+                .checked_add(dur2intervals(other))
+                .expect("overflow when adding duration to instant"),
+        }
+    }
+
+    pub fn sub_duration(&self, other: &Duration) -> SystemTime {
+        SystemTime {
+            t: self.t
+                .checked_sub(dur2intervals(other))
+                .expect("overflow when subtracting duration from instant"),
+        }
+    }
+}
+
+pub const UNIX_EPOCH: SystemTime = SystemTime { t: 0 };
diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs
index be8cb88416b..1231898ed7e 100644
--- a/src/libstd/sys/mod.rs
+++ b/src/libstd/sys/mod.rs
@@ -39,6 +39,9 @@ cfg_if! {
     } else if #[cfg(windows)] {
         mod windows;
         pub use self::windows::*;
+    } else if #[cfg(target_os = "cloudabi")] {
+        mod cloudabi;
+        pub use self::cloudabi::*;
     } else if #[cfg(target_os = "redox")] {
         mod redox;
         pub use self::redox::*;
@@ -59,9 +62,10 @@ cfg_if! {
     if #[cfg(any(unix, target_os = "redox"))] {
         // On unix we'll document what's already available
         pub use self::ext as unix_ext;
-    } else if #[cfg(target_arch = "wasm32")] {
-        // On wasm right now the module below doesn't compile (missing things
-        // in `libc` which is empty) so just omit everything with an empty module
+    } else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32"))] {
+        // On CloudABI and wasm right now the module below doesn't compile
+        // (missing things in `libc` which is empty) so just omit everything
+        // with an empty module
         #[unstable(issue = "0", feature = "std_internals")]
         pub mod unix_ext {}
     } else {
@@ -77,8 +81,9 @@ cfg_if! {
     if #[cfg(windows)] {
         // On windows we'll just be documenting what's already available
         pub use self::ext as windows_ext;
-    } else if #[cfg(target_arch = "wasm32")] {
-        // On wasm right now the shim below doesn't compile, so just omit it
+    } else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32"))] {
+        // On CloudABI and wasm right now the shim below doesn't compile, so
+        // just omit it
         #[unstable(issue = "0", feature = "std_internals")]
         pub mod windows_ext {}
     } else {
diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs
index 938e8656808..27504d374dd 100644
--- a/src/libstd/sys_common/mod.rs
+++ b/src/libstd/sys_common/mod.rs
@@ -46,7 +46,7 @@ pub mod bytestring;
 pub mod process;
 
 cfg_if! {
-    if #[cfg(any(target_os = "redox", target_os = "l4re"))] {
+    if #[cfg(any(target_os = "cloudabi", target_os = "l4re", target_os = "redox"))] {
         pub use sys::net;
     } else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] {
         pub use sys::net;
diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs
index fdbcfd10bde..8071f07d811 100644
--- a/src/tools/tidy/src/pal.rs
+++ b/src/tools/tidy/src/pal.rs
@@ -168,8 +168,8 @@ fn find_test_mod(contents: &str) -> usize {
         let prev_newline_idx = contents[..prev_newline_idx].rfind('\n');
         if let Some(nl) = prev_newline_idx {
             let prev_line = &contents[nl + 1 .. mod_tests_idx];
-            let emcc_cfg = "cfg(all(test, not(target_os";
-            if prev_line.contains(emcc_cfg) {
+            if prev_line.contains("cfg(all(test, not(target_os")
+                || prev_line.contains("cfg(all(test, not(any(target_os") {
                 nl
             } else {
                 mod_tests_idx