about summary refs log tree commit diff
path: root/src/libstd/sys
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd/sys')
-rw-r--r--src/libstd/sys/cloudabi/abi/cloudabi.rs18
-rw-r--r--src/libstd/sys/cloudabi/backtrace.rs17
-rw-r--r--src/libstd/sys/cloudabi/shims/process.rs12
-rw-r--r--src/libstd/sys/cloudabi/stdio.rs4
-rw-r--r--src/libstd/sys/cloudabi/thread.rs10
-rw-r--r--src/libstd/sys/mod.rs3
-rw-r--r--src/libstd/sys/redox/args.rs16
-rw-r--r--src/libstd/sys/redox/backtrace/tracing.rs17
-rw-r--r--src/libstd/sys/redox/ext/ffi.rs10
-rw-r--r--src/libstd/sys/redox/ext/fs.rs74
-rw-r--r--src/libstd/sys/redox/ext/mod.rs1
-rw-r--r--src/libstd/sys/redox/ext/net.rs769
-rw-r--r--src/libstd/sys/redox/ext/process.rs10
-rw-r--r--src/libstd/sys/redox/ext/thread.rs6
-rw-r--r--src/libstd/sys/redox/fd.rs5
-rw-r--r--src/libstd/sys/redox/net/mod.rs4
-rw-r--r--src/libstd/sys/redox/net/netc.rs2
-rw-r--r--src/libstd/sys/redox/net/tcp.rs10
-rw-r--r--src/libstd/sys/redox/net/udp.rs12
-rw-r--r--src/libstd/sys/redox/os.rs3
-rw-r--r--src/libstd/sys/redox/os_str.rs7
-rw-r--r--src/libstd/sys/redox/process.rs28
-rw-r--r--src/libstd/sys/redox/stdio.rs4
-rw-r--r--src/libstd/sys/redox/syscall/error.rs4
-rw-r--r--src/libstd/sys/redox/thread.rs10
-rw-r--r--src/libstd/sys/redox/time.rs2
-rw-r--r--src/libstd/sys/unix/args.rs19
-rw-r--r--src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs1
-rw-r--r--src/libstd/sys/unix/backtrace/tracing/gcc_s.rs17
-rw-r--r--src/libstd/sys/unix/condvar.rs13
-rw-r--r--src/libstd/sys/unix/env.rs11
-rw-r--r--src/libstd/sys/unix/ext/ffi.rs8
-rw-r--r--src/libstd/sys/unix/ext/fs.rs498
-rw-r--r--src/libstd/sys/unix/ext/mod.rs1
-rw-r--r--src/libstd/sys/unix/ext/net.rs137
-rw-r--r--src/libstd/sys/unix/ext/process.rs10
-rw-r--r--src/libstd/sys/unix/ext/thread.rs4
-rw-r--r--src/libstd/sys/unix/fast_thread_local.rs7
-rw-r--r--src/libstd/sys/unix/fd.rs25
-rw-r--r--src/libstd/sys/unix/fs.rs217
-rw-r--r--src/libstd/sys/unix/l4re.rs4
-rw-r--r--src/libstd/sys/unix/mod.rs5
-rw-r--r--src/libstd/sys/unix/mutex.rs9
-rw-r--r--src/libstd/sys/unix/net.rs45
-rw-r--r--src/libstd/sys/unix/os.rs69
-rw-r--r--src/libstd/sys/unix/os_str.rs7
-rw-r--r--src/libstd/sys/unix/pipe.rs37
-rw-r--r--src/libstd/sys/unix/process/mod.rs2
-rw-r--r--src/libstd/sys/unix/process/process_common.rs41
-rw-r--r--src/libstd/sys/unix/process/process_fuchsia.rs75
-rw-r--r--src/libstd/sys/unix/process/process_unix.rs118
-rw-r--r--src/libstd/sys/unix/process/zircon.rs85
-rw-r--r--src/libstd/sys/unix/rand.rs29
-rw-r--r--src/libstd/sys/unix/stack_overflow.rs9
-rw-r--r--src/libstd/sys/unix/stdio.rs4
-rw-r--r--src/libstd/sys/unix/thread.rs169
-rw-r--r--src/libstd/sys/unix/time.rs6
-rw-r--r--src/libstd/sys/wasm/args.rs38
-rw-r--r--src/libstd/sys/wasm/mod.rs233
-rw-r--r--src/libstd/sys/wasm/os.rs40
-rw-r--r--src/libstd/sys/wasm/os_str.rs7
-rw-r--r--src/libstd/sys/wasm/process.rs12
-rw-r--r--src/libstd/sys/wasm/rwlock.rs4
-rw-r--r--src/libstd/sys/wasm/stdio.rs39
-rw-r--r--src/libstd/sys/wasm/thread.rs10
-rw-r--r--src/libstd/sys/wasm/time.rs44
-rw-r--r--src/libstd/sys/windows/backtrace/mod.rs298
-rw-r--r--src/libstd/sys/windows/backtrace/printing/mod.rs14
-rw-r--r--src/libstd/sys/windows/backtrace/printing/msvc.rs198
-rw-r--r--src/libstd/sys/windows/c.rs84
-rw-r--r--src/libstd/sys/windows/ext/ffi.rs11
-rw-r--r--src/libstd/sys/windows/ext/fs.rs128
-rw-r--r--src/libstd/sys/windows/ext/mod.rs1
-rw-r--r--src/libstd/sys/windows/ext/process.rs8
-rw-r--r--src/libstd/sys/windows/fs.rs47
-rw-r--r--src/libstd/sys/windows/mod.rs10
-rw-r--r--src/libstd/sys/windows/mutex.rs2
-rw-r--r--src/libstd/sys/windows/os_str.rs5
-rw-r--r--src/libstd/sys/windows/pipe.rs2
-rw-r--r--src/libstd/sys/windows/process.rs26
-rw-r--r--src/libstd/sys/windows/stdio.rs4
-rw-r--r--src/libstd/sys/windows/thread.rs13
82 files changed, 3034 insertions, 984 deletions
diff --git a/src/libstd/sys/cloudabi/abi/cloudabi.rs b/src/libstd/sys/cloudabi/abi/cloudabi.rs
index 2909db5098e..cd9a5ad448f 100644
--- a/src/libstd/sys/cloudabi/abi/cloudabi.rs
+++ b/src/libstd/sys/cloudabi/abi/cloudabi.rs
@@ -121,6 +121,7 @@ include!("bitflags.rs");
 /// File or memory access pattern advisory information.
 #[repr(u8)]
 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
 pub enum advice {
   /// The application expects that it will not access the
   /// specified data in the near future.
@@ -140,12 +141,12 @@ pub enum advice {
   /// 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)]
+#[non_exhaustive]
 pub enum auxtype {
   /// Base address of the binary argument data provided to
   /// [`proc_exec()`](fn.proc_exec.html).
@@ -210,12 +211,12 @@ pub enum auxtype {
   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)]
+#[non_exhaustive]
 pub enum clockid {
   /// The system-wide monotonic clock, which is defined as a
   /// clock measuring real time, whose value cannot be
@@ -232,7 +233,6 @@ pub enum clockid {
   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.
@@ -267,6 +267,7 @@ pub const DIRCOOKIE_START: dircookie = dircookie(0);
 /// exclusively or merely provided for alignment with POSIX.
 #[repr(u16)]
 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
 pub enum errno {
   /// No error occurred. System call completed successfully.
   SUCCESS        =  0,
@@ -422,7 +423,6 @@ pub enum errno {
   XDEV           = 75,
   /// Extension: Capabilities insufficient.
   NOTCAPABLE     = 76,
-  #[doc(hidden)] _NonExhaustive = -1 as isize as u16,
 }
 
 bitflags! {
@@ -438,6 +438,7 @@ bitflags! {
 /// Type of a subscription to an event or its occurrence.
 #[repr(u8)]
 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
 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).
@@ -463,7 +464,6 @@ pub enum eventtype {
   /// 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.
@@ -530,6 +530,7 @@ pub type filesize = u64;
 /// The type of a file descriptor or file.
 #[repr(u8)]
 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
 pub enum filetype {
   /// The type of the file descriptor or file is unknown or
   /// is different from any of the other types specified.
@@ -558,7 +559,6 @@ pub enum filetype {
   SOCKET_STREAM    = 130,
   /// The file refers to a symbolic link inode.
   SYMBOLIC_LINK    = 144,
-  #[doc(hidden)] _NonExhaustive = -1 as isize as u8,
 }
 
 bitflags! {
@@ -847,12 +847,12 @@ bitflags! {
 /// memory.
 #[repr(u8)]
 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
 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! {
@@ -878,6 +878,7 @@ bitflags! {
 /// Signal condition.
 #[repr(u8)]
 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
 pub enum signal {
   /// Process abort signal.
   ///
@@ -983,7 +984,6 @@ pub enum signal {
   ///
   /// Action: Terminates the process.
   XFSZ   = 26,
-  #[doc(hidden)] _NonExhaustive = -1 as isize as u8,
 }
 
 bitflags! {
@@ -1049,6 +1049,7 @@ pub type userdata = u64;
 /// should be set.
 #[repr(u8)]
 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
 pub enum whence {
   /// Seek relative to current position.
   CUR = 1,
@@ -1056,7 +1057,6 @@ pub enum whence {
   END = 2,
   /// Seek relative to start-of-file.
   SET = 3,
-  #[doc(hidden)] _NonExhaustive = -1 as isize as u8,
 }
 
 /// Auxiliary vector entry.
diff --git a/src/libstd/sys/cloudabi/backtrace.rs b/src/libstd/sys/cloudabi/backtrace.rs
index 33d93179237..2c43b5937ce 100644
--- a/src/libstd/sys/cloudabi/backtrace.rs
+++ b/src/libstd/sys/cloudabi/backtrace.rs
@@ -64,6 +64,10 @@ extern "C" fn trace_fn(
     arg: *mut libc::c_void,
 ) -> uw::_Unwind_Reason_Code {
     let cx = unsafe { &mut *(arg as *mut Context) };
+    if cx.idx >= cx.frames.len() {
+        return uw::_URC_NORMAL_STOP;
+    }
+
     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 {
@@ -73,13 +77,12 @@ extern "C" fn trace_fn(
     }
 
     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;
-    }
+    cx.frames[cx.idx] = Frame {
+        symbol_addr: symaddr as *mut u8,
+        exact_position: ip as *mut u8,
+        inline_context: 0,
+    };
+    cx.idx += 1;
 
     uw::_URC_NO_REASON
 }
diff --git a/src/libstd/sys/cloudabi/shims/process.rs b/src/libstd/sys/cloudabi/shims/process.rs
index 52e8c82e2b2..fcd40c15c17 100644
--- a/src/libstd/sys/cloudabi/shims/process.rs
+++ b/src/libstd/sys/cloudabi/shims/process.rs
@@ -126,6 +126,18 @@ impl fmt::Display for ExitStatus {
     }
 }
 
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(bool);
+
+impl ExitCode {
+    pub const SUCCESS: ExitCode = ExitCode(false);
+    pub const FAILURE: ExitCode = ExitCode(true);
+
+    pub fn as_i32(&self) -> i32 {
+        self.0 as i32
+    }
+}
+
 pub struct Process(Void);
 
 impl Process {
diff --git a/src/libstd/sys/cloudabi/stdio.rs b/src/libstd/sys/cloudabi/stdio.rs
index 9519a926471..1d7344f921c 100644
--- a/src/libstd/sys/cloudabi/stdio.rs
+++ b/src/libstd/sys/cloudabi/stdio.rs
@@ -77,3 +77,7 @@ pub fn is_ebadf(err: &io::Error) -> bool {
 }
 
 pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
+
+pub fn stderr_prints_nothing() -> bool {
+    false
+}
diff --git a/src/libstd/sys/cloudabi/thread.rs b/src/libstd/sys/cloudabi/thread.rs
index c980ae75261..8cca47efd22 100644
--- a/src/libstd/sys/cloudabi/thread.rs
+++ b/src/libstd/sys/cloudabi/thread.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use alloc::boxed::FnBox;
+use boxed::FnBox;
 use cmp;
 use ffi::CStr;
 use io;
@@ -32,7 +32,7 @@ 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> {
+    pub unsafe fn new<'a>(stack: usize, p: Box<dyn 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();
@@ -111,12 +111,14 @@ impl Drop for Thread {
 
 #[cfg_attr(test, allow(dead_code))]
 pub mod guard {
-    pub unsafe fn current() -> Option<usize> {
+    pub type Guard = !;
+    pub unsafe fn current() -> Option<Guard> {
         None
     }
-    pub unsafe fn init() -> Option<usize> {
+    pub unsafe fn init() -> Option<Guard> {
         None
     }
+    pub unsafe fn deinit() {}
 }
 
 fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs
index 1231898ed7e..c44db3b1072 100644
--- a/src/libstd/sys/mod.rs
+++ b/src/libstd/sys/mod.rs
@@ -67,6 +67,7 @@ cfg_if! {
         // (missing things in `libc` which is empty) so just omit everything
         // with an empty module
         #[unstable(issue = "0", feature = "std_internals")]
+        #[allow(missing_docs)]
         pub mod unix_ext {}
     } else {
         // On other platforms like Windows document the bare bones of unix
@@ -80,11 +81,13 @@ cfg_if! {
 cfg_if! {
     if #[cfg(windows)] {
         // On windows we'll just be documenting what's already available
+        #[allow(missing_docs)]
         pub use self::ext as windows_ext;
     } 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")]
+        #[allow(missing_docs)]
         pub mod windows_ext {}
     } else {
         // On all other platforms (aka linux/osx/etc) then pull in a "minimal"
diff --git a/src/libstd/sys/redox/args.rs b/src/libstd/sys/redox/args.rs
index 59ae2a74a6d..556ed77372e 100644
--- a/src/libstd/sys/redox/args.rs
+++ b/src/libstd/sys/redox/args.rs
@@ -73,17 +73,15 @@ mod imp {
             CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
         }).collect();
 
-        LOCK.lock();
+        let _guard = LOCK.lock();
         let ptr = get_global_ptr();
         assert!((*ptr).is_none());
         (*ptr) = Some(box args);
-        LOCK.unlock();
     }
 
     pub unsafe fn cleanup() {
-        LOCK.lock();
+        let _guard = LOCK.lock();
         *get_global_ptr() = None;
-        LOCK.unlock();
     }
 
     pub fn args() -> Args {
@@ -96,16 +94,14 @@ mod imp {
 
     fn clone() -> Option<Vec<Vec<u8>>> {
         unsafe {
-            LOCK.lock();
+            let _guard = LOCK.lock();
             let ptr = get_global_ptr();
-            let ret = (*ptr).as_ref().map(|s| (**s).clone());
-            LOCK.unlock();
-            return ret
+            (*ptr).as_ref().map(|s| (**s).clone())
         }
     }
 
-    fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
-        unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
+    unsafe fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
+        mem::transmute(&GLOBAL_ARGS_PTR)
     }
 
 }
diff --git a/src/libstd/sys/redox/backtrace/tracing.rs b/src/libstd/sys/redox/backtrace/tracing.rs
index 0a174b3c3f5..c0414b78f8d 100644
--- a/src/libstd/sys/redox/backtrace/tracing.rs
+++ b/src/libstd/sys/redox/backtrace/tracing.rs
@@ -68,6 +68,10 @@ pub fn unwind_backtrace(frames: &mut [Frame])
 extern 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) };
+    if cx.idx >= cx.frames.len() {
+        return uw::_URC_NORMAL_STOP;
+    }
+
     let mut ip_before_insn = 0;
     let mut ip = unsafe {
         uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
@@ -94,13 +98,12 @@ extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
         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;
-    }
+    cx.frames[cx.idx] = Frame {
+        symbol_addr: symaddr as *mut u8,
+        exact_position: ip as *mut u8,
+        inline_context: 0,
+    };
+    cx.idx += 1;
 
     uw::_URC_NO_REASON
 }
diff --git a/src/libstd/sys/redox/ext/ffi.rs b/src/libstd/sys/redox/ext/ffi.rs
index d59b4fc0b70..cd88c8f46b3 100644
--- a/src/libstd/sys/redox/ext/ffi.rs
+++ b/src/libstd/sys/redox/ext/ffi.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Unix-specific extension to the primitives in the `std::ffi` module
+//! Redox-specific extension to the primitives in the `std::ffi` module.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -17,7 +17,9 @@ use mem;
 use sys::os_str::Buf;
 use sys_common::{FromInner, IntoInner, AsInner};
 
-/// Unix-specific extensions to `OsString`.
+/// Redox-specific extensions to [`OsString`].
+///
+/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait OsStringExt {
     /// Creates an `OsString` from a byte vector.
@@ -39,7 +41,9 @@ impl OsStringExt for OsString {
     }
 }
 
-/// Unix-specific extensions to `OsStr`.
+/// Redox-specific extensions to [`OsStr`].
+///
+/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait OsStrExt {
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/sys/redox/ext/fs.rs b/src/libstd/sys/redox/ext/fs.rs
index 5d4edc2cf92..c1dba6edda4 100644
--- a/src/libstd/sys/redox/ext/fs.rs
+++ b/src/libstd/sys/redox/ext/fs.rs
@@ -18,7 +18,9 @@ use path::Path;
 use sys;
 use sys_common::{FromInner, AsInner, AsInnerMut};
 
-/// Redox-specific extensions to `Permissions`
+/// Redox-specific extensions to [`fs::Permissions`].
+///
+/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
 #[stable(feature = "fs_ext", since = "1.1.0")]
 pub trait PermissionsExt {
     /// Returns the underlying raw `mode_t` bits that are the standard Redox
@@ -30,13 +32,14 @@ pub trait PermissionsExt {
     /// use std::fs::File;
     /// use std::os::redox::fs::PermissionsExt;
     ///
-    /// # fn run() -> std::io::Result<()> {
-    /// let f = File::create("foo.txt")?;
-    /// let metadata = f.metadata()?;
-    /// let permissions = metadata.permissions();
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::create("foo.txt")?;
+    ///     let metadata = f.metadata()?;
+    ///     let permissions = metadata.permissions();
     ///
-    /// println!("permissions: {}", permissions.mode());
-    /// # Ok(()) }
+    ///     println!("permissions: {}", permissions.mode());
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "fs_ext", since = "1.1.0")]
     fn mode(&self) -> u32;
@@ -49,14 +52,15 @@ pub trait PermissionsExt {
     /// use std::fs::File;
     /// use std::os::redox::fs::PermissionsExt;
     ///
-    /// # fn run() -> std::io::Result<()> {
-    /// let f = File::create("foo.txt")?;
-    /// let metadata = f.metadata()?;
-    /// let mut permissions = metadata.permissions();
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::create("foo.txt")?;
+    ///     let metadata = f.metadata()?;
+    ///     let mut permissions = metadata.permissions();
     ///
-    /// permissions.set_mode(0o644); // Read/write for owner and read for others.
-    /// assert_eq!(permissions.mode(), 0o644);
-    /// # Ok(()) }
+    ///     permissions.set_mode(0o644); // Read/write for owner and read for others.
+    ///     assert_eq!(permissions.mode(), 0o644);
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "fs_ext", since = "1.1.0")]
     fn set_mode(&mut self, mode: u32);
@@ -93,7 +97,9 @@ impl PermissionsExt for Permissions {
     }
 }
 
-/// Redox-specific extensions to `OpenOptions`
+/// Redox-specific extensions to [`fs::OpenOptions`].
+///
+/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
 #[stable(feature = "fs_ext", since = "1.1.0")]
 pub trait OpenOptionsExt {
     /// Sets the mode bits that a new file will be created with.
@@ -161,13 +167,9 @@ impl OpenOptionsExt for OpenOptions {
     }
 }
 
-// Hm, why are there casts here to the returned type, shouldn't the types always
-// be the same? Right you are! Turns out, however, on android at least the types
-// in the raw `stat` structure are not the same as the types being returned. Who
-// knew!
-//
-// As a result to make sure this compiles for all platforms we do the manual
-// casts and rely on manual lowering to `stat` if the raw type is desired.
+/// Redox-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
 #[stable(feature = "metadata_ext", since = "1.1.0")]
 pub trait MetadataExt {
     #[stable(feature = "metadata_ext", since = "1.1.0")]
@@ -202,6 +204,13 @@ pub trait MetadataExt {
     fn blocks(&self) -> u64;
 }
 
+// Hm, why are there casts here to the returned type, shouldn't the types always
+// be the same? Right you are! Turns out, however, on android at least the types
+// in the raw `stat` structure are not the same as the types being returned. Who
+// knew!
+//
+// As a result to make sure this compiles for all platforms we do the manual
+// casts and rely on manual lowering to `stat` if the raw type is desired.
 #[stable(feature = "metadata_ext", since = "1.1.0")]
 impl MetadataExt for fs::Metadata {
     fn dev(&self) -> u64 {
@@ -251,7 +260,12 @@ impl MetadataExt for fs::Metadata {
     }
 }
 
-/// Add special Redox types (block/char device, fifo and socket)
+/// Redox-specific extensions for [`FileType`].
+///
+/// Adds support for special Unix file types such as block/character devices,
+/// pipes, and sockets.
+///
+/// [`FileType`]: ../../../../std/fs/struct.FileType.html
 #[stable(feature = "file_type_ext", since = "1.5.0")]
 pub trait FileTypeExt {
     /// Returns whether this file type is a block device.
@@ -291,13 +305,13 @@ impl FileTypeExt for fs::FileType {
 ///
 /// # Examples
 ///
-/// ```
+/// ```no_run
 /// use std::os::redox::fs;
 ///
-/// # fn foo() -> std::io::Result<()> {
-/// fs::symlink("a.txt", "b.txt")?;
-/// # Ok(())
-/// # }
+/// fn main() -> std::io::Result<()> {
+///     fs::symlink("a.txt", "b.txt")?;
+///     Ok(())
+/// }
 /// ```
 #[stable(feature = "symlink", since = "1.1.0")]
 pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
@@ -305,8 +319,10 @@ pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
     sys::fs::symlink(src.as_ref(), dst.as_ref())
 }
 
+/// Redox-specific extensions to [`fs::DirBuilder`].
+///
+/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
 #[stable(feature = "dir_builder", since = "1.6.0")]
-/// An extension trait for `fs::DirBuilder` for Redox-specific options.
 pub trait DirBuilderExt {
     /// Sets the mode to create new directories with. This option defaults to
     /// 0o777.
diff --git a/src/libstd/sys/redox/ext/mod.rs b/src/libstd/sys/redox/ext/mod.rs
index 9fd8d6c9186..cb2c75ae0bf 100644
--- a/src/libstd/sys/redox/ext/mod.rs
+++ b/src/libstd/sys/redox/ext/mod.rs
@@ -33,6 +33,7 @@
 pub mod ffi;
 pub mod fs;
 pub mod io;
+pub mod net;
 pub mod process;
 pub mod thread;
 
diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs
new file mode 100644
index 00000000000..2ab77703242
--- /dev/null
+++ b/src/libstd/sys/redox/ext/net.rs
@@ -0,0 +1,769 @@
+// 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.
+
+#![stable(feature = "unix_socket_redox", since = "1.29")]
+
+//! Unix-specific networking functionality
+
+use fmt;
+use io::{self, Error, ErrorKind, Initializer};
+use net::Shutdown;
+use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
+use path::Path;
+use time::Duration;
+use sys::{cvt, fd::FileDesc, syscall};
+
+/// An address associated with a Unix socket.
+///
+/// # Examples
+///
+/// ```
+/// use std::os::unix::net::UnixListener;
+///
+/// let socket = match UnixListener::bind("/tmp/sock") {
+///     Ok(sock) => sock,
+///     Err(e) => {
+///         println!("Couldn't bind: {:?}", e);
+///         return
+///     }
+/// };
+/// let addr = socket.local_addr().expect("Couldn't get local address");
+/// ```
+#[derive(Clone)]
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+pub struct SocketAddr(());
+
+impl SocketAddr {
+    /// Returns the contents of this address if it is a `pathname` address.
+    ///
+    /// # Examples
+    ///
+    /// With a pathname:
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    /// use std::path::Path;
+    ///
+    /// let socket = UnixListener::bind("/tmp/sock").unwrap();
+    /// let addr = socket.local_addr().expect("Couldn't get local address");
+    /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
+    /// ```
+    ///
+    /// Without a pathname:
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let socket = UnixDatagram::unbound().unwrap();
+    /// let addr = socket.local_addr().expect("Couldn't get local address");
+    /// assert_eq!(addr.as_pathname(), None);
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn as_pathname(&self) -> Option<&Path> {
+        None
+    }
+
+    /// Returns true if and only if the address is unnamed.
+    ///
+    /// # Examples
+    ///
+    /// A named address:
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let socket = UnixListener::bind("/tmp/sock").unwrap();
+    /// let addr = socket.local_addr().expect("Couldn't get local address");
+    /// assert_eq!(addr.is_unnamed(), false);
+    /// ```
+    ///
+    /// An unnamed address:
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let socket = UnixDatagram::unbound().unwrap();
+    /// let addr = socket.local_addr().expect("Couldn't get local address");
+    /// assert_eq!(addr.is_unnamed(), true);
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn is_unnamed(&self) -> bool {
+        false
+    }
+}
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl fmt::Debug for SocketAddr {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(fmt, "SocketAddr")
+    }
+}
+
+/// A Unix stream socket.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::net::UnixStream;
+/// use std::io::prelude::*;
+///
+/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap();
+/// stream.write_all(b"hello world").unwrap();
+/// let mut response = String::new();
+/// stream.read_to_string(&mut response).unwrap();
+/// println!("{}", response);
+/// ```
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+pub struct UnixStream(FileDesc);
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl fmt::Debug for UnixStream {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        let mut builder = fmt.debug_struct("UnixStream");
+        builder.field("fd", &self.0.raw());
+        if let Ok(addr) = self.local_addr() {
+            builder.field("local", &addr);
+        }
+        if let Ok(addr) = self.peer_addr() {
+            builder.field("peer", &addr);
+        }
+        builder.finish()
+    }
+}
+
+impl UnixStream {
+    /// Connects to the socket named by `path`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = match UnixStream::connect("/tmp/sock") {
+    ///     Ok(sock) => sock,
+    ///     Err(e) => {
+    ///         println!("Couldn't connect: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
+        if let Some(s) = path.as_ref().to_str() {
+            cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC))
+                .map(FileDesc::new)
+                .map(UnixStream)
+        } else {
+            Err(Error::new(
+                ErrorKind::Other,
+                "UnixStream::connect: non-utf8 paths not supported on redox"
+            ))
+        }
+    }
+
+    /// Creates an unnamed pair of connected sockets.
+    ///
+    /// Returns two `UnixStream`s which are connected to each other.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let (sock1, sock2) = match UnixStream::pair() {
+    ///     Ok((sock1, sock2)) => (sock1, sock2),
+    ///     Err(e) => {
+    ///         println!("Couldn't create a pair of sockets: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
+        let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC))
+            .map(FileDesc::new)?;
+        let client = server.duplicate_path(b"connect")?;
+        let stream = server.duplicate_path(b"listen")?;
+        Ok((UnixStream(client), UnixStream(stream)))
+    }
+
+    /// Creates a new independently owned handle to the underlying socket.
+    ///
+    /// The returned `UnixStream` is a reference to the same stream that this
+    /// object references. Both handles will read and write the same stream of
+    /// data, and options set on one stream will be propagated to the other
+    /// stream.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// let sock_copy = socket.try_clone().expect("Couldn't clone socket");
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn try_clone(&self) -> io::Result<UnixStream> {
+        self.0.duplicate().map(UnixStream)
+    }
+
+    /// Returns the socket address of the local half of this connection.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// let addr = socket.local_addr().expect("Couldn't get local address");
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn local_addr(&self) -> io::Result<SocketAddr> {
+        Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox"))
+    }
+
+    /// Returns the socket address of the remote half of this connection.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// let addr = socket.peer_addr().expect("Couldn't get peer address");
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox"))
+    }
+
+    /// Sets the read timeout for the socket.
+    ///
+    /// If the provided value is [`None`], then [`read`] calls will block
+    /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method.
+    ///
+    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+    /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
+    /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read
+    /// [`Duration`]: ../../../../std/time/struct.Duration.html
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+    /// ```
+    ///
+    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method:
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+    /// let err = result.unwrap_err();
+    /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn set_read_timeout(&self, _timeout: Option<Duration>) -> io::Result<()> {
+        Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox"))
+    }
+
+    /// Sets the write timeout for the socket.
+    ///
+    /// If the provided value is [`None`], then [`write`] calls will block
+    /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is
+    /// passed to this method.
+    ///
+    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+    /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
+    /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write
+    /// [`Duration`]: ../../../../std/time/struct.Duration.html
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
+    /// ```
+    ///
+    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method:
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::net::UdpSocket;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap();
+    /// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+    /// let err = result.unwrap_err();
+    /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn set_write_timeout(&self, _timeout: Option<Duration>) -> io::Result<()> {
+        Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox"))
+    }
+
+    /// Returns the read timeout of this socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+    /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0)));
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox"))
+    }
+
+    /// Returns the write timeout of this socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
+    /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0)));
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox"))
+    }
+
+    /// Moves the socket into or out of nonblocking mode.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.set_nonblocking(true).expect("Couldn't set nonblocking");
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        self.0.set_nonblocking(nonblocking)
+    }
+
+    /// Returns the value of the `SO_ERROR` option.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// if let Ok(Some(err)) = socket.take_error() {
+    ///     println!("Got error: {:?}", err);
+    /// }
+    /// ```
+    ///
+    /// # Platform specific
+    /// On Redox this always returns None.
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        Ok(None)
+    }
+
+    /// Shuts down the read, write, or both halves of this connection.
+    ///
+    /// This function will cause all pending and future I/O calls on the
+    /// specified portions to immediately return with an appropriate value
+    /// (see the documentation of [`Shutdown`]).
+    ///
+    /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::net::Shutdown;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.shutdown(Shutdown::Both).expect("shutdown function failed");
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> {
+        Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox"))
+    }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl io::Read for UnixStream {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        io::Read::read(&mut &*self, buf)
+    }
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
+    }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl<'a> io::Read for &'a UnixStream {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.read(buf)
+    }
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
+    }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl io::Write for UnixStream {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        io::Write::write(&mut &*self, buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        io::Write::flush(&mut &*self)
+    }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl<'a> io::Write for &'a UnixStream {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl AsRawFd for UnixStream {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.raw()
+    }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl FromRawFd for UnixStream {
+    unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
+        UnixStream(FileDesc::new(fd))
+    }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl IntoRawFd for UnixStream {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw()
+    }
+}
+
+/// A structure representing a Unix domain socket server.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+/// use std::os::unix::net::{UnixStream, UnixListener};
+///
+/// fn handle_client(stream: UnixStream) {
+///     // ...
+/// }
+///
+/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+///
+/// // accept connections and process them, spawning a new thread for each one
+/// for stream in listener.incoming() {
+///     match stream {
+///         Ok(stream) => {
+///             /* connection succeeded */
+///             thread::spawn(|| handle_client(stream));
+///         }
+///         Err(err) => {
+///             /* connection failed */
+///             break;
+///         }
+///     }
+/// }
+/// ```
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+pub struct UnixListener(FileDesc);
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl fmt::Debug for UnixListener {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        let mut builder = fmt.debug_struct("UnixListener");
+        builder.field("fd", &self.0.raw());
+        if let Ok(addr) = self.local_addr() {
+            builder.field("local", &addr);
+        }
+        builder.finish()
+    }
+}
+
+impl UnixListener {
+    /// Creates a new `UnixListener` bound to the specified socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = match UnixListener::bind("/path/to/the/socket") {
+    ///     Ok(sock) => sock,
+    ///     Err(e) => {
+    ///         println!("Couldn't connect: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
+        if let Some(s) = path.as_ref().to_str() {
+            cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC))
+                .map(FileDesc::new)
+                .map(UnixListener)
+        } else {
+            Err(Error::new(
+                ErrorKind::Other,
+                "UnixListener::bind: non-utf8 paths not supported on redox"
+            ))
+        }
+    }
+
+    /// Accepts a new incoming connection to this listener.
+    ///
+    /// This function will block the calling thread until a new Unix connection
+    /// is established. When established, the corresponding [`UnixStream`] and
+    /// the remote peer's address will be returned.
+    ///
+    /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+    ///
+    /// match listener.accept() {
+    ///     Ok((socket, addr)) => println!("Got a client: {:?}", addr),
+    ///     Err(e) => println!("accept function failed: {:?}", e),
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
+        self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(())))
+    }
+
+    /// Creates a new independently owned handle to the underlying socket.
+    ///
+    /// The returned `UnixListener` is a reference to the same socket that this
+    /// object references. Both handles can be used to accept incoming
+    /// connections and options set on one listener will affect the other.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+    ///
+    /// let listener_copy = listener.try_clone().expect("try_clone failed");
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn try_clone(&self) -> io::Result<UnixListener> {
+        self.0.duplicate().map(UnixListener)
+    }
+
+    /// Returns the local socket address of this listener.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+    ///
+    /// let addr = listener.local_addr().expect("Couldn't get local address");
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn local_addr(&self) -> io::Result<SocketAddr> {
+        Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox"))
+    }
+
+    /// Moves the socket into or out of nonblocking mode.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+    ///
+    /// listener.set_nonblocking(true).expect("Couldn't set non blocking");
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        self.0.set_nonblocking(nonblocking)
+    }
+
+    /// Returns the value of the `SO_ERROR` option.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = UnixListener::bind("/tmp/sock").unwrap();
+    ///
+    /// if let Ok(Some(err)) = listener.take_error() {
+    ///     println!("Got error: {:?}", err);
+    /// }
+    /// ```
+    ///
+    /// # Platform specific
+    /// On Redox this always returns None.
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        Ok(None)
+    }
+
+    /// Returns an iterator over incoming connections.
+    ///
+    /// The iterator will never return [`None`] and will also not yield the
+    /// peer's [`SocketAddr`] structure.
+    ///
+    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+    /// [`SocketAddr`]: struct.SocketAddr.html
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::thread;
+    /// use std::os::unix::net::{UnixStream, UnixListener};
+    ///
+    /// fn handle_client(stream: UnixStream) {
+    ///     // ...
+    /// }
+    ///
+    /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+    ///
+    /// for stream in listener.incoming() {
+    ///     match stream {
+    ///         Ok(stream) => {
+    ///             thread::spawn(|| handle_client(stream));
+    ///         }
+    ///         Err(err) => {
+    ///             break;
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket_redox", since = "1.29")]
+    pub fn incoming<'a>(&'a self) -> Incoming<'a> {
+        Incoming { listener: self }
+    }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl AsRawFd for UnixListener {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.raw()
+    }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl FromRawFd for UnixListener {
+    unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
+        UnixListener(FileDesc::new(fd))
+    }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl IntoRawFd for UnixListener {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw()
+    }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl<'a> IntoIterator for &'a UnixListener {
+    type Item = io::Result<UnixStream>;
+    type IntoIter = Incoming<'a>;
+
+    fn into_iter(self) -> Incoming<'a> {
+        self.incoming()
+    }
+}
+
+/// An iterator over incoming connections to a [`UnixListener`].
+///
+/// It will never return [`None`].
+///
+/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+/// [`UnixListener`]: struct.UnixListener.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+/// use std::os::unix::net::{UnixStream, UnixListener};
+///
+/// fn handle_client(stream: UnixStream) {
+///     // ...
+/// }
+///
+/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+///
+/// for stream in listener.incoming() {
+///     match stream {
+///         Ok(stream) => {
+///             thread::spawn(|| handle_client(stream));
+///         }
+///         Err(err) => {
+///             break;
+///         }
+///     }
+/// }
+/// ```
+#[derive(Debug)]
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+pub struct Incoming<'a> {
+    listener: &'a UnixListener,
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl<'a> Iterator for Incoming<'a> {
+    type Item = io::Result<UnixStream>;
+
+    fn next(&mut self) -> Option<io::Result<UnixStream>> {
+        Some(self.listener.accept().map(|s| s.0))
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (usize::max_value(), None)
+    }
+}
diff --git a/src/libstd/sys/redox/ext/process.rs b/src/libstd/sys/redox/ext/process.rs
index e68e180acf1..cfb6d5fc703 100644
--- a/src/libstd/sys/redox/ext/process.rs
+++ b/src/libstd/sys/redox/ext/process.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Unix-specific extensions to primitives in the `std::process` module.
+//! Redox-specific extensions to primitives in the `std::process` module.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -18,7 +18,9 @@ use process;
 use sys;
 use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};
 
-/// Unix-specific extensions to the `std::process::Command` builder
+/// Redox-specific extensions to the [`process::Command`] builder,
+///
+/// [`process::Command`]: ../../../../std/process/struct.Command.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait CommandExt {
     /// Sets the child process's user id. This translates to a
@@ -107,7 +109,9 @@ impl CommandExt for process::Command {
     }
 }
 
-/// Unix-specific extensions to `std::process::ExitStatus`
+/// Redox-specific extensions to [`process::ExitStatus`].
+///
+/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait ExitStatusExt {
     /// Creates a new `ExitStatus` from the raw underlying `i32` return value of
diff --git a/src/libstd/sys/redox/ext/thread.rs b/src/libstd/sys/redox/ext/thread.rs
index 52be2ccd9f9..71ff0d46b91 100644
--- a/src/libstd/sys/redox/ext/thread.rs
+++ b/src/libstd/sys/redox/ext/thread.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Unix-specific extensions to primitives in the `std::thread` module.
+//! Redox-specific extensions to primitives in the `std::thread` module.
 
 #![stable(feature = "thread_extensions", since = "1.9.0")]
 
@@ -19,7 +19,9 @@ use thread::JoinHandle;
 #[allow(deprecated)]
 pub type RawPthread = usize;
 
-/// Unix-specific extensions to `std::thread::JoinHandle`
+/// Redox-specific extensions to [`thread::JoinHandle`].
+///
+/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html
 #[stable(feature = "thread_extensions", since = "1.9.0")]
 pub trait JoinHandleExt {
     /// Extracts the raw pthread_t without taking ownership
diff --git a/src/libstd/sys/redox/fd.rs b/src/libstd/sys/redox/fd.rs
index ba7bbdc657f..e04e2791b23 100644
--- a/src/libstd/sys/redox/fd.rs
+++ b/src/libstd/sys/redox/fd.rs
@@ -47,7 +47,10 @@ impl FileDesc {
     }
 
     pub fn duplicate(&self) -> io::Result<FileDesc> {
-        let new_fd = cvt(syscall::dup(self.fd, &[]))?;
+        self.duplicate_path(&[])
+    }
+    pub fn duplicate_path(&self, path: &[u8]) -> io::Result<FileDesc> {
+        let new_fd = cvt(syscall::dup(self.fd, path))?;
         Ok(FileDesc::new(new_fd))
     }
 
diff --git a/src/libstd/sys/redox/net/mod.rs b/src/libstd/sys/redox/net/mod.rs
index 0291d7f0e92..67f22231d5f 100644
--- a/src/libstd/sys/redox/net/mod.rs
+++ b/src/libstd/sys/redox/net/mod.rs
@@ -41,12 +41,12 @@ impl Iterator for LookupHost {
 pub fn lookup_host(host: &str) -> Result<LookupHost> {
     let mut ip_string = String::new();
     File::open("/etc/net/ip")?.read_to_string(&mut ip_string)?;
-    let ip: Vec<u8> = ip_string.trim().split(".").map(|part| part.parse::<u8>()
+    let ip: Vec<u8> = ip_string.trim().split('.').map(|part| part.parse::<u8>()
                                .unwrap_or(0)).collect();
 
     let mut dns_string = String::new();
     File::open("/etc/net/dns")?.read_to_string(&mut dns_string)?;
-    let dns: Vec<u8> = dns_string.trim().split(".").map(|part| part.parse::<u8>()
+    let dns: Vec<u8> = dns_string.trim().split('.').map(|part| part.parse::<u8>()
                                  .unwrap_or(0)).collect();
 
     if ip.len() == 4 && dns.len() == 4 {
diff --git a/src/libstd/sys/redox/net/netc.rs b/src/libstd/sys/redox/net/netc.rs
index d443a4d68a1..b6d9f456295 100644
--- a/src/libstd/sys/redox/net/netc.rs
+++ b/src/libstd/sys/redox/net/netc.rs
@@ -24,10 +24,10 @@ pub struct in_addr {
 }
 
 #[derive(Copy, Clone)]
+#[repr(align(4))]
 #[repr(C)]
 pub struct in6_addr {
     pub s6_addr: [u8; 16],
-    __align: [u32; 0],
 }
 
 #[derive(Copy, Clone)]
diff --git a/src/libstd/sys/redox/net/tcp.rs b/src/libstd/sys/redox/net/tcp.rs
index 319965ab396..b5664908479 100644
--- a/src/libstd/sys/redox/net/tcp.rs
+++ b/src/libstd/sys/redox/net/tcp.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use cmp;
-use io::{Error, ErrorKind, Result};
+use io::{self, Error, ErrorKind, Result};
 use mem;
 use net::{SocketAddr, Shutdown};
 use path::Path;
@@ -130,6 +130,10 @@ impl TcpStream {
     pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
         let file = self.0.dup(b"read_timeout")?;
         if let Some(duration) = duration_option {
+            if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
+                return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                          "cannot set a 0 duration timeout"));
+            }
             file.write(&TimeSpec {
                 tv_sec: duration.as_secs() as i64,
                 tv_nsec: duration.subsec_nanos() as i32
@@ -143,6 +147,10 @@ impl TcpStream {
     pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
         let file = self.0.dup(b"write_timeout")?;
         if let Some(duration) = duration_option {
+            if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
+                return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                          "cannot set a 0 duration timeout"));
+            }
             file.write(&TimeSpec {
                 tv_sec: duration.as_secs() as i64,
                 tv_nsec: duration.subsec_nanos() as i32
diff --git a/src/libstd/sys/redox/net/udp.rs b/src/libstd/sys/redox/net/udp.rs
index 7e7666e7ef3..22af02079e7 100644
--- a/src/libstd/sys/redox/net/udp.rs
+++ b/src/libstd/sys/redox/net/udp.rs
@@ -10,7 +10,7 @@
 
 use cell::UnsafeCell;
 use cmp;
-use io::{Error, ErrorKind, Result};
+use io::{self, Error, ErrorKind, Result};
 use mem;
 use net::{SocketAddr, Ipv4Addr, Ipv6Addr};
 use path::Path;
@@ -58,7 +58,7 @@ impl UdpSocket {
 
     pub fn recv(&self, buf: &mut [u8]) -> Result<usize> {
         if let Some(addr) = *self.get_conn() {
-            let from = self.0.dup(format!("{}", addr).as_bytes())?;
+            let from = self.0.dup(addr.to_string().as_bytes())?;
             from.read(buf)
         } else {
             Err(Error::new(ErrorKind::Other, "UdpSocket::recv not connected"))
@@ -179,6 +179,10 @@ impl UdpSocket {
     pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
         let file = self.0.dup(b"read_timeout")?;
         if let Some(duration) = duration_option {
+            if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
+                return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                          "cannot set a 0 duration timeout"));
+            }
             file.write(&TimeSpec {
                 tv_sec: duration.as_secs() as i64,
                 tv_nsec: duration.subsec_nanos() as i32
@@ -192,6 +196,10 @@ impl UdpSocket {
     pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
         let file = self.0.dup(b"write_timeout")?;
         if let Some(duration) = duration_option {
+            if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
+                return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                          "cannot set a 0 duration timeout"));
+            }
             file.write(&TimeSpec {
                 tv_sec: duration.as_secs() as i64,
                 tv_nsec: duration.subsec_nanos() as i32
diff --git a/src/libstd/sys/redox/os.rs b/src/libstd/sys/redox/os.rs
index 480765b77a0..5822216779b 100644
--- a/src/libstd/sys/redox/os.rs
+++ b/src/libstd/sys/redox/os.rs
@@ -30,9 +30,6 @@ use sys_common::mutex::Mutex;
 use sys::{cvt, fd, syscall};
 use vec;
 
-const TMPBUF_SZ: usize = 128;
-static ENV_LOCK: Mutex = Mutex::new();
-
 extern {
     #[link_name = "__errno_location"]
     fn errno_location() -> *mut i32;
diff --git a/src/libstd/sys/redox/os_str.rs b/src/libstd/sys/redox/os_str.rs
index 655bfdb9167..eb3a1ead58c 100644
--- a/src/libstd/sys/redox/os_str.rs
+++ b/src/libstd/sys/redox/os_str.rs
@@ -19,7 +19,7 @@ use rc::Rc;
 use sync::Arc;
 use sys_common::{AsInner, IntoInner};
 use sys_common::bytestring::debug_fmt_bytestring;
-use std_unicode::lossy::Utf8Lossy;
+use core::str::lossy::Utf8Lossy;
 
 #[derive(Clone, Hash)]
 pub struct Buf {
@@ -104,6 +104,11 @@ impl Buf {
         self.inner.shrink_to_fit()
     }
 
+    #[inline]
+    pub fn shrink_to(&mut self, min_capacity: usize) {
+        self.inner.shrink_to(min_capacity)
+    }
+
     pub fn as_slice(&self) -> &Slice {
         unsafe { mem::transmute(&*self.inner) }
     }
diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs
index 3fd54973896..2037616e6ac 100644
--- a/src/libstd/sys/redox/process.rs
+++ b/src/libstd/sys/redox/process.rs
@@ -13,6 +13,8 @@ use ffi::OsStr;
 use os::unix::ffi::OsStrExt;
 use fmt;
 use io::{self, Error, ErrorKind};
+use iter;
+use libc::{EXIT_SUCCESS, EXIT_FAILURE};
 use path::{Path, PathBuf};
 use sys::fd::FileDesc;
 use sys::fs::{File, OpenOptions};
@@ -50,7 +52,7 @@ pub struct Command {
     uid: Option<u32>,
     gid: Option<u32>,
     saw_nul: bool,
-    closures: Vec<Box<FnMut() -> io::Result<()> + Send + Sync>>,
+    closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
     stdin: Option<Stdio>,
     stdout: Option<Stdio>,
     stderr: Option<Stdio>,
@@ -121,7 +123,7 @@ impl Command {
     }
 
     pub fn before_exec(&mut self,
-                       f: Box<FnMut() -> io::Result<()> + Send + Sync>) {
+                       f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>) {
         self.closures.push(f);
     }
 
@@ -295,11 +297,11 @@ impl Command {
             t!(callback());
         }
 
-        let mut args: Vec<[usize; 2]> = Vec::new();
-        args.push([self.program.as_ptr() as usize, self.program.len()]);
-        for arg in self.args.iter() {
-            args.push([arg.as_ptr() as usize, arg.len()]);
-        }
+        let args: Vec<[usize; 2]> = iter::once(
+            [self.program.as_ptr() as usize, self.program.len()]
+        ).chain(
+            self.args.iter().map(|arg| [arg.as_ptr() as usize, arg.len()])
+        ).collect();
 
         self.env.apply();
 
@@ -480,6 +482,18 @@ impl fmt::Display for ExitStatus {
     }
 }
 
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(u8);
+
+impl ExitCode {
+    pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
+    pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);
+
+    pub fn as_i32(&self) -> i32 {
+        self.0 as i32
+    }
+}
+
 /// The unique id of the process (this should never be negative).
 pub struct Process {
     pid: usize,
diff --git a/src/libstd/sys/redox/stdio.rs b/src/libstd/sys/redox/stdio.rs
index 3abb094ac34..7a4d11b0ecb 100644
--- a/src/libstd/sys/redox/stdio.rs
+++ b/src/libstd/sys/redox/stdio.rs
@@ -75,3 +75,7 @@ pub fn is_ebadf(err: &io::Error) -> bool {
 }
 
 pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
+
+pub fn stderr_prints_nothing() -> bool {
+    false
+}
diff --git a/src/libstd/sys/redox/syscall/error.rs b/src/libstd/sys/redox/syscall/error.rs
index d8d78d55016..1ef79547431 100644
--- a/src/libstd/sys/redox/syscall/error.rs
+++ b/src/libstd/sys/redox/syscall/error.rs
@@ -48,13 +48,13 @@ impl Error {
 }
 
 impl fmt::Debug for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.write_str(self.text())
     }
 }
 
 impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.write_str(self.text())
     }
 }
diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs
index c4aad8d86f8..f4177087d77 100644
--- a/src/libstd/sys/redox/thread.rs
+++ b/src/libstd/sys/redox/thread.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use alloc::boxed::FnBox;
+use boxed::FnBox;
 use ffi::CStr;
 use io;
 use mem;
@@ -28,7 +28,7 @@ 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> {
+    pub unsafe fn new<'a>(_stack: usize, p: Box<dyn FnBox() + 'a>) -> io::Result<Thread> {
         let p = box p;
 
         let id = cvt(syscall::clone(syscall::CLONE_VM | syscall::CLONE_FS | syscall::CLONE_FILES))?;
@@ -88,6 +88,8 @@ impl Thread {
 }
 
 pub mod guard {
-    pub unsafe fn current() -> Option<usize> { None }
-    pub unsafe fn init() -> Option<usize> { None }
+    pub type Guard = !;
+    pub unsafe fn current() -> Option<Guard> { None }
+    pub unsafe fn init() -> Option<Guard> { None }
+    pub unsafe fn deinit() {}
 }
diff --git a/src/libstd/sys/redox/time.rs b/src/libstd/sys/redox/time.rs
index cf798500b7f..5c491115c55 100644
--- a/src/libstd/sys/redox/time.rs
+++ b/src/libstd/sys/redox/time.rs
@@ -144,7 +144,7 @@ impl Instant {
 
     pub fn sub_instant(&self, other: &Instant) -> Duration {
         self.t.sub_timespec(&other.t).unwrap_or_else(|_| {
-            panic!("other was less than the current instant")
+            panic!("specified instant was later than self")
         })
     }
 
diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs
index e1c7ffc19e5..c3c033dfbc7 100644
--- a/src/libstd/sys/unix/args.rs
+++ b/src/libstd/sys/unix/args.rs
@@ -66,7 +66,8 @@ impl DoubleEndedIterator for Args {
           target_os = "emscripten",
           target_os = "haiku",
           target_os = "l4re",
-          target_os = "fuchsia"))]
+          target_os = "fuchsia",
+          target_os = "hermit"))]
 mod imp {
     use os::unix::prelude::*;
     use ptr;
@@ -79,20 +80,20 @@ mod imp {
 
     static mut ARGC: isize = 0;
     static mut ARGV: *const *const u8 = ptr::null();
+    // We never call `ENV_LOCK.init()`, so it is UB to attempt to
+    // acquire this mutex reentrantly!
     static LOCK: Mutex = Mutex::new();
 
     pub unsafe fn init(argc: isize, argv: *const *const u8) {
-        LOCK.lock();
+        let _guard = LOCK.lock();
         ARGC = argc;
         ARGV = argv;
-        LOCK.unlock();
     }
 
     pub unsafe fn cleanup() {
-        LOCK.lock();
+        let _guard = LOCK.lock();
         ARGC = 0;
         ARGV = ptr::null();
-        LOCK.unlock();
     }
 
     pub fn args() -> Args {
@@ -104,13 +105,11 @@ mod imp {
 
     fn clone() -> Vec<OsString> {
         unsafe {
-            LOCK.lock();
-            let ret = (0..ARGC).map(|i| {
+            let _guard = LOCK.lock();
+            (0..ARGC).map(|i| {
                 let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char);
                 OsStringExt::from_vec(cstr.to_bytes().to_vec())
-            }).collect();
-            LOCK.unlock();
-            return ret
+            }).collect()
         }
     }
 }
diff --git a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs
index 400d39cd4bd..6293eeb4ed6 100644
--- a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs
+++ b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs
@@ -38,6 +38,7 @@ pub fn unwind_backtrace(frames: &mut [Frame])
         *to = Frame {
             exact_position: *from as *mut u8,
             symbol_addr: *from as *mut u8,
+            inline_context: 0,
         };
     }
     Ok((nb_frames as usize, BacktraceContext))
diff --git a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs
index 000c08d2e0d..6e841568679 100644
--- a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs
+++ b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs
@@ -68,6 +68,10 @@ pub fn unwind_backtrace(frames: &mut [Frame])
 extern 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) };
+    if cx.idx >= cx.frames.len() {
+        return uw::_URC_NORMAL_STOP;
+    }
+
     let mut ip_before_insn = 0;
     let mut ip = unsafe {
         uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
@@ -94,13 +98,12 @@ extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
         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;
-    }
+    cx.frames[cx.idx] = Frame {
+        symbol_addr: symaddr as *mut u8,
+        exact_position: ip as *mut u8,
+        inline_context: 0,
+    };
+    cx.idx += 1;
 
     uw::_URC_NO_REASON
 }
diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs
index 4f878d8ad1f..2007da7b1f6 100644
--- a/src/libstd/sys/unix/condvar.rs
+++ b/src/libstd/sys/unix/condvar.rs
@@ -41,13 +41,15 @@ impl Condvar {
     #[cfg(any(target_os = "macos",
               target_os = "ios",
               target_os = "l4re",
-              target_os = "android"))]
+              target_os = "android",
+              target_os = "hermit"))]
     pub unsafe fn init(&mut self) {}
 
     #[cfg(not(any(target_os = "macos",
                   target_os = "ios",
                   target_os = "l4re",
-                  target_os = "android")))]
+                  target_os = "android",
+                  target_os = "hermit")))]
     pub unsafe fn init(&mut self) {
         use mem;
         let mut attr: libc::pthread_condattr_t = mem::uninitialized();
@@ -83,7 +85,10 @@ impl Condvar {
     // where we configure condition variable to use monotonic clock (instead of
     // default system clock). This approach avoids all problems that result
     // from changes made to the system time.
-    #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))]
+    #[cfg(not(any(target_os = "macos",
+                  target_os = "ios",
+                  target_os = "android",
+                  target_os = "hermit")))]
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
         use mem;
 
@@ -113,7 +118,7 @@ impl Condvar {
     // This implementation is modeled after libcxx's condition_variable
     // https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46
     // https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367
-    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))]
+    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android", target_os = "hermit"))]
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool {
         use ptr;
         use time::Instant;
diff --git a/src/libstd/sys/unix/env.rs b/src/libstd/sys/unix/env.rs
index 00cf7eca75d..ad116c57f55 100644
--- a/src/libstd/sys/unix/env.rs
+++ b/src/libstd/sys/unix/env.rs
@@ -172,3 +172,14 @@ pub mod os {
     pub const EXE_SUFFIX: &'static str = "";
     pub const EXE_EXTENSION: &'static str = "";
 }
+
+#[cfg(target_os = "hermit")]
+pub mod os {
+    pub const FAMILY: &'static str = "unix";
+    pub const OS: &'static str = "hermit";
+    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/unix/ext/ffi.rs b/src/libstd/sys/unix/ext/ffi.rs
index fb9984ccbdd..8347145db5a 100644
--- a/src/libstd/sys/unix/ext/ffi.rs
+++ b/src/libstd/sys/unix/ext/ffi.rs
@@ -17,7 +17,9 @@ use mem;
 use sys::os_str::Buf;
 use sys_common::{FromInner, IntoInner, AsInner};
 
-/// Unix-specific extensions to `OsString`.
+/// Unix-specific extensions to [`OsString`].
+///
+/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait OsStringExt {
     /// Creates an [`OsString`] from a byte vector.
@@ -66,7 +68,9 @@ impl OsStringExt for OsString {
     }
 }
 
-/// Unix-specific extensions to `OsStr`.
+/// Unix-specific extensions to [`OsStr`].
+///
+/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait OsStrExt {
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs
index 2e17fd58e0a..507e9d88171 100644
--- a/src/libstd/sys/unix/ext/fs.rs
+++ b/src/libstd/sys/unix/ext/fs.rs
@@ -41,24 +41,96 @@ pub trait FileExt {
     ///
     /// # Examples
     ///
-    /// ```
-    /// use std::os::unix::prelude::FileExt;
+    /// ```no_run
+    /// use std::io;
     /// use std::fs::File;
+    /// use std::os::unix::prelude::FileExt;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let mut buf = [0u8; 8];
-    /// let file = File::open("foo.txt")?;
+    /// fn main() -> io::Result<()> {
+    ///     let mut buf = [0u8; 8];
+    ///     let file = File::open("foo.txt")?;
     ///
-    /// // We now read 8 bytes from the offset 10.
-    /// let num_bytes_read = file.read_at(&mut buf, 10)?;
-    /// println!("read {} bytes: {:?}", num_bytes_read, buf);
-    /// # Ok(())
-    /// # }
+    ///     // We now read 8 bytes from the offset 10.
+    ///     let num_bytes_read = file.read_at(&mut buf, 10)?;
+    ///     println!("read {} bytes: {:?}", num_bytes_read, buf);
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "file_offset", since = "1.15.0")]
     fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
 
+    /// Reads the exact number of byte required to fill `buf` from the given offset.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`.
+    ///
+    /// [`Read::read_exact`]: ../../../../std/io/trait.Read.html#method.read_exact
+    /// [`read_at`]: #tymethod.read_at
+    ///
+    /// # Errors
+    ///
+    /// If this function encounters an error of the kind
+    /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
+    /// will continue.
+    ///
+    /// If this function encounters an "end of file" before completely filling
+    /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
+    /// The contents of `buf` are unspecified in this case.
+    ///
+    /// If any other read error is encountered then this function immediately
+    /// returns. The contents of `buf` are unspecified in this case.
+    ///
+    /// If this function returns an error, it is unspecified how many bytes it
+    /// has read, but it will never read more than would be necessary to
+    /// completely fill the buffer.
+    ///
+    /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
+    /// [`ErrorKind::UnexpectedEof`]: ../../../../std/io/enum.ErrorKind.html#variant.UnexpectedEof
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(rw_exact_all_at)]
+    /// use std::io;
+    /// use std::fs::File;
+    /// use std::os::unix::prelude::FileExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut buf = [0u8; 8];
+    ///     let file = File::open("foo.txt")?;
+    ///
+    ///     // We now read exactly 8 bytes from the offset 10.
+    ///     file.read_exact_at(&mut buf, 10)?;
+    ///     println!("read {} bytes: {:?}", buf.len(), buf);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "rw_exact_all_at", issue = "51984")]
+    fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
+        while !buf.is_empty() {
+            match self.read_at(buf, offset) {
+                Ok(0) => break,
+                Ok(n) => {
+                    let tmp = buf;
+                    buf = &mut tmp[n..];
+                    offset += n as u64;
+                }
+                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        if !buf.is_empty() {
+            Err(io::Error::new(io::ErrorKind::UnexpectedEof,
+                               "failed to fill whole buffer"))
+        } else {
+            Ok(())
+        }
+    }
+
     /// Writes a number of bytes starting from a given offset.
     ///
     /// Returns the number of bytes written.
@@ -78,21 +150,76 @@ pub trait FileExt {
     ///
     /// # Examples
     ///
-    /// ```
-    /// use std::os::unix::prelude::FileExt;
+    /// ```no_run
     /// use std::fs::File;
+    /// use std::io;
+    /// use std::os::unix::prelude::FileExt;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let file = File::open("foo.txt")?;
+    /// fn main() -> io::Result<()> {
+    ///     let file = File::open("foo.txt")?;
     ///
-    /// // We now write at the offset 10.
-    /// file.write_at(b"sushi", 10)?;
-    /// # Ok(())
-    /// # }
+    ///     // We now write at the offset 10.
+    ///     file.write_at(b"sushi", 10)?;
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "file_offset", since = "1.15.0")]
     fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
+
+    /// Attempts to write an entire buffer starting from a given offset.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// This method will continuously call [`write_at`] until there is no more data
+    /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
+    /// returned. This method will not return until the entire buffer has been
+    /// successfully written or such an error occurs. The first error that is
+    /// not of [`ErrorKind::Interrupted`] kind generated from this method will be
+    /// returned.
+    ///
+    /// # Errors
+    ///
+    /// This function will return the first error of
+    /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns.
+    ///
+    /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
+    /// [`write_at`]: #tymethod.write_at
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(rw_exact_all_at)]
+    /// use std::fs::File;
+    /// use std::io;
+    /// use std::os::unix::prelude::FileExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let file = File::open("foo.txt")?;
+    ///
+    ///     // We now write at the offset 10.
+    ///     file.write_all_at(b"sushi", 10)?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "rw_exact_all_at", issue = "51984")]
+    fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
+        while !buf.is_empty() {
+            match self.write_at(buf, offset) {
+                Ok(0) => return Err(io::Error::new(io::ErrorKind::WriteZero,
+                                                   "failed to write whole buffer")),
+                Ok(n) => {
+                    buf = &buf[n..];
+                    offset += n as u64
+                }
+                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        Ok(())
+    }
 }
 
 #[stable(feature = "file_offset", since = "1.15.0")]
@@ -105,7 +232,9 @@ impl FileExt for fs::File {
     }
 }
 
-/// Unix-specific extensions to `Permissions`
+/// Unix-specific extensions to [`fs::Permissions`].
+///
+/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
 #[stable(feature = "fs_ext", since = "1.1.0")]
 pub trait PermissionsExt {
     /// Returns the underlying raw `st_mode` bits that contain the standard
@@ -117,13 +246,13 @@ pub trait PermissionsExt {
     /// use std::fs::File;
     /// use std::os::unix::fs::PermissionsExt;
     ///
-    /// # fn run() -> std::io::Result<()> {
-    /// let f = File::create("foo.txt")?;
-    /// let metadata = f.metadata()?;
-    /// let permissions = metadata.permissions();
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::create("foo.txt")?;
+    ///     let metadata = f.metadata()?;
+    ///     let permissions = metadata.permissions();
     ///
-    /// println!("permissions: {}", permissions.mode());
-    /// # Ok(()) }
+    ///     println!("permissions: {}", permissions.mode());
+    ///     Ok(()) }
     /// ```
     #[stable(feature = "fs_ext", since = "1.1.0")]
     fn mode(&self) -> u32;
@@ -136,14 +265,14 @@ pub trait PermissionsExt {
     /// use std::fs::File;
     /// use std::os::unix::fs::PermissionsExt;
     ///
-    /// # fn run() -> std::io::Result<()> {
-    /// let f = File::create("foo.txt")?;
-    /// let metadata = f.metadata()?;
-    /// let mut permissions = metadata.permissions();
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::create("foo.txt")?;
+    ///     let metadata = f.metadata()?;
+    ///     let mut permissions = metadata.permissions();
     ///
-    /// permissions.set_mode(0o644); // Read/write for owner and read for others.
-    /// assert_eq!(permissions.mode(), 0o644);
-    /// # Ok(()) }
+    ///     permissions.set_mode(0o644); // Read/write for owner and read for others.
+    ///     assert_eq!(permissions.mode(), 0o644);
+    ///     Ok(()) }
     /// ```
     #[stable(feature = "fs_ext", since = "1.1.0")]
     fn set_mode(&mut self, mode: u32);
@@ -180,7 +309,9 @@ impl PermissionsExt for Permissions {
     }
 }
 
-/// Unix-specific extensions to `OpenOptions`
+/// Unix-specific extensions to [`fs::OpenOptions`].
+///
+/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
 #[stable(feature = "fs_ext", since = "1.1.0")]
 pub trait OpenOptionsExt {
     /// Sets the mode bits that a new file will be created with.
@@ -246,13 +377,9 @@ impl OpenOptionsExt for OpenOptions {
     }
 }
 
-// Hm, why are there casts here to the returned type, shouldn't the types always
-// be the same? Right you are! Turns out, however, on android at least the types
-// in the raw `stat` structure are not the same as the types being returned. Who
-// knew!
-//
-// As a result to make sure this compiles for all platforms we do the manual
-// casts and rely on manual lowering to `stat` if the raw type is desired.
+/// Unix-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
 #[stable(feature = "metadata_ext", since = "1.1.0")]
 pub trait MetadataExt {
     /// Returns the ID of the device containing the file.
@@ -260,15 +387,15 @@ pub trait MetadataExt {
     /// # Examples
     ///
     /// ```no_run
+    /// use std::io;
     /// use std::fs;
     /// use std::os::unix::fs::MetadataExt;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("some_file")?;
-    /// let dev_id = meta.dev();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let dev_id = meta.dev();
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn dev(&self) -> u64;
@@ -279,13 +406,13 @@ pub trait MetadataExt {
     /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("some_file")?;
-    /// let inode = meta.ino();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let inode = meta.ino();
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn ino(&self) -> u64;
@@ -296,17 +423,17 @@ pub trait MetadataExt {
     /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::MetadataExt;
-    ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("some_file")?;
-    /// let mode = meta.mode();
-    /// let user_has_write_access      = mode & 0o200;
-    /// let user_has_read_write_access = mode & 0o600;
-    /// let group_has_read_access      = mode & 0o040;
-    /// let others_have_exec_access    = mode & 0o001;
-    /// # Ok(())
-    /// # }
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let mode = meta.mode();
+    ///     let user_has_write_access      = mode & 0o200;
+    ///     let user_has_read_write_access = mode & 0o600;
+    ///     let group_has_read_access      = mode & 0o040;
+    ///     let others_have_exec_access    = mode & 0o001;
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn mode(&self) -> u32;
@@ -317,13 +444,13 @@ pub trait MetadataExt {
     /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::MetadataExt;
+    ///  use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("some_file")?;
-    /// let nb_hard_links = meta.nlink();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let nb_hard_links = meta.nlink();
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn nlink(&self) -> u64;
@@ -334,13 +461,13 @@ pub trait MetadataExt {
     /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("some_file")?;
-    /// let user_id = meta.uid();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let user_id = meta.uid();
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn uid(&self) -> u32;
@@ -351,13 +478,13 @@ pub trait MetadataExt {
     /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("some_file")?;
-    /// let group_id = meta.gid();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let group_id = meta.gid();
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn gid(&self) -> u32;
@@ -368,13 +495,13 @@ pub trait MetadataExt {
     /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("some_file")?;
-    /// let device_id = meta.rdev();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let device_id = meta.rdev();
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn rdev(&self) -> u64;
@@ -385,13 +512,13 @@ pub trait MetadataExt {
     /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("some_file")?;
-    /// let file_size = meta.size();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let file_size = meta.size();
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn size(&self) -> u64;
@@ -402,13 +529,13 @@ pub trait MetadataExt {
     /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("some_file")?;
-    /// let last_access_time = meta.atime();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let last_access_time = meta.atime();
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn atime(&self) -> i64;
@@ -419,13 +546,13 @@ pub trait MetadataExt {
     /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("some_file")?;
-    /// let nano_last_access_time = meta.atime_nsec();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let nano_last_access_time = meta.atime_nsec();
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn atime_nsec(&self) -> i64;
@@ -436,13 +563,13 @@ pub trait MetadataExt {
     /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("some_file")?;
-    /// let last_modification_time = meta.mtime();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let last_modification_time = meta.mtime();
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn mtime(&self) -> i64;
@@ -453,13 +580,13 @@ pub trait MetadataExt {
     /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("some_file")?;
-    /// let nano_last_modification_time = meta.mtime_nsec();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let nano_last_modification_time = meta.mtime_nsec();
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn mtime_nsec(&self) -> i64;
@@ -470,13 +597,13 @@ pub trait MetadataExt {
     /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("some_file")?;
-    /// let last_status_change_time = meta.ctime();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let last_status_change_time = meta.ctime();
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn ctime(&self) -> i64;
@@ -487,13 +614,13 @@ pub trait MetadataExt {
     /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("some_file")?;
-    /// let nano_last_status_change_time = meta.ctime_nsec();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let nano_last_status_change_time = meta.ctime_nsec();
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn ctime_nsec(&self) -> i64;
@@ -504,13 +631,13 @@ pub trait MetadataExt {
     /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("some_file")?;
-    /// let blocksize = meta.blksize();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let blocksize = meta.blksize();
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn blksize(&self) -> u64;
@@ -523,13 +650,13 @@ pub trait MetadataExt {
     /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("some_file")?;
-    /// let blocks = meta.blocks();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let blocks = meta.blocks();
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn blocks(&self) -> u64;
@@ -555,24 +682,29 @@ impl MetadataExt for fs::Metadata {
     fn blocks(&self) -> u64 { self.st_blocks() }
 }
 
-/// Add support for special unix types (block/char device, fifo and socket).
+/// Unix-specific extensions for [`FileType`].
+///
+/// Adds support for special Unix file types such as block/character devices,
+/// pipes, and sockets.
+///
+/// [`FileType`]: ../../../../std/fs/struct.FileType.html
 #[stable(feature = "file_type_ext", since = "1.5.0")]
 pub trait FileTypeExt {
     /// Returns whether this file type is a block device.
     ///
     /// # Examples
     ///
-    /// ```
+    /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::FileTypeExt;
+    /// use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("block_device_file")?;
-    /// let file_type = meta.file_type();
-    /// assert!(file_type.is_block_device());
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("block_device_file")?;
+    ///     let file_type = meta.file_type();
+    ///     assert!(file_type.is_block_device());
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "file_type_ext", since = "1.5.0")]
     fn is_block_device(&self) -> bool;
@@ -580,17 +712,17 @@ pub trait FileTypeExt {
     ///
     /// # Examples
     ///
-    /// ```
+    /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::FileTypeExt;
+    /// use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("char_device_file")?;
-    /// let file_type = meta.file_type();
-    /// assert!(file_type.is_char_device());
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("char_device_file")?;
+    ///     let file_type = meta.file_type();
+    ///     assert!(file_type.is_char_device());
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "file_type_ext", since = "1.5.0")]
     fn is_char_device(&self) -> bool;
@@ -598,17 +730,17 @@ pub trait FileTypeExt {
     ///
     /// # Examples
     ///
-    /// ```
+    /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::FileTypeExt;
+    /// use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("fifo_file")?;
-    /// let file_type = meta.file_type();
-    /// assert!(file_type.is_fifo());
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("fifo_file")?;
+    ///     let file_type = meta.file_type();
+    ///     assert!(file_type.is_fifo());
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "file_type_ext", since = "1.5.0")]
     fn is_fifo(&self) -> bool;
@@ -616,17 +748,17 @@ pub trait FileTypeExt {
     ///
     /// # Examples
     ///
-    /// ```
+    /// ```no_run
     /// use std::fs;
     /// use std::os::unix::fs::FileTypeExt;
+    /// use std::io;
     ///
-    /// # use std::io;
-    /// # fn f() -> io::Result<()> {
-    /// let meta = fs::metadata("unix.socket")?;
-    /// let file_type = meta.file_type();
-    /// assert!(file_type.is_socket());
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("unix.socket")?;
+    ///     let file_type = meta.file_type();
+    ///     assert!(file_type.is_socket());
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "file_type_ext", since = "1.5.0")]
     fn is_socket(&self) -> bool;
@@ -687,13 +819,13 @@ impl DirEntryExt for fs::DirEntry {
 ///
 /// # Examples
 ///
-/// ```
+/// ```no_run
 /// use std::os::unix::fs;
 ///
-/// # fn foo() -> std::io::Result<()> {
-/// fs::symlink("a.txt", "b.txt")?;
-/// # Ok(())
-/// # }
+/// fn main() -> std::io::Result<()> {
+///     fs::symlink("a.txt", "b.txt")?;
+///     Ok(())
+/// }
 /// ```
 #[stable(feature = "symlink", since = "1.1.0")]
 pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
@@ -701,10 +833,10 @@ pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
     sys::fs::symlink(src.as_ref(), dst.as_ref())
 }
 
-#[stable(feature = "dir_builder", since = "1.6.0")]
-/// An extension trait for [`fs::DirBuilder`] for unix-specific options.
+/// Unix-specific extensions to [`fs::DirBuilder`].
 ///
 /// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
+#[stable(feature = "dir_builder", since = "1.6.0")]
 pub trait DirBuilderExt {
     /// Sets the mode to create new directories with. This option defaults to
     /// 0o777.
diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs
index c221f7c8cfe..88e4237f8e2 100644
--- a/src/libstd/sys/unix/ext/mod.rs
+++ b/src/libstd/sys/unix/ext/mod.rs
@@ -35,6 +35,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 #![doc(cfg(unix))]
+#![allow(missing_docs)]
 
 pub mod io;
 pub mod ffi;
diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs
index 86b0f35be92..55f43ccd7db 100644
--- a/src/libstd/sys/unix/ext/net.rs
+++ b/src/libstd/sys/unix/ext/net.rs
@@ -51,13 +51,11 @@ use libc::MSG_NOSIGNAL;
 const MSG_NOSIGNAL: libc::c_int = 0x0;
 
 fn sun_path_offset() -> usize {
-    unsafe {
-        // Work with an actual instance of the type since using a null pointer is UB
-        let addr: libc::sockaddr_un = mem::uninitialized();
-        let base = &addr as *const _ as usize;
-        let path = &addr.sun_path as *const _ as usize;
-        path - base
-    }
+    // Work with an actual instance of the type since using a null pointer is UB
+    let addr: libc::sockaddr_un = unsafe { mem::uninitialized() };
+    let base = &addr as *const _ as usize;
+    let path = &addr.sun_path as *const _ as usize;
+    path - base
 }
 
 unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
@@ -216,7 +214,10 @@ impl SocketAddr {
         let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
 
         // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
-        if len == 0 || (cfg!(not(target_os = "linux")) && self.addr.sun_path[0] == 0) {
+        if len == 0
+            || (cfg!(not(any(target_os = "linux", target_os = "android")))
+                && self.addr.sun_path[0] == 0)
+        {
             AddressKind::Unnamed
         } else if self.addr.sun_path[0] == 0 {
             AddressKind::Abstract(&path[1..len])
@@ -387,10 +388,11 @@ impl UnixStream {
     /// Sets the read timeout for the socket.
     ///
     /// If the provided value is [`None`], then [`read`] calls will block
-    /// indefinitely. It is an error to pass the zero [`Duration`] to this
+    /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
     /// method.
     ///
     /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+    /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
     /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read
     /// [`Duration`]: ../../../../std/time/struct.Duration.html
     ///
@@ -403,6 +405,20 @@ impl UnixStream {
     /// let socket = UnixStream::connect("/tmp/sock").unwrap();
     /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
     /// ```
+    ///
+    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method:
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+    /// let err = result.unwrap_err();
+    /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
         self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
@@ -411,11 +427,12 @@ impl UnixStream {
     /// Sets the write timeout for the socket.
     ///
     /// If the provided value is [`None`], then [`write`] calls will block
-    /// indefinitely. It is an error to pass the zero [`Duration`] to this
-    /// method.
+    /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is
+    /// passed to this method.
     ///
     /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
-    /// [`read`]: ../../../../std/io/trait.Write.html#tymethod.write
+    /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
+    /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write
     /// [`Duration`]: ../../../../std/time/struct.Duration.html
     ///
     /// # Examples
@@ -427,6 +444,20 @@ impl UnixStream {
     /// let socket = UnixStream::connect("/tmp/sock").unwrap();
     /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
     /// ```
+    ///
+    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method:
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::net::UdpSocket;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap();
+    /// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+    /// let err = result.unwrap_err();
+    /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
         self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
@@ -493,6 +524,9 @@ impl UnixStream {
     ///     println!("Got error: {:?}", err);
     /// }
     /// ```
+    ///
+    /// # Platform specific
+    /// On Redox this always returns None.
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
         self.0.take_error()
@@ -815,6 +849,9 @@ impl UnixListener {
     ///     println!("Got error: {:?}", err);
     /// }
     /// ```
+    ///
+    /// # Platform specific
+    /// On Redox this always returns None.
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
         self.0.take_error()
@@ -1250,10 +1287,11 @@ impl UnixDatagram {
     /// Sets the read timeout for the socket.
     ///
     /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will
-    /// block indefinitely. It is an error to pass the zero [`Duration`] to this
-    /// method.
+    /// block indefinitely. An [`Err`] is returned if the zero [`Duration`]
+    /// is passed to this method.
     ///
     /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+    /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
     /// [`recv`]: #method.recv
     /// [`recv_from`]: #method.recv_from
     /// [`Duration`]: ../../../../std/time/struct.Duration.html
@@ -1267,6 +1305,20 @@ impl UnixDatagram {
     /// let sock = UnixDatagram::unbound().unwrap();
     /// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed");
     /// ```
+    ///
+    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method:
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixDatagram::unbound().unwrap();
+    /// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+    /// let err = result.unwrap_err();
+    /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
         self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
@@ -1275,7 +1327,7 @@ impl UnixDatagram {
     /// Sets the write timeout for the socket.
     ///
     /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will
-    /// block indefinitely. It is an error to pass the zero [`Duration`] to this
+    /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
     /// method.
     ///
     /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
@@ -1293,6 +1345,20 @@ impl UnixDatagram {
     /// sock.set_write_timeout(Some(Duration::new(1, 0)))
     ///     .expect("set_write_timeout function failed");
     /// ```
+    ///
+    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method:
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixDatagram::unbound().unwrap();
+    /// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+    /// let err = result.unwrap_err();
+    /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
         self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
@@ -1410,7 +1476,7 @@ impl IntoRawFd for UnixDatagram {
 #[cfg(all(test, not(target_os = "emscripten")))]
 mod test {
     use thread;
-    use io;
+    use io::{self, ErrorKind};
     use io::prelude::*;
     use time::Duration;
     use sys_common::io::test::tmpdir;
@@ -1613,6 +1679,27 @@ mod test {
         assert!(kind == io::ErrorKind::WouldBlock || kind == io::ErrorKind::TimedOut);
     }
 
+    // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+    // when passed zero Durations
+    #[test]
+    fn test_unix_stream_timeout_zero_duration() {
+        let dir = tmpdir();
+        let socket_path = dir.path().join("sock");
+
+        let listener = or_panic!(UnixListener::bind(&socket_path));
+        let stream = or_panic!(UnixStream::connect(&socket_path));
+
+        let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
+        let err = result.unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+        let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
+        let err = result.unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+        drop(listener);
+    }
+
     #[test]
     fn test_unix_datagram() {
         let dir = tmpdir();
@@ -1712,6 +1799,24 @@ mod test {
         thread.join().unwrap();
     }
 
+    // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+    // when passed zero Durations
+    #[test]
+    fn test_unix_datagram_timeout_zero_duration() {
+        let dir = tmpdir();
+        let path = dir.path().join("sock");
+
+        let datagram = or_panic!(UnixDatagram::bind(&path));
+
+        let result = datagram.set_write_timeout(Some(Duration::new(0, 0)));
+        let err = result.unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+        let result = datagram.set_read_timeout(Some(Duration::new(0, 0)));
+        let err = result.unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::InvalidInput);
+    }
+
     #[test]
     fn abstract_namespace_not_allowed() {
         assert!(UnixStream::connect("\0asdf").is_err());
diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs
index 60309bec6d4..21630ae9746 100644
--- a/src/libstd/sys/unix/ext/process.rs
+++ b/src/libstd/sys/unix/ext/process.rs
@@ -18,7 +18,9 @@ use process;
 use sys;
 use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};
 
-/// Unix-specific extensions to the `std::process::Command` builder
+/// Unix-specific extensions to the [`process::Command`] builder.
+///
+/// [`process::Command`]: ../../../../std/process/struct.Command.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait CommandExt {
     /// Sets the child process's user id. This translates to a
@@ -117,7 +119,9 @@ impl CommandExt for process::Command {
     }
 }
 
-/// Unix-specific extensions to `std::process::ExitStatus`
+/// Unix-specific extensions to [`process::ExitStatus`].
+///
+/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait ExitStatusExt {
     /// Creates a new `ExitStatus` from the raw underlying `i32` return value of
@@ -193,7 +197,7 @@ impl IntoRawFd for process::ChildStderr {
 }
 
 /// Returns the OS-assigned process identifier associated with this process's parent.
-#[unstable(feature = "unix_ppid", issue = "46104")]
+#[stable(feature = "unix_ppid", since = "1.27.0")]
 pub fn parent_id() -> u32 {
     ::sys::os::getppid()
 }
diff --git a/src/libstd/sys/unix/ext/thread.rs b/src/libstd/sys/unix/ext/thread.rs
index fe2a48764dc..8dadf29945c 100644
--- a/src/libstd/sys/unix/ext/thread.rs
+++ b/src/libstd/sys/unix/ext/thread.rs
@@ -21,7 +21,9 @@ use thread::JoinHandle;
 #[allow(deprecated)]
 pub type RawPthread = pthread_t;
 
-/// Unix-specific extensions to `std::thread::JoinHandle`
+/// Unix-specific extensions to [`thread::JoinHandle`].
+///
+/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html
 #[stable(feature = "thread_extensions", since = "1.9.0")]
 pub trait JoinHandleExt {
     /// Extracts the raw pthread_t without taking ownership
diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs
index 6cdbe5df75d..c13a0fea1e0 100644
--- a/src/libstd/sys/unix/fast_thread_local.rs
+++ b/src/libstd/sys/unix/fast_thread_local.rs
@@ -20,7 +20,7 @@
 // fallback implementation to use as well.
 //
 // Due to rust-lang/rust#18804, make sure this is not generic!
-#[cfg(target_os = "linux")]
+#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "hermit"))]
 pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
     use libc;
     use mem;
@@ -55,11 +55,6 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
     _tlv_atexit(dtor, t);
 }
 
-// Just use the thread_local fallback implementation, at least until there's
-// a more direct implementation.
-#[cfg(target_os = "fuchsia")]
-pub use sys_common::thread_local::register_dtor_fallback as register_dtor;
-
 pub fn requires_move_before_drop() -> bool {
     // The macOS implementation of TLS apparently had an odd aspect to it
     // where the pointer we have may be overwritten while this destructor
diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs
index 5dafc3251e7..4830e38d6a9 100644
--- a/src/libstd/sys/unix/fd.rs
+++ b/src/libstd/sys/unix/fd.rs
@@ -75,8 +75,15 @@ impl FileDesc {
         unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
             -> io::Result<isize>
         {
+            use convert::TryInto;
             use libc::pread64;
-            cvt(pread64(fd, buf, count, offset as i32))
+            // pread64 on emscripten actually takes a 32 bit offset
+            if let Ok(o) = offset.try_into() {
+                cvt(pread64(fd, buf, count, o))
+            } else {
+                Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                   "cannot pread >2GB"))
+            }
         }
 
         #[cfg(not(any(target_os = "android", target_os = "emscripten")))]
@@ -116,8 +123,15 @@ impl FileDesc {
         unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
             -> io::Result<isize>
         {
+            use convert::TryInto;
             use libc::pwrite64;
-            cvt(pwrite64(fd, buf, count, offset as i32))
+            // pwrite64 on emscripten actually takes a 32 bit offset
+            if let Ok(o) = offset.try_into() {
+                cvt(pwrite64(fd, buf, count, o))
+            } else {
+                Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                   "cannot pwrite >2GB"))
+            }
         }
 
         #[cfg(not(any(target_os = "android", target_os = "emscripten")))]
@@ -140,6 +154,13 @@ impl FileDesc {
         }
     }
 
+    #[cfg(target_os = "linux")]
+    pub fn get_cloexec(&self) -> io::Result<bool> {
+        unsafe {
+            Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0)
+        }
+    }
+
     #[cfg(not(any(target_env = "newlib",
                   target_os = "solaris",
                   target_os = "emscripten",
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
index a1ca839dc18..7a89d9857bb 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -25,8 +25,12 @@ use sys_common::{AsInner, FromInner};
 
 #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))]
 use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, readdir64_r, open64};
+#[cfg(any(target_os = "linux", target_os = "emscripten"))]
+use libc::fstatat64;
+#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))]
+use libc::dirfd;
 #[cfg(target_os = "android")]
-use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, lseek64,
+use libc::{stat as stat64, fstat as fstat64, fstatat as fstatat64, lstat as lstat64, lseek64,
            dirent as dirent64, open as open64};
 #[cfg(not(any(target_os = "linux",
               target_os = "emscripten",
@@ -48,9 +52,16 @@ pub struct FileAttr {
     stat: stat64,
 }
 
-pub struct ReadDir {
+// all DirEntry's will have a reference to this struct
+struct InnerReadDir {
     dirp: Dir,
-    root: Arc<PathBuf>,
+    root: PathBuf,
+}
+
+#[derive(Clone)]
+pub struct ReadDir {
+    inner: Arc<InnerReadDir>,
+    end_of_stream: bool,
 }
 
 struct Dir(*mut libc::DIR);
@@ -60,8 +71,8 @@ unsafe impl Sync for Dir {}
 
 pub struct DirEntry {
     entry: dirent64,
-    root: Arc<PathBuf>,
-    // We need to store an owned copy of the directory name
+    dir: ReadDir,
+    // We need to store an owned copy of the entry name
     // on Solaris and Fuchsia because a) it uses a zero-length
     // array to store the name, b) its lifetime between readdir
     // calls is not guaranteed.
@@ -207,7 +218,7 @@ impl fmt::Debug for ReadDir {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
         // Thus the result will be e g 'ReadDir("/home")'
-        fmt::Debug::fmt(&*self.root, f)
+        fmt::Debug::fmt(&*self.inner.root, f)
     }
 }
 
@@ -223,7 +234,7 @@ impl Iterator for ReadDir {
                 // is safe to use in threaded applications and it is generally preferred
                 // over the readdir_r(3C) function.
                 super::os::set_errno(0);
-                let entry_ptr = libc::readdir(self.dirp.0);
+                let entry_ptr = libc::readdir(self.inner.dirp.0);
                 if entry_ptr.is_null() {
                     // NULL can mean either the end is reached or an error occurred.
                     // So we had to clear errno beforehand to check for an error now.
@@ -240,7 +251,7 @@ impl Iterator for ReadDir {
                     entry: *entry_ptr,
                     name: ::slice::from_raw_parts(name as *const u8,
                                                   namelen as usize).to_owned().into_boxed_slice(),
-                    root: self.root.clone()
+                    dir: self.clone()
                 };
                 if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
                     return Some(Ok(ret))
@@ -251,14 +262,25 @@ impl Iterator for ReadDir {
 
     #[cfg(not(any(target_os = "solaris", target_os = "fuchsia")))]
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
+        if self.end_of_stream {
+            return None;
+        }
+
         unsafe {
             let mut ret = DirEntry {
                 entry: mem::zeroed(),
-                root: self.root.clone()
+                dir: self.clone(),
             };
             let mut entry_ptr = ptr::null_mut();
             loop {
-                if readdir64_r(self.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 {
+                if readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 {
+                    if entry_ptr.is_null() {
+                        // We encountered an error (which will be returned in this iteration), but
+                        // we also reached the end of the directory stream. The `end_of_stream`
+                        // flag is enabled to make sure that we return `None` in the next iteration
+                        // (instead of looping forever)
+                        self.end_of_stream = true;
+                    }
                     return Some(Err(Error::last_os_error()))
                 }
                 if entry_ptr.is_null() {
@@ -281,23 +303,34 @@ impl Drop for Dir {
 
 impl DirEntry {
     pub fn path(&self) -> PathBuf {
-        self.root.join(OsStr::from_bytes(self.name_bytes()))
+        self.dir.inner.root.join(OsStr::from_bytes(self.name_bytes()))
     }
 
     pub fn file_name(&self) -> OsString {
         OsStr::from_bytes(self.name_bytes()).to_os_string()
     }
 
+    #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))]
+    pub fn metadata(&self) -> io::Result<FileAttr> {
+        let fd = cvt(unsafe {dirfd(self.dir.inner.dirp.0)})?;
+        let mut stat: stat64 = unsafe { mem::zeroed() };
+        cvt(unsafe {
+            fstatat64(fd, self.entry.d_name.as_ptr(), &mut stat, libc::AT_SYMLINK_NOFOLLOW)
+        })?;
+        Ok(FileAttr { stat: stat })
+    }
+
+    #[cfg(not(any(target_os = "linux", target_os = "emscripten", target_os = "android")))]
     pub fn metadata(&self) -> io::Result<FileAttr> {
         lstat(&self.path())
     }
 
-    #[cfg(any(target_os = "solaris", target_os = "haiku"))]
+    #[cfg(any(target_os = "solaris", target_os = "haiku", target_os = "hermit"))]
     pub fn file_type(&self) -> io::Result<FileType> {
         lstat(&self.path()).map(|m| m.file_type())
     }
 
-    #[cfg(not(any(target_os = "solaris", target_os = "haiku")))]
+    #[cfg(not(any(target_os = "solaris", target_os = "haiku", target_os = "hermit")))]
     pub fn file_type(&self) -> io::Result<FileType> {
         match self.entry.d_type {
             libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }),
@@ -319,7 +352,8 @@ impl DirEntry {
               target_os = "solaris",
               target_os = "haiku",
               target_os = "l4re",
-              target_os = "fuchsia"))]
+              target_os = "fuchsia",
+              target_os = "hermit"))]
     pub fn ino(&self) -> u64 {
         self.entry.d_ino as u64
     }
@@ -350,7 +384,8 @@ impl DirEntry {
               target_os = "linux",
               target_os = "emscripten",
               target_os = "l4re",
-              target_os = "haiku"))]
+              target_os = "haiku",
+              target_os = "hermit"))]
     fn name_bytes(&self) -> &[u8] {
         unsafe {
             CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes()
@@ -441,15 +476,48 @@ impl File {
 
         // Currently the standard library supports Linux 2.6.18 which did not
         // have the O_CLOEXEC flag (passed above). If we're running on an older
-        // Linux kernel then the flag is just ignored by the OS, so we continue
-        // to explicitly ask for a CLOEXEC fd here.
+        // Linux kernel then the flag is just ignored by the OS. After we open
+        // the first file, we check whether it has CLOEXEC set. If it doesn't,
+        // we will explicitly ask for a CLOEXEC fd for every further file we
+        // open, if it does, we will skip that step.
         //
         // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc
         // that we support, so we only do this on Linux currently.
-        if cfg!(target_os = "linux") {
-            fd.set_cloexec()?;
+        #[cfg(target_os = "linux")]
+        fn ensure_cloexec(fd: &FileDesc) -> io::Result<()> {
+            use sync::atomic::{AtomicUsize, Ordering};
+
+            const OPEN_CLOEXEC_UNKNOWN: usize = 0;
+            const OPEN_CLOEXEC_SUPPORTED: usize = 1;
+            const OPEN_CLOEXEC_NOTSUPPORTED: usize = 2;
+            static OPEN_CLOEXEC: AtomicUsize = AtomicUsize::new(OPEN_CLOEXEC_UNKNOWN);
+
+            let need_to_set;
+            match OPEN_CLOEXEC.load(Ordering::Relaxed) {
+                OPEN_CLOEXEC_UNKNOWN => {
+                    need_to_set = !fd.get_cloexec()?;
+                    OPEN_CLOEXEC.store(if need_to_set {
+                        OPEN_CLOEXEC_NOTSUPPORTED
+                    } else {
+                        OPEN_CLOEXEC_SUPPORTED
+                    }, Ordering::Relaxed);
+                },
+                OPEN_CLOEXEC_SUPPORTED => need_to_set = false,
+                OPEN_CLOEXEC_NOTSUPPORTED => need_to_set = true,
+                _ => unreachable!(),
+            }
+            if need_to_set {
+                fd.set_cloexec()?;
+            }
+            Ok(())
+        }
+
+        #[cfg(not(target_os = "linux"))]
+        fn ensure_cloexec(_: &FileDesc) -> io::Result<()> {
+            Ok(())
         }
 
+        ensure_cloexec(&fd)?;
         Ok(File(fd))
     }
 
@@ -631,14 +699,18 @@ impl fmt::Debug for File {
 }
 
 pub fn readdir(p: &Path) -> io::Result<ReadDir> {
-    let root = Arc::new(p.to_path_buf());
+    let root = p.to_path_buf();
     let p = cstr(p)?;
     unsafe {
         let ptr = libc::opendir(p.as_ptr());
         if ptr.is_null() {
             Err(Error::last_os_error())
         } else {
-            Ok(ReadDir { dirp: Dir(ptr), root: root })
+            let inner = InnerReadDir { dirp: Dir(ptr), root };
+            Ok(ReadDir{
+                inner: Arc::new(inner),
+                end_of_stream: false,
+            })
         }
     }
 }
@@ -733,7 +805,7 @@ pub fn stat(p: &Path) -> io::Result<FileAttr> {
     let p = cstr(p)?;
     let mut stat: stat64 = unsafe { mem::zeroed() };
     cvt(unsafe {
-        stat64(p.as_ptr(), &mut stat as *mut _ as *mut _)
+        stat64(p.as_ptr(), &mut stat)
     })?;
     Ok(FileAttr { stat: stat })
 }
@@ -742,7 +814,7 @@ pub fn lstat(p: &Path) -> io::Result<FileAttr> {
     let p = cstr(p)?;
     let mut stat: stat64 = unsafe { mem::zeroed() };
     cvt(unsafe {
-        lstat64(p.as_ptr(), &mut stat as *mut _ as *mut _)
+        lstat64(p.as_ptr(), &mut stat)
     })?;
     Ok(FileAttr { stat: stat })
 }
@@ -761,8 +833,9 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
     Ok(PathBuf::from(OsString::from_vec(buf)))
 }
 
+#[cfg(not(any(target_os = "linux", target_os = "android")))]
 pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
-    use fs::{File, set_permissions};
+    use fs::File;
     if !from.is_file() {
         return Err(Error::new(ErrorKind::InvalidInput,
                               "the source path is not an existing regular file"))
@@ -773,6 +846,100 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
     let perm = reader.metadata()?.permissions();
 
     let ret = io::copy(&mut reader, &mut writer)?;
-    set_permissions(to, perm)?;
+    writer.set_permissions(perm)?;
     Ok(ret)
 }
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+    use cmp;
+    use fs::File;
+    use sync::atomic::{AtomicBool, Ordering};
+
+    // Kernel prior to 4.5 don't have copy_file_range
+    // We store the availability in a global to avoid unneccessary syscalls
+    static HAS_COPY_FILE_RANGE: AtomicBool = AtomicBool::new(true);
+
+    unsafe fn copy_file_range(
+        fd_in: libc::c_int,
+        off_in: *mut libc::loff_t,
+        fd_out: libc::c_int,
+        off_out: *mut libc::loff_t,
+        len: libc::size_t,
+        flags: libc::c_uint,
+    ) -> libc::c_long {
+        libc::syscall(
+            libc::SYS_copy_file_range,
+            fd_in,
+            off_in,
+            fd_out,
+            off_out,
+            len,
+            flags,
+        )
+    }
+
+    if !from.is_file() {
+        return Err(Error::new(ErrorKind::InvalidInput,
+                              "the source path is not an existing regular file"))
+    }
+
+    let mut reader = File::open(from)?;
+    let mut writer = File::create(to)?;
+    let (perm, len) = {
+        let metadata = reader.metadata()?;
+        (metadata.permissions(), metadata.size())
+    };
+
+    let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed);
+    let mut written = 0u64;
+    while written < len {
+        let copy_result = if has_copy_file_range {
+            let bytes_to_copy = cmp::min(len - written, usize::max_value() as u64) as usize;
+            let copy_result = unsafe {
+                // We actually don't have to adjust the offsets,
+                // because copy_file_range adjusts the file offset automatically
+                cvt(copy_file_range(reader.as_raw_fd(),
+                                    ptr::null_mut(),
+                                    writer.as_raw_fd(),
+                                    ptr::null_mut(),
+                                    bytes_to_copy,
+                                    0)
+                    )
+            };
+            if let Err(ref copy_err) = copy_result {
+                match copy_err.raw_os_error() {
+                    Some(libc::ENOSYS) | Some(libc::EPERM) => {
+                        HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed);
+                    }
+                    _ => {}
+                }
+            }
+            copy_result
+        } else {
+            Err(io::Error::from_raw_os_error(libc::ENOSYS))
+        };
+        match copy_result {
+            Ok(ret) => written += ret as u64,
+            Err(err) => {
+                match err.raw_os_error() {
+                    Some(os_err) if os_err == libc::ENOSYS
+                                 || os_err == libc::EXDEV
+                                 || os_err == libc::EPERM => {
+                        // Try fallback io::copy if either:
+                        // - Kernel version is < 4.5 (ENOSYS)
+                        // - Files are mounted on different fs (EXDEV)
+                        // - copy_file_range is disallowed, for example by seccomp (EPERM)
+                        assert_eq!(written, 0);
+                        let ret = io::copy(&mut reader, &mut writer)?;
+                        writer.set_permissions(perm)?;
+                        return Ok(ret)
+                    },
+                    _ => return Err(err),
+                }
+            }
+        }
+    }
+    writer.set_permissions(perm)?;
+    Ok(written)
+}
diff --git a/src/libstd/sys/unix/l4re.rs b/src/libstd/sys/unix/l4re.rs
index c3e8d0b7d95..21218489679 100644
--- a/src/libstd/sys/unix/l4re.rs
+++ b/src/libstd/sys/unix/l4re.rs
@@ -437,9 +437,5 @@ pub mod net {
     pub fn lookup_host(_: &str) -> io::Result<LookupHost> {
         unimpl!();
     }
-
-    pub fn res_init_if_glibc_before_2_26() -> io::Result<()> {
-        unimpl!();
-    }
 }
 
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
index 9bdea945ea4..c738003caf1 100644
--- a/src/libstd/sys/unix/mod.rs
+++ b/src/libstd/sys/unix/mod.rs
@@ -28,6 +28,7 @@ use libc;
 #[cfg(all(not(dox), target_os = "emscripten"))] pub use os::emscripten as platform;
 #[cfg(all(not(dox), target_os = "fuchsia"))]   pub use os::fuchsia as platform;
 #[cfg(all(not(dox), target_os = "l4re"))]      pub use os::linux as platform;
+#[cfg(all(not(dox), target_os = "hermit"))]    pub use os::hermit as platform;
 
 pub use self::rand::hashmap_random_keys;
 pub use libc::strlen;
@@ -80,11 +81,11 @@ pub fn init() {
         reset_sigpipe();
     }
 
-    #[cfg(not(any(target_os = "emscripten", target_os="fuchsia")))]
+    #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))]
     unsafe fn reset_sigpipe() {
         assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
     }
-    #[cfg(any(target_os = "emscripten", target_os="fuchsia"))]
+    #[cfg(any(target_os = "emscripten", target_os = "fuchsia"))]
     unsafe fn reset_sigpipe() {}
 }
 
diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs
index 52cf3f97c5c..1d447de1134 100644
--- a/src/libstd/sys/unix/mutex.rs
+++ b/src/libstd/sys/unix/mutex.rs
@@ -25,8 +25,10 @@ unsafe impl Sync for Mutex {}
 #[allow(dead_code)] // sys isn't exported yet
 impl Mutex {
     pub const fn new() -> Mutex {
-        // Might be moved and address is changing it is better to avoid
-        // initialization of potentially opaque OS data before it landed
+        // Might be moved to a different address, so it is better to avoid
+        // initialization of potentially opaque OS data before it landed.
+        // Be very careful using this newly constructed `Mutex`, reentrant
+        // locking is undefined behavior until `init` is called!
         Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
     }
     #[inline]
@@ -49,9 +51,6 @@ impl Mutex {
         // references, we instead create the mutex with type
         // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to
         // re-lock it from the same thread, thus avoiding undefined behavior.
-        //
-        // We can't do anything for StaticMutex, but that type is deprecated
-        // anyways.
         let mut attr: libc::pthread_mutexattr_t = mem::uninitialized();
         let r = libc::pthread_mutexattr_init(&mut attr);
         debug_assert_eq!(r, 0);
diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs
index e775f857f2b..04d9f0b06d3 100644
--- a/src/libstd/sys/unix/net.rs
+++ b/src/libstd/sys/unix/net.rs
@@ -51,6 +51,10 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> {
     if err == 0 {
         return Ok(())
     }
+
+    // We may need to trigger a glibc workaround. See on_resolver_failure() for details.
+    on_resolver_failure();
+
     if err == EAI_SYSTEM {
         return Err(io::Error::last_os_error())
     }
@@ -377,43 +381,22 @@ impl IntoInner<c_int> for Socket {
 // res_init unconditionally, we call it only when we detect we're linking
 // against glibc version < 2.26. (That is, when we both know its needed and
 // believe it's thread-safe).
-pub fn res_init_if_glibc_before_2_26() -> io::Result<()> {
+#[cfg(target_env = "gnu")]
+fn on_resolver_failure() {
+    use sys;
+
     // If the version fails to parse, we treat it the same as "not glibc".
-    if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) {
-        if let Some(version) = parse_glibc_version(version_str) {
-            if version < (2, 26) {
-                let ret = unsafe { libc::res_init() };
-                if ret != 0 {
-                    return Err(io::Error::last_os_error());
-                }
-            }
+    if let Some(version) = sys::os::glibc_version() {
+        if version < (2, 26) {
+            unsafe { libc::res_init() };
         }
     }
-    Ok(())
 }
 
-fn glibc_version_cstr() -> Option<&'static CStr> {
-    weak! {
-        fn gnu_get_libc_version() -> *const libc::c_char
-    }
-    if let Some(f) = gnu_get_libc_version.get() {
-        unsafe { Some(CStr::from_ptr(f())) }
-    } else {
-        None
-    }
-}
-
-// Returns Some((major, minor)) if the string is a valid "x.y" version,
-// ignoring any extra dot-separated parts. Otherwise return None.
-fn parse_glibc_version(version: &str) -> Option<(usize, usize)> {
-    let mut parsed_ints = version.split(".").map(str::parse::<usize>).fuse();
-    match (parsed_ints.next(), parsed_ints.next()) {
-        (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)),
-        _ => None
-    }
-}
+#[cfg(not(target_env = "gnu"))]
+fn on_resolver_failure() {}
 
-#[cfg(test)]
+#[cfg(all(test, taget_env = "gnu"))]
 mod test {
     use super::*;
 
diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs
index a46e855b4a6..f8f0bbd5bc2 100644
--- a/src/libstd/sys/unix/os.rs
+++ b/src/libstd/sys/unix/os.rs
@@ -33,6 +33,8 @@ use sys::fd;
 use vec;
 
 const TMPBUF_SZ: usize = 128;
+// We never call `ENV_LOCK.init()`, so it is UB to attempt to
+// acquire this mutex reentrantly!
 static ENV_LOCK: Mutex = Mutex::new();
 
 
@@ -47,6 +49,7 @@ extern {
                    target_os = "netbsd",
                    target_os = "openbsd",
                    target_os = "android",
+                   target_os = "hermit",
                    target_env = "newlib"),
                link_name = "__errno")]
     #[cfg_attr(target_os = "solaris", link_name = "___errno")]
@@ -376,7 +379,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
     }
 }
 
-#[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
+#[cfg(any(target_os = "fuchsia", target_os = "l4re", target_os = "hermit"))]
 pub fn current_exe() -> io::Result<PathBuf> {
     use io::ErrorKind;
     Err(io::Error::new(ErrorKind::Other, "Not yet implemented!"))
@@ -409,26 +412,19 @@ pub unsafe fn environ() -> *mut *const *const c_char {
 /// environment variables of the current process.
 pub fn env() -> Env {
     unsafe {
-        ENV_LOCK.lock();
+        let _guard = ENV_LOCK.lock();
         let mut environ = *environ();
-        if environ == ptr::null() {
-            ENV_LOCK.unlock();
-            panic!("os::env() failure getting env string from OS: {}",
-                   io::Error::last_os_error());
-        }
         let mut result = Vec::new();
-        while *environ != ptr::null() {
+        while environ != ptr::null() && *environ != ptr::null() {
             if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
                 result.push(key_value);
             }
             environ = environ.offset(1);
         }
-        let ret = Env {
+        return Env {
             iter: result.into_iter(),
             _dont_send_or_sync_me: PhantomData,
-        };
-        ENV_LOCK.unlock();
-        return ret
+        }
     }
 
     fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
@@ -452,15 +448,14 @@ pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
     // always None as well
     let k = CString::new(k.as_bytes())?;
     unsafe {
-        ENV_LOCK.lock();
+        let _guard = ENV_LOCK.lock();
         let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
         let ret = if s.is_null() {
             None
         } else {
             Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
         };
-        ENV_LOCK.unlock();
-        return Ok(ret)
+        Ok(ret)
     }
 }
 
@@ -469,10 +464,8 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
     let v = CString::new(v.as_bytes())?;
 
     unsafe {
-        ENV_LOCK.lock();
-        let ret = cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ());
-        ENV_LOCK.unlock();
-        return ret
+        let _guard = ENV_LOCK.lock();
+        cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ())
     }
 }
 
@@ -480,10 +473,8 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> {
     let nbuf = CString::new(n.as_bytes())?;
 
     unsafe {
-        ENV_LOCK.lock();
-        let ret = cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ());
-        ENV_LOCK.unlock();
-        return ret
+        let _guard = ENV_LOCK.lock();
+        cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ())
     }
 }
 
@@ -546,3 +537,35 @@ pub fn getpid() -> u32 {
 pub fn getppid() -> u32 {
     unsafe { libc::getppid() as u32 }
 }
+
+#[cfg(target_env = "gnu")]
+pub fn glibc_version() -> Option<(usize, usize)> {
+    if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) {
+        parse_glibc_version(version_str)
+    } else {
+        None
+    }
+}
+
+#[cfg(target_env = "gnu")]
+fn glibc_version_cstr() -> Option<&'static CStr> {
+    weak! {
+        fn gnu_get_libc_version() -> *const libc::c_char
+    }
+    if let Some(f) = gnu_get_libc_version.get() {
+        unsafe { Some(CStr::from_ptr(f())) }
+    } else {
+        None
+    }
+}
+
+// Returns Some((major, minor)) if the string is a valid "x.y" version,
+// ignoring any extra dot-separated parts. Otherwise return None.
+#[cfg(target_env = "gnu")]
+fn parse_glibc_version(version: &str) -> Option<(usize, usize)> {
+    let mut parsed_ints = version.split('.').map(str::parse::<usize>).fuse();
+    match (parsed_ints.next(), parsed_ints.next()) {
+        (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)),
+        _ => None
+    }
+}
diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs
index e0349387998..01c0fb830aa 100644
--- a/src/libstd/sys/unix/os_str.rs
+++ b/src/libstd/sys/unix/os_str.rs
@@ -19,7 +19,7 @@ use rc::Rc;
 use sync::Arc;
 use sys_common::{AsInner, IntoInner};
 use sys_common::bytestring::debug_fmt_bytestring;
-use std_unicode::lossy::Utf8Lossy;
+use core::str::lossy::Utf8Lossy;
 
 #[derive(Clone, Hash)]
 pub struct Buf {
@@ -104,6 +104,11 @@ impl Buf {
         self.inner.shrink_to_fit()
     }
 
+    #[inline]
+    pub fn shrink_to(&mut self, min_capacity: usize) {
+        self.inner.shrink_to(min_capacity)
+    }
+
     pub fn as_slice(&self) -> &Slice {
         unsafe { mem::transmute(&*self.inner) }
     }
diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs
index ec9b6f17dca..0a5dccdddda 100644
--- a/src/libstd/sys/unix/pipe.rs
+++ b/src/libstd/sys/unix/pipe.rs
@@ -100,24 +100,6 @@ pub fn read2(p1: AnonPipe,
         // wait for either pipe to become readable using `poll`
         cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?;
 
-        // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
-        // EAGAIN. If we hit EOF, then this will happen because the underlying
-        // reader will return Ok(0), in which case we'll see `Ok` ourselves. In
-        // this case we flip the other fd back into blocking mode and read
-        // whatever's leftover on that file descriptor.
-        let read = |fd: &FileDesc, dst: &mut Vec<u8>| {
-            match fd.read_to_end(dst) {
-                Ok(_) => Ok(true),
-                Err(e) => {
-                    if e.raw_os_error() == Some(libc::EWOULDBLOCK) ||
-                       e.raw_os_error() == Some(libc::EAGAIN) {
-                        Ok(false)
-                    } else {
-                        Err(e)
-                    }
-                }
-            }
-        };
         if fds[0].revents != 0 && read(&p1, v1)? {
             p2.set_nonblocking(false)?;
             return p2.read_to_end(v2).map(|_| ());
@@ -127,4 +109,23 @@ pub fn read2(p1: AnonPipe,
             return p1.read_to_end(v1).map(|_| ());
         }
     }
+
+    // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
+    // EAGAIN. If we hit EOF, then this will happen because the underlying
+    // reader will return Ok(0), in which case we'll see `Ok` ourselves. In
+    // this case we flip the other fd back into blocking mode and read
+    // whatever's leftover on that file descriptor.
+    fn read(fd: &FileDesc, dst: &mut Vec<u8>) -> Result<bool, io::Error> {
+        match fd.read_to_end(dst) {
+            Ok(_) => Ok(true),
+            Err(e) => {
+                if e.raw_os_error() == Some(libc::EWOULDBLOCK) ||
+                   e.raw_os_error() == Some(libc::EAGAIN) {
+                    Ok(false)
+                } else {
+                    Err(e)
+                }
+            }
+        }
+    }
 }
diff --git a/src/libstd/sys/unix/process/mod.rs b/src/libstd/sys/unix/process/mod.rs
index 2a331069bc2..d8ac26c45b1 100644
--- a/src/libstd/sys/unix/process/mod.rs
+++ b/src/libstd/sys/unix/process/mod.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub use self::process_common::{Command, ExitStatus, Stdio, StdioPipes};
+pub use self::process_common::{Command, ExitStatus, ExitCode, Stdio, StdioPipes};
 pub use self::process_inner::Process;
 
 mod process_common;
diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs
index c53bcdbf8e3..77f125f3c5b 100644
--- a/src/libstd/sys/unix/process/process_common.rs
+++ b/src/libstd/sys/unix/process/process_common.rs
@@ -13,7 +13,7 @@ use os::unix::prelude::*;
 use ffi::{OsString, OsStr, CString, CStr};
 use fmt;
 use io;
-use libc::{self, c_int, gid_t, uid_t, c_char};
+use libc::{self, c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};
 use ptr;
 use sys::fd::FileDesc;
 use sys::fs::{File, OpenOptions};
@@ -45,19 +45,25 @@ pub struct Command {
     // other keys.
     program: CString,
     args: Vec<CString>,
-    argv: Vec<*const c_char>,
+    argv: Argv,
     env: CommandEnv<DefaultEnvKey>,
 
     cwd: Option<CString>,
     uid: Option<uid_t>,
     gid: Option<gid_t>,
     saw_nul: bool,
-    closures: Vec<Box<FnMut() -> io::Result<()> + Send + Sync>>,
+    closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
     stdin: Option<Stdio>,
     stdout: Option<Stdio>,
     stderr: Option<Stdio>,
 }
 
+// Create a new type for argv, so that we can make it `Send`
+struct Argv(Vec<*const c_char>);
+
+// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args`
+unsafe impl Send for Argv {}
+
 // passed back to std::process with the pipes connected to the child, if any
 // were requested
 pub struct StdioPipes {
@@ -92,7 +98,7 @@ impl Command {
         let mut saw_nul = false;
         let program = os2c(program, &mut saw_nul);
         Command {
-            argv: vec![program.as_ptr(), ptr::null()],
+            argv: Argv(vec![program.as_ptr(), ptr::null()]),
             program,
             args: Vec::new(),
             env: Default::default(),
@@ -111,8 +117,8 @@ impl Command {
         // Overwrite the trailing NULL pointer in `argv` and then add a new null
         // pointer.
         let arg = os2c(arg, &mut self.saw_nul);
-        self.argv[self.args.len() + 1] = arg.as_ptr();
-        self.argv.push(ptr::null());
+        self.argv.0[self.args.len() + 1] = arg.as_ptr();
+        self.argv.0.push(ptr::null());
 
         // Also make sure we keep track of the owned value to schedule a
         // destructor for this memory.
@@ -133,7 +139,7 @@ impl Command {
         self.saw_nul
     }
     pub fn get_argv(&self) -> &Vec<*const c_char> {
-        &self.argv
+        &self.argv.0
     }
 
     #[allow(dead_code)]
@@ -149,12 +155,12 @@ impl Command {
         self.gid
     }
 
-    pub fn get_closures(&mut self) -> &mut Vec<Box<FnMut() -> io::Result<()> + Send + Sync>> {
+    pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
         &mut self.closures
     }
 
     pub fn before_exec(&mut self,
-                       f: Box<FnMut() -> io::Result<()> + Send + Sync>) {
+                       f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>) {
         self.closures.push(f);
     }
 
@@ -178,6 +184,10 @@ impl Command {
         let maybe_env = self.env.capture_if_changed();
         maybe_env.map(|env| construct_envp(env, &mut self.saw_nul))
     }
+    #[allow(dead_code)]
+    pub fn env_saw_path(&self) -> bool {
+        self.env.have_changed_path()
+    }
 
     pub fn setup_io(&self, default: Stdio, needs_stdin: bool)
                 -> io::Result<(StdioPipes, ChildPipes)> {
@@ -387,6 +397,19 @@ impl fmt::Display for ExitStatus {
     }
 }
 
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(u8);
+
+impl ExitCode {
+    pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
+    pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);
+
+    #[inline]
+    pub fn as_i32(&self) -> i32 {
+        self.0 as i32
+    }
+}
+
 #[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
     use super::*;
diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs
index 06c0540fec0..fa48001179e 100644
--- a/src/libstd/sys/unix/process/process_fuchsia.rs
+++ b/src/libstd/sys/unix/process/process_fuchsia.rs
@@ -56,68 +56,49 @@ impl Command {
                       -> io::Result<zx_handle_t> {
         use sys::process::zircon::*;
 
-        let job_handle = zx_job_default();
         let envp = match maybe_envp {
             Some(envp) => envp.as_ptr(),
             None => ptr::null(),
         };
 
-        // To make sure launchpad_destroy gets called on the launchpad if this function fails
-        struct LaunchpadDestructor(*mut launchpad_t);
-        impl Drop for LaunchpadDestructor {
-            fn drop(&mut self) { unsafe { launchpad_destroy(self.0); } }
-        }
-
-        // Duplicate the job handle
-        let mut job_copy: zx_handle_t = ZX_HANDLE_INVALID;
-        zx_cvt(zx_handle_duplicate(job_handle, ZX_RIGHT_SAME_RIGHTS, &mut job_copy))?;
-        // Create a launchpad
-        let mut launchpad: *mut launchpad_t = ptr::null_mut();
-        zx_cvt(launchpad_create(job_copy, self.get_argv()[0], &mut launchpad))?;
-        let launchpad_destructor = LaunchpadDestructor(launchpad);
-
-        // Set the process argv
-        zx_cvt(launchpad_set_args(launchpad, self.get_argv().len() as i32 - 1,
-                                  self.get_argv().as_ptr()))?;
-        // Setup the environment vars
-        zx_cvt(launchpad_set_environ(launchpad, envp))?;
-        zx_cvt(launchpad_add_vdso_vmo(launchpad))?;
-        // Load the executable
-        zx_cvt(launchpad_elf_load(launchpad, launchpad_vmo_from_file(self.get_argv()[0])))?;
-        zx_cvt(launchpad_load_vdso(launchpad, ZX_HANDLE_INVALID))?;
-        zx_cvt(launchpad_clone(launchpad, LP_CLONE_FDIO_NAMESPACE | LP_CLONE_FDIO_CWD))?;
+        let transfer_or_clone = |opt_fd, target_fd| if let Some(local_fd) = opt_fd {
+            fdio_spawn_action_t {
+                action: FDIO_SPAWN_ACTION_TRANSFER_FD,
+                local_fd,
+                target_fd,
+                ..Default::default()
+            }
+        } else {
+            fdio_spawn_action_t {
+                action: FDIO_SPAWN_ACTION_CLONE_FD,
+                local_fd: target_fd,
+                target_fd,
+                ..Default::default()
+            }
+        };
 
         // Clone stdin, stdout, and stderr
-        if let Some(fd) = stdio.stdin.fd() {
-            zx_cvt(launchpad_transfer_fd(launchpad, fd, 0))?;
-        } else {
-            zx_cvt(launchpad_clone_fd(launchpad, 0, 0))?;
-        }
-        if let Some(fd) = stdio.stdout.fd() {
-            zx_cvt(launchpad_transfer_fd(launchpad, fd, 1))?;
-        } else {
-            zx_cvt(launchpad_clone_fd(launchpad, 1, 1))?;
-        }
-        if let Some(fd) = stdio.stderr.fd() {
-            zx_cvt(launchpad_transfer_fd(launchpad, fd, 2))?;
-        } else {
-            zx_cvt(launchpad_clone_fd(launchpad, 2, 2))?;
-        }
+        let action1 = transfer_or_clone(stdio.stdin.fd(), 0);
+        let action2 = transfer_or_clone(stdio.stdout.fd(), 1);
+        let action3 = transfer_or_clone(stdio.stderr.fd(), 2);
+        let actions = [action1, action2, action3];
 
-        // We don't want FileDesc::drop to be called on any stdio. It would close their fds. The
-        // fds will be closed once the child process finishes.
+        // We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc
+        // always consumes transferred file descriptors.
         mem::forget(stdio);
 
         for callback in self.get_closures().iter_mut() {
             callback()?;
         }
 
-        // `launchpad_go` destroys the launchpad, so we must not
-        mem::forget(launchpad_destructor);
-
         let mut process_handle: zx_handle_t = 0;
-        let mut err_msg: *const libc::c_char = ptr::null();
-        zx_cvt(launchpad_go(launchpad, &mut process_handle, &mut err_msg))?;
+        zx_cvt(fdio_spawn_etc(
+            0,
+            FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE,
+            self.get_argv()[0], self.get_argv().as_ptr(), envp, 3, actions.as_ptr(),
+            &mut process_handle,
+            ptr::null_mut(),
+        ))?;
         // FIXME: See if we want to do something with that err_msg
 
         Ok(process_handle)
diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs
index 189280a4ba9..9d6d607e3f3 100644
--- a/src/libstd/sys/unix/process/process_unix.rs
+++ b/src/libstd/sys/unix/process/process_unix.rs
@@ -34,6 +34,11 @@ impl Command {
         }
 
         let (ours, theirs) = self.setup_io(default, needs_stdin)?;
+
+        if let Some(ret) = self.posix_spawn(&theirs, envp.as_ref())? {
+            return Ok((ret, ours))
+        }
+
         let (input, output) = sys::pipe::anon_pipe()?;
 
         let pid = unsafe {
@@ -229,6 +234,119 @@ impl Command {
         libc::execvp(self.get_argv()[0], self.get_argv().as_ptr());
         io::Error::last_os_error()
     }
+
+    #[cfg(not(any(target_os = "macos", target_os = "freebsd",
+                  all(target_os = "linux", target_env = "gnu"))))]
+    fn posix_spawn(&mut self, _: &ChildPipes, _: Option<&CStringArray>)
+        -> io::Result<Option<Process>>
+    {
+        Ok(None)
+    }
+
+    // Only support platforms for which posix_spawn() can return ENOENT
+    // directly.
+    #[cfg(any(target_os = "macos", target_os = "freebsd",
+              all(target_os = "linux", target_env = "gnu")))]
+    fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>)
+        -> io::Result<Option<Process>>
+    {
+        use mem;
+        use sys;
+
+        if self.get_cwd().is_some() ||
+            self.get_gid().is_some() ||
+            self.get_uid().is_some() ||
+            self.env_saw_path() ||
+            self.get_closures().len() != 0 {
+            return Ok(None)
+        }
+
+        // Only glibc 2.24+ posix_spawn() supports returning ENOENT directly.
+        #[cfg(all(target_os = "linux", target_env = "gnu"))]
+        {
+            if let Some(version) = sys::os::glibc_version() {
+                if version < (2, 24) {
+                    return Ok(None)
+                }
+            } else {
+                return Ok(None)
+            }
+        }
+
+        let mut p = Process { pid: 0, status: None };
+
+        struct PosixSpawnFileActions(libc::posix_spawn_file_actions_t);
+
+        impl Drop for PosixSpawnFileActions {
+            fn drop(&mut self) {
+                unsafe {
+                    libc::posix_spawn_file_actions_destroy(&mut self.0);
+                }
+            }
+        }
+
+        struct PosixSpawnattr(libc::posix_spawnattr_t);
+
+        impl Drop for PosixSpawnattr {
+            fn drop(&mut self) {
+                unsafe {
+                    libc::posix_spawnattr_destroy(&mut self.0);
+                }
+            }
+        }
+
+        unsafe {
+            let mut file_actions = PosixSpawnFileActions(mem::uninitialized());
+            let mut attrs = PosixSpawnattr(mem::uninitialized());
+
+            libc::posix_spawnattr_init(&mut attrs.0);
+            libc::posix_spawn_file_actions_init(&mut file_actions.0);
+
+            if let Some(fd) = stdio.stdin.fd() {
+                cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0,
+                                                           fd,
+                                                           libc::STDIN_FILENO))?;
+            }
+            if let Some(fd) = stdio.stdout.fd() {
+                cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0,
+                                                           fd,
+                                                           libc::STDOUT_FILENO))?;
+            }
+            if let Some(fd) = stdio.stderr.fd() {
+                cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0,
+                                                           fd,
+                                                           libc::STDERR_FILENO))?;
+            }
+
+            let mut set: libc::sigset_t = mem::uninitialized();
+            cvt(libc::sigemptyset(&mut set))?;
+            cvt(libc::posix_spawnattr_setsigmask(&mut attrs.0,
+                                                 &set))?;
+            cvt(libc::sigaddset(&mut set, libc::SIGPIPE))?;
+            cvt(libc::posix_spawnattr_setsigdefault(&mut attrs.0,
+                                                    &set))?;
+
+            let flags = libc::POSIX_SPAWN_SETSIGDEF |
+                libc::POSIX_SPAWN_SETSIGMASK;
+            cvt(libc::posix_spawnattr_setflags(&mut attrs.0, flags as _))?;
+
+            let envp = envp.map(|c| c.as_ptr())
+                .unwrap_or(*sys::os::environ() as *const _);
+            let ret = libc::posix_spawnp(
+                &mut p.pid,
+                self.get_argv()[0],
+                &file_actions.0,
+                &attrs.0,
+                self.get_argv().as_ptr() as *const _,
+                envp as *const _,
+            );
+            if ret == 0 {
+                Ok(Some(p))
+            } else {
+                Err(io::Error::from_raw_os_error(ret))
+            }
+        }
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/libstd/sys/unix/process/zircon.rs b/src/libstd/sys/unix/process/zircon.rs
index 90864e6ef3f..a06c73ee263 100644
--- a/src/libstd/sys/unix/process/zircon.rs
+++ b/src/libstd/sys/unix/process/zircon.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_camel_case_types)]
+#![allow(non_camel_case_types, unused)]
 
 use convert::TryInto;
 use io;
@@ -117,75 +117,36 @@ extern {
                               avail: *mut size_t) -> zx_status_t;
 }
 
-// From `enum special_handles` in system/ulib/launchpad/launchpad.c
-// HND_LOADER_SVC = 0
-// HND_EXEC_VMO = 1
-// HND_SEGMENTS_VMAR = 2
-const HND_SPECIAL_COUNT: c_int = 3;
-
+#[derive(Default)]
 #[repr(C)]
-pub struct launchpad_t {
-    argc: u32,
-    envc: u32,
-    args: *const c_char,
-    args_len: size_t,
-    env: *const c_char,
-    env_len: size_t,
-
-    handles: *mut zx_handle_t,
-    handles_info: *mut u32,
-    handle_count: size_t,
-    handle_alloc: size_t,
-
-    entry: zx_vaddr_t,
-    base: zx_vaddr_t,
-    vdso_base: zx_vaddr_t,
-
-    stack_size: size_t,
-
-    special_handles: [zx_handle_t; HND_SPECIAL_COUNT as usize],
-    loader_message: bool,
+pub struct fdio_spawn_action_t {
+    pub action: u32,
+    pub reserved0: u32,
+    pub local_fd: i32,
+    pub target_fd: i32,
+    pub reserved1: u64,
 }
 
 extern {
-    pub fn launchpad_create(job: zx_handle_t, name: *const c_char,
-                            lp: *mut *mut launchpad_t) -> zx_status_t;
-
-    pub fn launchpad_go(lp: *mut launchpad_t,
-                        proc_handle: *mut zx_handle_t,
-                        err_msg: *mut *const c_char) -> zx_status_t;
-
-    pub fn launchpad_destroy(lp: *mut launchpad_t);
-
-    pub fn launchpad_set_args(lp: *mut launchpad_t, argc: c_int,
-                               argv: *const *const c_char) -> zx_status_t;
-
-    pub fn launchpad_set_environ(lp: *mut launchpad_t, envp: *const *const c_char) -> zx_status_t;
-
-    pub fn launchpad_clone(lp: *mut launchpad_t, what: u32) -> zx_status_t;
-
-    pub fn launchpad_clone_fd(lp: *mut launchpad_t, fd: c_int, target_fd: c_int) -> zx_status_t;
-
-    pub fn launchpad_transfer_fd(lp: *mut launchpad_t, fd: c_int, target_fd: c_int) -> zx_status_t;
-
-    pub fn launchpad_elf_load(lp: *mut launchpad_t, vmo: zx_handle_t) -> zx_status_t;
-
-    pub fn launchpad_add_vdso_vmo(lp: *mut launchpad_t) -> zx_status_t;
+    pub fn fdio_spawn_etc(job: zx_handle_t, flags: u32, path: *const c_char,
+                          argv: *const *const c_char, envp: *const *const c_char,
+                          action_count: u64, actions: *const fdio_spawn_action_t,
+                          process: *mut zx_handle_t, err_msg: *mut c_char) -> zx_status_t;
+}
 
-    pub fn launchpad_load_vdso(lp: *mut launchpad_t, vmo: zx_handle_t) -> zx_status_t;
+// fdio_spawn_etc flags
 
-    pub fn launchpad_vmo_from_file(filename: *const c_char) -> zx_handle_t;
-}
+pub const FDIO_SPAWN_CLONE_JOB: u32 = 0x0001;
+pub const FDIO_SPAWN_CLONE_LDSVC: u32 = 0x0002;
+pub const FDIO_SPAWN_CLONE_NAMESPACE: u32 = 0x0004;
+pub const FDIO_SPAWN_CLONE_STDIO: u32 = 0x0008;
+pub const FDIO_SPAWN_CLONE_ENVIRON: u32 = 0x0010;
+pub const FDIO_SPAWN_CLONE_ALL: u32 = 0xFFFF;
 
-// Launchpad clone constants
+// fdio_spawn_etc actions
 
-pub const LP_CLONE_FDIO_NAMESPACE: u32 = 0x0001;
-pub const LP_CLONE_FDIO_CWD: u32 = 0x0002;
-// LP_CLONE_FDIO_STDIO = 0x0004
-// LP_CLONE_FDIO_ALL = 0x00FF
-// LP_CLONE_ENVIRON = 0x0100
-// LP_CLONE_DEFAULT_JOB = 0x0200
-// LP_CLONE_ALL = 0xFFFF
+pub const FDIO_SPAWN_ACTION_CLONE_FD: u32 = 0x0001;
+pub const FDIO_SPAWN_ACTION_TRANSFER_FD: u32 = 0x0002;
 
 // Errors
 
diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs
index caa18945765..01c0ada4ffb 100644
--- a/src/libstd/sys/unix/rand.rs
+++ b/src/libstd/sys/unix/rand.rs
@@ -183,35 +183,10 @@ mod imp {
 mod imp {
     #[link(name = "zircon")]
     extern {
-        fn zx_cprng_draw(buffer: *mut u8, len: usize, actual: *mut usize) -> i32;
-    }
-
-    fn getrandom(buf: &mut [u8]) -> Result<usize, i32> {
-        unsafe {
-            let mut actual = 0;
-            let status = zx_cprng_draw(buf.as_mut_ptr(), buf.len(), &mut actual);
-            if status == 0 {
-                Ok(actual)
-            } else {
-                Err(status)
-            }
-        }
+        fn zx_cprng_draw(buffer: *mut u8, len: usize);
     }
 
     pub fn fill_bytes(v: &mut [u8]) {
-        let mut buf = v;
-        while !buf.is_empty() {
-            let ret = getrandom(buf);
-            match ret {
-                Err(err) => {
-                    panic!("kernel zx_cprng_draw call failed! (returned {}, buf.len() {})",
-                        err, buf.len())
-                }
-                Ok(actual) => {
-                    let move_buf = buf;
-                    buf = &mut move_buf[(actual as usize)..];
-                }
-            }
-        }
+        unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }
     }
 }
diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs
index 51adbc24ae0..40453f9b8a1 100644
--- a/src/libstd/sys/unix/stack_overflow.rs
+++ b/src/libstd/sys/unix/stack_overflow.rs
@@ -57,9 +57,6 @@ mod imp {
     use sys_common::thread_info;
 
 
-    // This is initialized in init() and only read from after
-    static mut PAGE_SIZE: usize = 0;
-
     #[cfg(any(target_os = "linux", target_os = "android"))]
     unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
         #[repr(C)]
@@ -102,12 +99,12 @@ mod imp {
                                     _data: *mut libc::c_void) {
         use sys_common::util::report_overflow;
 
-        let guard = thread_info::stack_guard().unwrap_or(0);
+        let guard = thread_info::stack_guard().unwrap_or(0..0);
         let addr = siginfo_si_addr(info);
 
         // If the faulting address is within the guard page, then we print a
         // message saying so and abort.
-        if guard != 0 && guard - PAGE_SIZE <= addr && addr < guard {
+        if guard.start <= addr && addr < guard.end {
             report_overflow();
             rtabort!("stack overflow");
         } else {
@@ -123,8 +120,6 @@ mod imp {
     static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut();
 
     pub unsafe fn init() {
-        PAGE_SIZE = ::sys::os::page_size();
-
         let mut action: sigaction = mem::zeroed();
         action.sa_flags = SA_SIGINFO | SA_ONSTACK;
         action.sa_sigaction = signal_handler as sighandler_t;
diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs
index e9b3d4affc7..87ba2aef4f1 100644
--- a/src/libstd/sys/unix/stdio.rs
+++ b/src/libstd/sys/unix/stdio.rs
@@ -75,3 +75,7 @@ pub fn is_ebadf(err: &io::Error) -> bool {
 }
 
 pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
+
+pub fn stderr_prints_nothing() -> bool {
+    false
+}
diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs
index cb249af4254..f3a45d24657 100644
--- a/src/libstd/sys/unix/thread.rs
+++ b/src/libstd/sys/unix/thread.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use alloc::boxed::FnBox;
+use boxed::FnBox;
 use cmp;
 use ffi::CStr;
 use io;
@@ -49,7 +49,7 @@ unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t,
 }
 
 impl Thread {
-    pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
+    pub unsafe fn new<'a>(stack: usize, p: Box<dyn FnBox() + 'a>)
                           -> io::Result<Thread> {
         let p = box p;
         let mut native: libc::pthread_t = mem::zeroed();
@@ -138,7 +138,8 @@ impl Thread {
               target_os = "solaris",
               target_os = "haiku",
               target_os = "l4re",
-              target_os = "emscripten"))]
+              target_os = "emscripten",
+              target_os = "hermit"))]
     pub fn set_name(_name: &CStr) {
         // Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name.
     }
@@ -205,8 +206,11 @@ impl Drop for Thread {
           not(target_os = "solaris")))]
 #[cfg_attr(test, allow(dead_code))]
 pub mod guard {
-    pub unsafe fn current() -> Option<usize> { None }
-    pub unsafe fn init() -> Option<usize> { None }
+    use ops::Range;
+    pub type Guard = Range<usize>;
+    pub unsafe fn current() -> Option<Guard> { None }
+    pub unsafe fn init() -> Option<Guard> { None }
+    pub unsafe fn deinit() {}
 }
 
 
@@ -220,16 +224,45 @@ pub mod guard {
 #[cfg_attr(test, allow(dead_code))]
 pub mod guard {
     use libc;
-    use libc::mmap;
-    use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
+    use libc::{mmap, mprotect};
+    use libc::{PROT_NONE, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
+    use ops::Range;
     use sys::os;
 
-    #[cfg(any(target_os = "macos",
-              target_os = "bitrig",
-              target_os = "openbsd",
-              target_os = "solaris"))]
+    // This is initialized in init() and only read from after
+    static mut PAGE_SIZE: usize = 0;
+
+    pub type Guard = Range<usize>;
+
+    #[cfg(target_os = "solaris")]
+    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+        let mut current_stack: libc::stack_t = ::mem::zeroed();
+        assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
+        Some(current_stack.ss_sp)
+    }
+
+    #[cfg(target_os = "macos")]
+    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+        let stackaddr = libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize -
+             libc::pthread_get_stacksize_np(libc::pthread_self());
+        Some(stackaddr as *mut libc::c_void)
+    }
+
+    #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
     unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
-        current().map(|s| s as *mut libc::c_void)
+        let mut current_stack: libc::stack_t = ::mem::zeroed();
+        assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
+                                             &mut current_stack), 0);
+
+        let extra = if cfg!(target_os = "bitrig") {3} else {1} * PAGE_SIZE;
+        let stackaddr = if libc::pthread_main_np() == 1 {
+            // main thread
+            current_stack.ss_sp as usize - current_stack.ss_size + extra
+        } else {
+            // new thread
+            current_stack.ss_sp as usize - current_stack.ss_size
+        };
+        Some(stackaddr as *mut libc::c_void)
     }
 
     #[cfg(any(target_os = "android", target_os = "freebsd",
@@ -253,9 +286,10 @@ pub mod guard {
         ret
     }
 
-    pub unsafe fn init() -> Option<usize> {
-        let psize = os::page_size();
-        let mut stackaddr = get_stack_start()?;
+    // Precondition: PAGE_SIZE is initialized.
+    unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> {
+        assert!(PAGE_SIZE != 0);
+        let stackaddr = get_stack_start()?;
 
         // Ensure stackaddr is page aligned! A parent process might
         // have reset RLIMIT_STACK to be non-page aligned. The
@@ -263,11 +297,18 @@ pub mod guard {
         // stackaddr < stackaddr + stacksize, so if stackaddr is not
         // page-aligned, calculate the fix such that stackaddr <
         // new_page_aligned_stackaddr < stackaddr + stacksize
-        let remainder = (stackaddr as usize) % psize;
-        if remainder != 0 {
-            stackaddr = ((stackaddr as usize) + psize - remainder)
-                as *mut libc::c_void;
-        }
+        let remainder = (stackaddr as usize) % PAGE_SIZE;
+        Some(if remainder == 0 {
+            stackaddr
+        } else {
+            ((stackaddr as usize) + PAGE_SIZE - remainder) as *mut libc::c_void
+        })
+    }
+
+    pub unsafe fn init() -> Option<Guard> {
+        PAGE_SIZE = os::page_size();
+
+        let stackaddr = get_stack_start_aligned()?;
 
         if cfg!(target_os = "linux") {
             // Linux doesn't allocate the whole stack right away, and
@@ -280,60 +321,71 @@ pub mod guard {
             // Instead, we'll just note where we expect rlimit to start
             // faulting, so our handler can report "stack overflow", and
             // trust that the kernel's own stack guard will work.
-            Some(stackaddr as usize)
+            let stackaddr = stackaddr as usize;
+            Some(stackaddr - PAGE_SIZE..stackaddr)
         } else {
             // Reallocate the last page of the stack.
             // This ensures SIGBUS will be raised on
             // stack overflow.
-            let result = mmap(stackaddr, psize, PROT_NONE,
+            // Systems which enforce strict PAX MPROTECT do not allow
+            // to mprotect() a mapping with less restrictive permissions
+            // than the initial mmap() used, so we mmap() here with
+            // read/write permissions and only then mprotect() it to
+            // no permissions at all. See issue #50313.
+            let result = mmap(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE,
                               MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
-
             if result != stackaddr || result == MAP_FAILED {
                 panic!("failed to allocate a guard page");
             }
 
+            let result = mprotect(stackaddr, PAGE_SIZE, PROT_NONE);
+            if result != 0 {
+                panic!("failed to protect the guard page");
+            }
+
+            let guardaddr = stackaddr as usize;
             let offset = if cfg!(target_os = "freebsd") {
                 2
             } else {
                 1
             };
 
-            Some(stackaddr as usize + offset * psize)
+            Some(guardaddr..guardaddr + offset * PAGE_SIZE)
         }
     }
 
-    #[cfg(target_os = "solaris")]
-    pub unsafe fn current() -> Option<usize> {
-        let mut current_stack: libc::stack_t = ::mem::zeroed();
-        assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
-        Some(current_stack.ss_sp as usize)
-    }
-
-    #[cfg(target_os = "macos")]
-    pub unsafe fn current() -> Option<usize> {
-        Some((libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize -
-              libc::pthread_get_stacksize_np(libc::pthread_self())))
+    pub unsafe fn deinit() {
+        if !cfg!(target_os = "linux") {
+            if let Some(stackaddr) = get_stack_start_aligned() {
+                // Remove the protection on the guard page.
+                // FIXME: we cannot unmap the page, because when we mmap()
+                // above it may be already mapped by the OS, which we can't
+                // detect from mmap()'s return value. If we unmap this page,
+                // it will lead to failure growing stack size on platforms like
+                // macOS. Instead, just restore the page to a writable state.
+                // This ain't Linux, so we probably don't need to care about
+                // execstack.
+                let result = mprotect(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE);
+
+                if result != 0 {
+                    panic!("unable to reset the guard page");
+                }
+            }
+        }
     }
 
-    #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
-    pub unsafe fn current() -> Option<usize> {
-        let mut current_stack: libc::stack_t = ::mem::zeroed();
-        assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
-                                             &mut current_stack), 0);
-
-        let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size();
-        Some(if libc::pthread_main_np() == 1 {
-            // main thread
-            current_stack.ss_sp as usize - current_stack.ss_size + extra
-        } else {
-            // new thread
-            current_stack.ss_sp as usize - current_stack.ss_size
-        })
+    #[cfg(any(target_os = "macos",
+              target_os = "bitrig",
+              target_os = "openbsd",
+              target_os = "solaris"))]
+    pub unsafe fn current() -> Option<Guard> {
+        let stackaddr = get_stack_start()? as usize;
+        Some(stackaddr - PAGE_SIZE..stackaddr)
     }
 
     #[cfg(any(target_os = "android", target_os = "freebsd",
               target_os = "linux", target_os = "netbsd", target_os = "l4re"))]
-    pub unsafe fn current() -> Option<usize> {
+    pub unsafe fn current() -> Option<Guard> {
         let mut ret = None;
         let mut attr: libc::pthread_attr_t = ::mem::zeroed();
         assert_eq!(libc::pthread_attr_init(&mut attr), 0);
@@ -352,12 +404,23 @@ pub mod guard {
             assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
                                                    &mut size), 0);
 
+            let stackaddr = stackaddr as usize;
             ret = if cfg!(target_os = "freebsd") {
-                Some(stackaddr as usize - guardsize)
+                // FIXME does freebsd really fault *below* the guard addr?
+                let guardaddr = stackaddr - guardsize;
+                Some(guardaddr - PAGE_SIZE..guardaddr)
             } else if cfg!(target_os = "netbsd") {
-                Some(stackaddr as usize)
+                Some(stackaddr - guardsize..stackaddr)
+            } else if cfg!(all(target_os = "linux", target_env = "gnu")) {
+                // glibc used to include the guard area within the stack, as noted in the BUGS
+                // section of `man pthread_attr_getguardsize`.  This has been corrected starting
+                // with glibc 2.27, and in some distro backports, so the guard is now placed at the
+                // end (below) the stack.  There's no easy way for us to know which we have at
+                // runtime, so we'll just match any fault in the range right above or below the
+                // stack base to call that fault a stack overflow.
+                Some(stackaddr - guardsize..stackaddr + guardsize)
             } else {
-                Some(stackaddr as usize + guardsize)
+                Some(stackaddr..stackaddr + guardsize)
             };
         }
         assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs
index 83127935909..0b1fb726357 100644
--- a/src/libstd/sys/unix/time.rs
+++ b/src/libstd/sys/unix/time.rs
@@ -289,7 +289,7 @@ mod inner {
 
         pub fn sub_instant(&self, other: &Instant) -> Duration {
             self.t.sub_timespec(&other.t).unwrap_or_else(|_| {
-                panic!("other was less than the current instant")
+                panic!("specified instant was later than self")
             })
         }
 
@@ -345,9 +345,9 @@ mod inner {
         }
     }
 
-    #[cfg(not(target_os = "dragonfly"))]
+    #[cfg(not(any(target_os = "dragonfly", target_os = "hermit")))]
     pub type clock_t = libc::c_int;
-    #[cfg(target_os = "dragonfly")]
+    #[cfg(any(target_os = "dragonfly", target_os = "hermit"))]
     pub type clock_t = libc::c_ulong;
 
     fn now(clock: clock_t) -> Timespec {
diff --git a/src/libstd/sys/wasm/args.rs b/src/libstd/sys/wasm/args.rs
index d2a4a7b19d5..b3c6b671e80 100644
--- a/src/libstd/sys/wasm/args.rs
+++ b/src/libstd/sys/wasm/args.rs
@@ -10,8 +10,8 @@
 
 use ffi::OsString;
 use marker::PhantomData;
-use mem;
 use vec;
+use sys::ArgsSysCall;
 
 pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
     // On wasm these should always be null, so there's nothing for us to do here
@@ -21,38 +21,10 @@ pub unsafe fn cleanup() {
 }
 
 pub fn args() -> Args {
-    // When the runtime debugging is enabled we'll link to some extra runtime
-    // functions to actually implement this. These are for now just implemented
-    // in a node.js script but they're off by default as they're sort of weird
-    // in a web-wasm world.
-    if !super::DEBUG {
-        return Args {
-            iter: Vec::new().into_iter(),
-            _dont_send_or_sync_me: PhantomData,
-        }
-    }
-
-    // You'll find the definitions of these in `src/etc/wasm32-shim.js`. These
-    // are just meant for debugging and should not be relied on.
-    extern {
-        fn rust_wasm_args_count() -> usize;
-        fn rust_wasm_args_arg_size(a: usize) -> usize;
-        fn rust_wasm_args_arg_fill(a: usize, ptr: *mut u8);
-    }
-
-    unsafe {
-        let cnt = rust_wasm_args_count();
-        let mut v = Vec::with_capacity(cnt);
-        for i in 0..cnt {
-            let n = rust_wasm_args_arg_size(i);
-            let mut data = vec![0; n];
-            rust_wasm_args_arg_fill(i, data.as_mut_ptr());
-            v.push(mem::transmute::<Vec<u8>, OsString>(data));
-        }
-        Args {
-            iter: v.into_iter(),
-            _dont_send_or_sync_me: PhantomData,
-        }
+    let v = ArgsSysCall::perform();
+    Args {
+        iter: v.into_iter(),
+        _dont_send_or_sync_me: PhantomData,
     }
 }
 
diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs
index ba3d6a2813a..c02e5e809c8 100644
--- a/src/libstd/sys/wasm/mod.rs
+++ b/src/libstd/sys/wasm/mod.rs
@@ -26,17 +26,11 @@
 
 use io;
 use os::raw::c_char;
-
-// Right now the wasm backend doesn't even have the ability to print to the
-// console by default. Wasm can't import anything from JS! (you have to
-// explicitly provide it).
-//
-// Sometimes that's a real bummer, though, so this flag can be set to `true` to
-// enable calling various shims defined in `src/etc/wasm32-shim.js` which should
-// help receive debug output and see what's going on. In general this flag
-// currently controls "will we call out to our own defined shims in node.js",
-// and this flag should always be `false` for release builds.
-const DEBUG: bool = false;
+use ptr;
+use sys::os_str::Buf;
+use sys_common::{AsInner, FromInner};
+use ffi::{OsString, OsStr};
+use time::Duration;
 
 pub mod args;
 #[cfg(feature = "backtrace")]
@@ -92,7 +86,7 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize {
 }
 
 pub unsafe fn abort_internal() -> ! {
-    ::intrinsics::abort();
+    ExitSysCall::perform(1)
 }
 
 // We don't have randomness yet, but I totally used a random number generator to
@@ -103,3 +97,218 @@ pub unsafe fn abort_internal() -> ! {
 pub fn hashmap_random_keys() -> (u64, u64) {
     (1, 2)
 }
+
+// Implement a minimal set of system calls to enable basic IO
+pub enum SysCallIndex {
+    Read = 0,
+    Write = 1,
+    Exit = 2,
+    Args = 3,
+    GetEnv = 4,
+    SetEnv = 5,
+    Time = 6,
+}
+
+#[repr(C)]
+pub struct ReadSysCall {
+    fd: usize,
+    ptr: *mut u8,
+    len: usize,
+    result: usize,
+}
+
+impl ReadSysCall {
+    pub fn perform(fd: usize, buffer: &mut [u8]) -> usize {
+        let mut call_record = ReadSysCall {
+            fd,
+            len: buffer.len(),
+            ptr: buffer.as_mut_ptr(),
+            result: 0
+        };
+        if unsafe { syscall(SysCallIndex::Read, &mut call_record) } {
+            call_record.result
+        } else {
+            0
+        }
+    }
+}
+
+#[repr(C)]
+pub struct WriteSysCall {
+    fd: usize,
+    ptr: *const u8,
+    len: usize,
+}
+
+impl WriteSysCall {
+    pub fn perform(fd: usize, buffer: &[u8]) {
+        let mut call_record = WriteSysCall {
+            fd,
+            len: buffer.len(),
+            ptr: buffer.as_ptr()
+        };
+        unsafe { syscall(SysCallIndex::Write, &mut call_record); }
+    }
+}
+
+#[repr(C)]
+pub struct ExitSysCall {
+    code: usize,
+}
+
+impl ExitSysCall {
+    pub fn perform(code: usize) -> ! {
+        let mut call_record = ExitSysCall {
+            code
+        };
+        unsafe {
+            syscall(SysCallIndex::Exit, &mut call_record);
+            ::intrinsics::abort();
+        }
+    }
+}
+
+fn receive_buffer<E, F: FnMut(&mut [u8]) -> Result<usize, E>>(estimate: usize, mut f: F)
+    -> Result<Vec<u8>, E>
+{
+    let mut buffer = vec![0; estimate];
+    loop {
+        let result = f(&mut buffer)?;
+        if result <= buffer.len() {
+            buffer.truncate(result);
+            break;
+        }
+        buffer.resize(result, 0);
+    }
+    Ok(buffer)
+}
+
+#[repr(C)]
+pub struct ArgsSysCall {
+    ptr: *mut u8,
+    len: usize,
+    result: usize
+}
+
+impl ArgsSysCall {
+    pub fn perform() -> Vec<OsString> {
+        receive_buffer(1024, |buffer| -> Result<usize, !> {
+            let mut call_record = ArgsSysCall {
+                len: buffer.len(),
+                ptr: buffer.as_mut_ptr(),
+                result: 0
+            };
+            if unsafe { syscall(SysCallIndex::Args, &mut call_record) } {
+                Ok(call_record.result)
+            } else {
+                Ok(0)
+            }
+        })
+            .unwrap()
+            .split(|b| *b == 0)
+            .map(|s| FromInner::from_inner(Buf { inner: s.to_owned() }))
+            .collect()
+    }
+}
+
+#[repr(C)]
+pub struct GetEnvSysCall {
+    key_ptr: *const u8,
+    key_len: usize,
+    value_ptr: *mut u8,
+    value_len: usize,
+    result: usize
+}
+
+impl GetEnvSysCall {
+    pub fn perform(key: &OsStr) -> Option<OsString> {
+        let key_buf = &AsInner::as_inner(key).inner;
+        receive_buffer(64, |buffer| {
+            let mut call_record = GetEnvSysCall {
+                key_len: key_buf.len(),
+                key_ptr: key_buf.as_ptr(),
+                value_len: buffer.len(),
+                value_ptr: buffer.as_mut_ptr(),
+                result: !0usize
+            };
+            if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) } {
+                if call_record.result == !0usize {
+                    Err(())
+                } else {
+                    Ok(call_record.result)
+                }
+            } else {
+                Err(())
+            }
+        }).ok().map(|s| {
+            FromInner::from_inner(Buf { inner: s })
+        })
+    }
+}
+
+#[repr(C)]
+pub struct SetEnvSysCall {
+    key_ptr: *const u8,
+    key_len: usize,
+    value_ptr: *const u8,
+    value_len: usize
+}
+
+impl SetEnvSysCall {
+    pub fn perform(key: &OsStr, value: Option<&OsStr>) {
+        let key_buf = &AsInner::as_inner(key).inner;
+        let value_buf = value.map(|v| &AsInner::as_inner(v).inner);
+        let mut call_record = SetEnvSysCall {
+            key_len: key_buf.len(),
+            key_ptr: key_buf.as_ptr(),
+            value_len: value_buf.map(|v| v.len()).unwrap_or(!0usize),
+            value_ptr: value_buf.map(|v| v.as_ptr()).unwrap_or(ptr::null())
+        };
+        unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); }
+    }
+}
+
+pub enum TimeClock {
+    Monotonic = 0,
+    System = 1,
+}
+
+#[repr(C)]
+pub struct TimeSysCall {
+    clock: usize,
+    secs_hi: usize,
+    secs_lo: usize,
+    nanos: usize
+}
+
+impl TimeSysCall {
+    pub fn perform(clock: TimeClock) -> Duration {
+        let mut call_record = TimeSysCall {
+            clock: clock as usize,
+            secs_hi: 0,
+            secs_lo: 0,
+            nanos: 0
+        };
+        if unsafe { syscall(SysCallIndex::Time, &mut call_record) } {
+            Duration::new(
+                ((call_record.secs_hi as u64) << 32) | (call_record.secs_lo as u64),
+                call_record.nanos as u32
+            )
+        } else {
+            panic!("Time system call is not implemented by WebAssembly host");
+        }
+    }
+}
+
+unsafe fn syscall<T>(index: SysCallIndex, data: &mut T) -> bool {
+    #[cfg(feature = "wasm_syscall")]
+    extern {
+        #[no_mangle]
+        fn rust_wasm_syscall(index: usize, data: *mut Void) -> usize;
+    }
+
+    #[cfg(not(feature = "wasm_syscall"))]
+    unsafe fn rust_wasm_syscall(_index: usize, _data: *mut Void) -> usize { 0 }
+
+    rust_wasm_syscall(index as usize, data as *mut T as *mut Void) != 0
+}
diff --git a/src/libstd/sys/wasm/os.rs b/src/libstd/sys/wasm/os.rs
index c98030f7ebf..0cb991e19b0 100644
--- a/src/libstd/sys/wasm/os.rs
+++ b/src/libstd/sys/wasm/os.rs
@@ -8,23 +8,20 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use core::intrinsics;
-
 use error::Error as StdError;
 use ffi::{OsString, OsStr};
 use fmt;
 use io;
-use mem;
 use path::{self, PathBuf};
 use str;
-use sys::{unsupported, Void};
+use sys::{unsupported, Void, ExitSysCall, GetEnvSysCall, SetEnvSysCall};
 
 pub fn errno() -> i32 {
     0
 }
 
 pub fn error_string(_errno: i32) -> String {
-    format!("operation successful")
+    "operation successful".to_string()
 }
 
 pub fn getcwd() -> io::Result<PathBuf> {
@@ -87,36 +84,15 @@ pub fn env() -> Env {
 }
 
 pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
-    // If we're debugging the runtime then we actually probe node.js to ask for
-    // the value of environment variables to help provide inputs to programs.
-    // The `extern` shims here are defined in `src/etc/wasm32-shim.js` and are
-    // intended for debugging only, you should not rely on them.
-    if !super::DEBUG {
-        return Ok(None)
-    }
-
-    extern {
-        fn rust_wasm_getenv_len(k: *const u8, kl: usize) -> isize;
-        fn rust_wasm_getenv_data(k: *const u8, kl: usize, v: *mut u8);
-    }
-    unsafe {
-        let k: &[u8] = mem::transmute(k);
-        let n = rust_wasm_getenv_len(k.as_ptr(), k.len());
-        if n == -1 {
-            return Ok(None)
-        }
-        let mut data = vec![0; n as usize];
-        rust_wasm_getenv_data(k.as_ptr(), k.len(), data.as_mut_ptr());
-        Ok(Some(mem::transmute(data)))
-    }
+    Ok(GetEnvSysCall::perform(k))
 }
 
-pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> {
-    unsupported()
+pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
+    Ok(SetEnvSysCall::perform(k, Some(v)))
 }
 
-pub fn unsetenv(_n: &OsStr) -> io::Result<()> {
-    unsupported()
+pub fn unsetenv(k: &OsStr) -> io::Result<()> {
+    Ok(SetEnvSysCall::perform(k, None))
 }
 
 pub fn temp_dir() -> PathBuf {
@@ -128,7 +104,7 @@ pub fn home_dir() -> Option<PathBuf> {
 }
 
 pub fn exit(_code: i32) -> ! {
-    unsafe { intrinsics::abort() }
+    ExitSysCall::perform(_code as isize as usize)
 }
 
 pub fn getpid() -> u32 {
diff --git a/src/libstd/sys/wasm/os_str.rs b/src/libstd/sys/wasm/os_str.rs
index 543c22ebe18..e0da5bdf36c 100644
--- a/src/libstd/sys/wasm/os_str.rs
+++ b/src/libstd/sys/wasm/os_str.rs
@@ -19,7 +19,7 @@ use rc::Rc;
 use sync::Arc;
 use sys_common::{AsInner, IntoInner};
 use sys_common::bytestring::debug_fmt_bytestring;
-use std_unicode::lossy::Utf8Lossy;
+use core::str::lossy::Utf8Lossy;
 
 #[derive(Clone, Hash)]
 pub struct Buf {
@@ -104,6 +104,11 @@ impl Buf {
         self.inner.shrink_to_fit()
     }
 
+    #[inline]
+    pub fn shrink_to(&mut self, min_capacity: usize) {
+        self.inner.shrink_to(min_capacity)
+    }
+
     pub fn as_slice(&self) -> &Slice {
         unsafe { mem::transmute(&*self.inner) }
     }
diff --git a/src/libstd/sys/wasm/process.rs b/src/libstd/sys/wasm/process.rs
index f3f5de350f1..433e9cec7c8 100644
--- a/src/libstd/sys/wasm/process.rs
+++ b/src/libstd/sys/wasm/process.rs
@@ -129,6 +129,18 @@ impl fmt::Display for ExitStatus {
     }
 }
 
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(bool);
+
+impl ExitCode {
+    pub const SUCCESS: ExitCode = ExitCode(false);
+    pub const FAILURE: ExitCode = ExitCode(true);
+
+    pub fn as_i32(&self) -> i32 {
+        self.0 as i32
+    }
+}
+
 pub struct Process(Void);
 
 impl Process {
diff --git a/src/libstd/sys/wasm/rwlock.rs b/src/libstd/sys/wasm/rwlock.rs
index 8b06f541674..6516010af47 100644
--- a/src/libstd/sys/wasm/rwlock.rs
+++ b/src/libstd/sys/wasm/rwlock.rs
@@ -30,7 +30,7 @@ impl RWLock {
         if *mode >= 0 {
             *mode += 1;
         } else {
-            panic!("rwlock locked for writing");
+            rtabort!("rwlock locked for writing");
         }
     }
 
@@ -51,7 +51,7 @@ impl RWLock {
         if *mode == 0 {
             *mode = -1;
         } else {
-            panic!("rwlock locked for reading")
+            rtabort!("rwlock locked for reading")
         }
     }
 
diff --git a/src/libstd/sys/wasm/stdio.rs b/src/libstd/sys/wasm/stdio.rs
index 0f75f240251..023f29576a2 100644
--- a/src/libstd/sys/wasm/stdio.rs
+++ b/src/libstd/sys/wasm/stdio.rs
@@ -9,19 +9,19 @@
 // except according to those terms.
 
 use io;
-use sys::{Void, unsupported};
+use sys::{ReadSysCall, WriteSysCall};
 
-pub struct Stdin(Void);
+pub struct Stdin;
 pub struct Stdout;
 pub struct Stderr;
 
 impl Stdin {
     pub fn new() -> io::Result<Stdin> {
-        unsupported()
+        Ok(Stdin)
     }
 
-    pub fn read(&self, _data: &mut [u8]) -> io::Result<usize> {
-        match self.0 {}
+    pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
+        Ok(ReadSysCall::perform(0, data))
     }
 }
 
@@ -31,19 +31,7 @@ impl Stdout {
     }
 
     pub fn write(&self, data: &[u8]) -> io::Result<usize> {
-        // If runtime debugging is enabled at compile time we'll invoke some
-        // runtime functions that are defined in our src/etc/wasm32-shim.js
-        // debugging script. Note that this ffi function call is intended
-        // *purely* for debugging only and should not be relied upon.
-        if !super::DEBUG {
-            return unsupported()
-        }
-        extern {
-            fn rust_wasm_write_stdout(data: *const u8, len: usize);
-        }
-        unsafe {
-            rust_wasm_write_stdout(data.as_ptr(), data.len())
-        }
+        WriteSysCall::perform(1, data);
         Ok(data.len())
     }
 
@@ -58,16 +46,7 @@ impl Stderr {
     }
 
     pub fn write(&self, data: &[u8]) -> io::Result<usize> {
-        // See comments in stdout for what's going on here.
-        if !super::DEBUG {
-            return unsupported()
-        }
-        extern {
-            fn rust_wasm_write_stderr(data: *const u8, len: usize);
-        }
-        unsafe {
-            rust_wasm_write_stderr(data.as_ptr(), data.len())
-        }
+        WriteSysCall::perform(2, data);
         Ok(data.len())
     }
 
@@ -90,3 +69,7 @@ pub const STDIN_BUF_SIZE: usize = 0;
 pub fn is_ebadf(_err: &io::Error) -> bool {
     true
 }
+
+pub fn stderr_prints_nothing() -> bool {
+    !cfg!(feature = "wasm_syscall")
+}
diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs
index 13980e0cc19..8173a624211 100644
--- a/src/libstd/sys/wasm/thread.rs
+++ b/src/libstd/sys/wasm/thread.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use alloc::boxed::FnBox;
+use boxed::FnBox;
 use ffi::CStr;
 use io;
 use sys::{unsupported, Void};
@@ -19,7 +19,7 @@ pub struct Thread(Void);
 pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
 
 impl Thread {
-    pub unsafe fn new<'a>(_stack: usize, _p: Box<FnBox() + 'a>)
+    pub unsafe fn new<'a>(_stack: usize, _p: Box<dyn FnBox() + 'a>)
         -> io::Result<Thread>
     {
         unsupported()
@@ -43,6 +43,8 @@ impl Thread {
 }
 
 pub mod guard {
-    pub unsafe fn current() -> Option<usize> { None }
-    pub unsafe fn init() -> Option<usize> { None }
+    pub type Guard = !;
+    pub unsafe fn current() -> Option<Guard> { None }
+    pub unsafe fn init() -> Option<Guard> { None }
+    pub unsafe fn deinit() {}
 }
diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/wasm/time.rs
index c269def98f6..e52435e6339 100644
--- a/src/libstd/sys/wasm/time.rs
+++ b/src/libstd/sys/wasm/time.rs
@@ -8,56 +8,50 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use fmt;
 use time::Duration;
+use sys::{TimeSysCall, TimeClock};
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub struct Instant;
+pub struct Instant(Duration);
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct SystemTime;
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct SystemTime(Duration);
 
-pub const UNIX_EPOCH: SystemTime = SystemTime;
+pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
 
 impl Instant {
     pub fn now() -> Instant {
-        panic!("not supported on web assembly");
+        Instant(TimeSysCall::perform(TimeClock::Monotonic))
     }
 
-    pub fn sub_instant(&self, _other: &Instant) -> Duration {
-        panic!("can't sub yet");
+    pub fn sub_instant(&self, other: &Instant) -> Duration {
+        self.0 - other.0
     }
 
-    pub fn add_duration(&self, _other: &Duration) -> Instant {
-        panic!("can't add yet");
+    pub fn add_duration(&self, other: &Duration) -> Instant {
+        Instant(self.0 + *other)
     }
 
-    pub fn sub_duration(&self, _other: &Duration) -> Instant {
-        panic!("can't sub yet");
+    pub fn sub_duration(&self, other: &Duration) -> Instant {
+        Instant(self.0 - *other)
     }
 }
 
 impl SystemTime {
     pub fn now() -> SystemTime {
-        panic!("not supported on web assembly");
+        SystemTime(TimeSysCall::perform(TimeClock::System))
     }
 
-    pub fn sub_time(&self, _other: &SystemTime)
+    pub fn sub_time(&self, other: &SystemTime)
                     -> Result<Duration, Duration> {
-        panic!()
-    }
-
-    pub fn add_duration(&self, _other: &Duration) -> SystemTime {
-        panic!()
+        self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
     }
 
-    pub fn sub_duration(&self, _other: &Duration) -> SystemTime {
-        panic!()
+    pub fn add_duration(&self, other: &Duration) -> SystemTime {
+        SystemTime(self.0 + *other)
     }
-}
 
-impl fmt::Debug for SystemTime {
-    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
-        panic!()
+    pub fn sub_duration(&self, other: &Duration) -> SystemTime {
+        SystemTime(self.0 - *other)
     }
 }
diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs
index 176891fff23..f64cae810b9 100644
--- a/src/libstd/sys/windows/backtrace/mod.rs
+++ b/src/libstd/sys/windows/backtrace/mod.rs
@@ -46,111 +46,281 @@ mod printing;
 #[path = "backtrace_gnu.rs"]
 pub mod gnu;
 
-pub use self::printing::{resolve_symname, foreach_symbol_fileline};
+pub use self::printing::{foreach_symbol_fileline, resolve_symname};
+use self::printing::{load_printing_fns_64, load_printing_fns_ex};
 
-pub fn unwind_backtrace(frames: &mut [Frame])
-    -> io::Result<(usize, BacktraceContext)>
-{
+pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
     let dbghelp = DynamicLibrary::open("dbghelp.dll")?;
 
     // Fetch the symbols necessary from dbghelp.dll
     let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
     let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?;
-    let StackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn)?;
+
+    // StackWalkEx might not be present and we'll fall back to StackWalk64
+    let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) {
+        Ok(StackWalkEx) => {
+            StackWalkVariant::StackWalkEx(StackWalkEx, load_printing_fns_ex(&dbghelp)?)
+        }
+        Err(e) => match sym!(dbghelp, "StackWalk64", StackWalk64Fn) {
+            Ok(StackWalk64) => {
+                StackWalkVariant::StackWalk64(StackWalk64, load_printing_fns_64(&dbghelp)?)
+            }
+            Err(..) => return Err(e),
+        },
+    };
 
     // Allocate necessary structures for doing the stack walk
     let process = unsafe { c::GetCurrentProcess() };
-    let thread = unsafe { c::GetCurrentThread() };
-    let mut context: c::CONTEXT = unsafe { mem::zeroed() };
-    unsafe { c::RtlCaptureContext(&mut context) };
-    let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() };
-    let image = init_frame(&mut frame, &context);
 
     let backtrace_context = BacktraceContext {
         handle: process,
         SymCleanup,
+        StackWalkVariant: sw_var,
         dbghelp,
     };
 
     // Initialize this process's symbols
     let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) };
     if ret != c::TRUE {
-        return Ok((0, backtrace_context))
+        return Ok((0, backtrace_context));
     }
 
     // And now that we're done with all the setup, do the stack walking!
-    // Start from -1 to avoid printing this stack frame, which will
-    // always be exactly the same.
+    match backtrace_context.StackWalkVariant {
+        StackWalkVariant::StackWalkEx(StackWalkEx, _) => {
+            set_frames(StackWalkEx, frames).map(|i| (i, backtrace_context))
+        }
+
+        StackWalkVariant::StackWalk64(StackWalk64, _) => {
+            set_frames(StackWalk64, frames).map(|i| (i, backtrace_context))
+        }
+    }
+}
+
+fn set_frames<W: StackWalker>(StackWalk: W, frames: &mut [Frame]) -> io::Result<usize> {
+    let process = unsafe { c::GetCurrentProcess() };
+    let thread = unsafe { c::GetCurrentProcess() };
+    let mut context: c::CONTEXT = unsafe { mem::zeroed() };
+    unsafe { c::RtlCaptureContext(&mut context) };
+    let mut frame = W::Item::new();
+    let image = frame.init(&context);
+
     let mut i = 0;
-    unsafe {
-        while i < frames.len() &&
-              StackWalk64(image, process, thread, &mut frame, &mut context,
-                          ptr::null_mut(),
-                          ptr::null_mut(),
-                          ptr::null_mut(),
-                          ptr::null_mut()) == c::TRUE
-        {
-            let addr = frame.AddrPC.Offset;
-            if addr == frame.AddrReturn.Offset || addr == 0 ||
-               frame.AddrReturn.Offset == 0 { break }
-
-            frames[i] = Frame {
-                symbol_addr: (addr - 1) as *const u8,
-                exact_position: (addr - 1) as *const u8,
-            };
-            i += 1;
+    while i < frames.len()
+        && StackWalk.walk(image, process, thread, &mut frame, &mut context) == c::TRUE
+    {
+        let addr = frame.get_addr();
+        frames[i] = Frame {
+            symbol_addr: addr,
+            exact_position: addr,
+            inline_context: 0,
+        };
+
+        i += 1
+    }
+    Ok(i)
+}
+
+type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL;
+type SymCleanupFn = unsafe extern "system" fn(c::HANDLE) -> c::BOOL;
+
+type StackWalkExFn = unsafe extern "system" fn(
+    c::DWORD,
+    c::HANDLE,
+    c::HANDLE,
+    *mut c::STACKFRAME_EX,
+    *mut c::CONTEXT,
+    *mut c_void,
+    *mut c_void,
+    *mut c_void,
+    *mut c_void,
+    c::DWORD,
+) -> c::BOOL;
+
+type StackWalk64Fn = unsafe extern "system" fn(
+    c::DWORD,
+    c::HANDLE,
+    c::HANDLE,
+    *mut c::STACKFRAME64,
+    *mut c::CONTEXT,
+    *mut c_void,
+    *mut c_void,
+    *mut c_void,
+    *mut c_void,
+) -> c::BOOL;
+
+trait StackWalker {
+    type Item: StackFrame;
+
+    fn walk(&self, c::DWORD, c::HANDLE, c::HANDLE, &mut Self::Item, &mut c::CONTEXT) -> c::BOOL;
+}
+
+impl StackWalker for StackWalkExFn {
+    type Item = c::STACKFRAME_EX;
+    fn walk(
+        &self,
+        image: c::DWORD,
+        process: c::HANDLE,
+        thread: c::HANDLE,
+        frame: &mut Self::Item,
+        context: &mut c::CONTEXT,
+    ) -> c::BOOL {
+        unsafe {
+            self(
+                image,
+                process,
+                thread,
+                frame,
+                context,
+                ptr::null_mut(),
+                ptr::null_mut(),
+                ptr::null_mut(),
+                ptr::null_mut(),
+                0,
+            )
+        }
+    }
+}
+
+impl StackWalker for StackWalk64Fn {
+    type Item = c::STACKFRAME64;
+    fn walk(
+        &self,
+        image: c::DWORD,
+        process: c::HANDLE,
+        thread: c::HANDLE,
+        frame: &mut Self::Item,
+        context: &mut c::CONTEXT,
+    ) -> c::BOOL {
+        unsafe {
+            self(
+                image,
+                process,
+                thread,
+                frame,
+                context,
+                ptr::null_mut(),
+                ptr::null_mut(),
+                ptr::null_mut(),
+                ptr::null_mut(),
+            )
         }
     }
+}
+
+trait StackFrame {
+    fn new() -> Self;
+    fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD;
+    fn get_addr(&self) -> *const u8;
+}
+
+impl StackFrame for c::STACKFRAME_EX {
+    fn new() -> c::STACKFRAME_EX {
+        unsafe { mem::zeroed() }
+    }
+
+    #[cfg(target_arch = "x86")]
+    fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+        self.AddrPC.Offset = ctx.Eip as u64;
+        self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        self.AddrStack.Offset = ctx.Esp as u64;
+        self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        self.AddrFrame.Offset = ctx.Ebp as u64;
+        self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        c::IMAGE_FILE_MACHINE_I386
+    }
+
+    #[cfg(target_arch = "x86_64")]
+    fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+        self.AddrPC.Offset = ctx.Rip as u64;
+        self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        self.AddrStack.Offset = ctx.Rsp as u64;
+        self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        self.AddrFrame.Offset = ctx.Rbp as u64;
+        self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        c::IMAGE_FILE_MACHINE_AMD64
+    }
+
+    #[cfg(target_arch = "aarch64")]
+    fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+        self.AddrPC.Offset = ctx.Pc as u64;
+        self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        self.AddrStack.Offset = ctx.Sp as u64;
+        self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        self.AddrFrame.Offset = ctx.Fp as u64;
+        self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        c::IMAGE_FILE_MACHINE_ARM64
+    }
 
-    Ok((i, backtrace_context))
+    fn get_addr(&self) -> *const u8 {
+        (self.AddrPC.Offset - 1) as *const u8
+    }
 }
 
-type SymInitializeFn =
-    unsafe extern "system" fn(c::HANDLE, *mut c_void,
-                              c::BOOL) -> c::BOOL;
-type SymCleanupFn =
-    unsafe extern "system" fn(c::HANDLE) -> c::BOOL;
-
-type StackWalk64Fn =
-    unsafe extern "system" fn(c::DWORD, c::HANDLE, c::HANDLE,
-                              *mut c::STACKFRAME64, *mut c::CONTEXT,
-                              *mut c_void, *mut c_void,
-                              *mut c_void, *mut c_void) -> c::BOOL;
-
-#[cfg(target_arch = "x86")]
-fn init_frame(frame: &mut c::STACKFRAME64,
-              ctx: &c::CONTEXT) -> c::DWORD {
-    frame.AddrPC.Offset = ctx.Eip as u64;
-    frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
-    frame.AddrStack.Offset = ctx.Esp as u64;
-    frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
-    frame.AddrFrame.Offset = ctx.Ebp as u64;
-    frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
-    c::IMAGE_FILE_MACHINE_I386
+impl StackFrame for c::STACKFRAME64 {
+    fn new() -> c::STACKFRAME64 {
+        unsafe { mem::zeroed() }
+    }
+
+    #[cfg(target_arch = "x86")]
+    fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+        self.AddrPC.Offset = ctx.Eip as u64;
+        self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        self.AddrStack.Offset = ctx.Esp as u64;
+        self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        self.AddrFrame.Offset = ctx.Ebp as u64;
+        self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        c::IMAGE_FILE_MACHINE_I386
+    }
+
+    #[cfg(target_arch = "x86_64")]
+    fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+        self.AddrPC.Offset = ctx.Rip as u64;
+        self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        self.AddrStack.Offset = ctx.Rsp as u64;
+        self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        self.AddrFrame.Offset = ctx.Rbp as u64;
+        self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        c::IMAGE_FILE_MACHINE_AMD64
+    }
+
+    #[cfg(target_arch = "aarch64")]
+    fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+        self.AddrPC.Offset = ctx.Pc as u64;
+        self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        self.AddrStack.Offset = ctx.Sp as u64;
+        self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        self.AddrFrame.Offset = ctx.Fp as u64;
+        self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        c::IMAGE_FILE_MACHINE_ARM64
+    }
+
+    fn get_addr(&self) -> *const u8 {
+        (self.AddrPC.Offset - 1) as *const u8
+    }
 }
 
-#[cfg(target_arch = "x86_64")]
-fn init_frame(frame: &mut c::STACKFRAME64,
-              ctx: &c::CONTEXT) -> c::DWORD {
-    frame.AddrPC.Offset = ctx.Rip as u64;
-    frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
-    frame.AddrStack.Offset = ctx.Rsp as u64;
-    frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
-    frame.AddrFrame.Offset = ctx.Rbp as u64;
-    frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
-    c::IMAGE_FILE_MACHINE_AMD64
+enum StackWalkVariant {
+    StackWalkEx(StackWalkExFn, printing::PrintingFnsEx),
+    StackWalk64(StackWalk64Fn, printing::PrintingFns64),
 }
 
 pub struct BacktraceContext {
     handle: c::HANDLE,
     SymCleanup: SymCleanupFn,
     // Only used in printing for msvc and not gnu
+    // The gnu version is effectively a ZST dummy.
+    #[allow(dead_code)]
+    StackWalkVariant: StackWalkVariant,
+    // keeping DynamycLibrary loaded until its functions no longer needed
     #[allow(dead_code)]
     dbghelp: DynamicLibrary,
 }
 
 impl Drop for BacktraceContext {
     fn drop(&mut self) {
-        unsafe { (self.SymCleanup)(self.handle); }
+        unsafe {
+            (self.SymCleanup)(self.handle);
+        }
     }
 }
diff --git a/src/libstd/sys/windows/backtrace/printing/mod.rs b/src/libstd/sys/windows/backtrace/printing/mod.rs
index 3e566f6e2bd..251d5028aea 100644
--- a/src/libstd/sys/windows/backtrace/printing/mod.rs
+++ b/src/libstd/sys/windows/backtrace/printing/mod.rs
@@ -15,6 +15,20 @@ mod printing;
 #[cfg(target_env = "gnu")]
 mod printing {
     pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
+
+    // dummy functions to mirror those present in msvc version.
+    use sys::dynamic_lib::DynamicLibrary;
+    use io;
+    pub struct PrintingFnsEx {}
+    pub struct PrintingFns64 {}
+    pub fn load_printing_fns_ex(_: &DynamicLibrary) -> io::Result<PrintingFnsEx> {
+        Ok(PrintingFnsEx{})
+    }
+    pub fn load_printing_fns_64(_: &DynamicLibrary) -> io::Result<PrintingFns64> {
+        Ok(PrintingFns64{})
+    }
 }
 
 pub use self::printing::{foreach_symbol_fileline, resolve_symname};
+pub use self::printing::{load_printing_fns_ex, load_printing_fns_64,
+                         PrintingFnsEx, PrintingFns64};
diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs
index 5a49b77af8e..c8b946bf13a 100644
--- a/src/libstd/sys/windows/backtrace/printing/msvc.rs
+++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs
@@ -10,27 +10,108 @@
 
 use ffi::CStr;
 use io;
-use libc::{c_ulong, c_char};
+use libc::{c_char, c_ulong};
 use mem;
-use sys::c;
 use sys::backtrace::BacktraceContext;
+use sys::backtrace::StackWalkVariant;
+use sys::c;
+use sys::dynamic_lib::DynamicLibrary;
 use sys_common::backtrace::Frame;
 
+// Structs holding printing functions and loaders for them
+// Two versions depending on whether dbghelp.dll has StackWalkEx or not
+// (the former being in newer Windows versions, the older being in Win7 and before)
+pub struct PrintingFnsEx {
+    resolve_symname: SymFromInlineContextFn,
+    sym_get_line: SymGetLineFromInlineContextFn,
+}
+pub struct PrintingFns64 {
+    resolve_symname: SymFromAddrFn,
+    sym_get_line: SymGetLineFromAddr64Fn,
+}
+
+pub fn load_printing_fns_ex(dbghelp: &DynamicLibrary) -> io::Result<PrintingFnsEx> {
+    Ok(PrintingFnsEx {
+        resolve_symname: sym!(dbghelp, "SymFromInlineContext", SymFromInlineContextFn)?,
+        sym_get_line: sym!(
+            dbghelp,
+            "SymGetLineFromInlineContext",
+            SymGetLineFromInlineContextFn
+        )?,
+    })
+}
+pub fn load_printing_fns_64(dbghelp: &DynamicLibrary) -> io::Result<PrintingFns64> {
+    Ok(PrintingFns64 {
+        resolve_symname: sym!(dbghelp, "SymFromAddr", SymFromAddrFn)?,
+        sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64", SymGetLineFromAddr64Fn)?,
+    })
+}
+
 type SymFromAddrFn =
-    unsafe extern "system" fn(c::HANDLE, u64, *mut u64,
-                              *mut c::SYMBOL_INFO) -> c::BOOL;
+    unsafe extern "system" fn(c::HANDLE, u64, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
+type SymFromInlineContextFn =
+    unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
+
 type SymGetLineFromAddr64Fn =
-    unsafe extern "system" fn(c::HANDLE, u64, *mut u32,
-                              *mut c::IMAGEHLP_LINE64) -> c::BOOL;
+    unsafe extern "system" fn(c::HANDLE, u64, *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL;
+type SymGetLineFromInlineContextFn = unsafe extern "system" fn(
+    c::HANDLE,
+    u64,
+    c::ULONG,
+    u64,
+    *mut c::DWORD,
+    *mut c::IMAGEHLP_LINE64,
+) -> c::BOOL;
 
 /// Converts a pointer to symbol to its string value.
-pub fn resolve_symname<F>(frame: Frame,
-                          callback: F,
-                          context: &BacktraceContext) -> io::Result<()>
-    where F: FnOnce(Option<&str>) -> io::Result<()>
+pub fn resolve_symname<F>(frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()>
+where
+    F: FnOnce(Option<&str>) -> io::Result<()>,
 {
-    let SymFromAddr = sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn)?;
+    match context.StackWalkVariant {
+        StackWalkVariant::StackWalkEx(_, ref fns) => resolve_symname_internal(
+            |process: c::HANDLE,
+             symbol_address: u64,
+             inline_context: c::ULONG,
+             info: *mut c::SYMBOL_INFO| unsafe {
+                let mut displacement = 0u64;
+                (fns.resolve_symname)(
+                    process,
+                    symbol_address,
+                    inline_context,
+                    &mut displacement,
+                    info,
+                )
+            },
+            frame,
+            callback,
+            context,
+        ),
+        StackWalkVariant::StackWalk64(_, ref fns) => resolve_symname_internal(
+            |process: c::HANDLE,
+             symbol_address: u64,
+             _inline_context: c::ULONG,
+             info: *mut c::SYMBOL_INFO| unsafe {
+                let mut displacement = 0u64;
+                (fns.resolve_symname)(process, symbol_address, &mut displacement, info)
+            },
+            frame,
+            callback,
+            context,
+        ),
+    }
+}
 
+fn resolve_symname_internal<F, R>(
+    mut symbol_resolver: R,
+    frame: Frame,
+    callback: F,
+    context: &BacktraceContext,
+) -> io::Result<()>
+where
+    F: FnOnce(Option<&str>) -> io::Result<()>,
+    R: FnMut(c::HANDLE, u64, c::ULONG, *mut c::SYMBOL_INFO) -> c::BOOL,
+{
     unsafe {
         let mut info: c::SYMBOL_INFO = mem::zeroed();
         info.MaxNameLen = c::MAX_SYM_NAME as c_ulong;
@@ -39,13 +120,22 @@ pub fn resolve_symname<F>(frame: Frame,
         // due to struct alignment.
         info.SizeOfStruct = 88;
 
-        let mut displacement = 0u64;
-        let ret = SymFromAddr(context.handle,
-                              frame.symbol_addr as u64,
-                              &mut displacement,
-                              &mut info);
-
-        let symname = if ret == c::TRUE {
+        let ret = symbol_resolver(
+            context.handle,
+            frame.symbol_addr as u64,
+            frame.inline_context,
+            &mut info,
+        );
+        let valid_range = if ret == c::TRUE && frame.symbol_addr as usize >= info.Address as usize {
+            if info.Size != 0 {
+                (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize
+            } else {
+                true
+            }
+        } else {
+            false
+        };
+        let symname = if valid_range {
             let ptr = info.Name.as_ptr() as *const c_char;
             CStr::from_ptr(ptr).to_str().ok()
         } else {
@@ -55,28 +145,72 @@ pub fn resolve_symname<F>(frame: Frame,
     }
 }
 
-pub fn foreach_symbol_fileline<F>(frame: Frame,
-                                  mut f: F,
-                                  context: &BacktraceContext)
-    -> io::Result<bool>
-    where F: FnMut(&[u8], u32) -> io::Result<()>
+pub fn foreach_symbol_fileline<F>(
+    frame: Frame,
+    callback: F,
+    context: &BacktraceContext,
+) -> io::Result<bool>
+where
+    F: FnMut(&[u8], u32) -> io::Result<()>,
 {
-    let SymGetLineFromAddr64 = sym!(&context.dbghelp,
-                                    "SymGetLineFromAddr64",
-                                    SymGetLineFromAddr64Fn)?;
+    match context.StackWalkVariant {
+        StackWalkVariant::StackWalkEx(_, ref fns) => foreach_symbol_fileline_iternal(
+            |process: c::HANDLE,
+             frame_address: u64,
+             inline_context: c::ULONG,
+             line: *mut c::IMAGEHLP_LINE64| unsafe {
+                let mut displacement = 0u32;
+                (fns.sym_get_line)(
+                    process,
+                    frame_address,
+                    inline_context,
+                    0,
+                    &mut displacement,
+                    line,
+                )
+            },
+            frame,
+            callback,
+            context,
+        ),
+        StackWalkVariant::StackWalk64(_, ref fns) => foreach_symbol_fileline_iternal(
+            |process: c::HANDLE,
+             frame_address: u64,
+             _inline_context: c::ULONG,
+             line: *mut c::IMAGEHLP_LINE64| unsafe {
+                let mut displacement = 0u32;
+                (fns.sym_get_line)(process, frame_address, &mut displacement, line)
+            },
+            frame,
+            callback,
+            context,
+        ),
+    }
+}
 
+fn foreach_symbol_fileline_iternal<F, G>(
+    mut line_getter: G,
+    frame: Frame,
+    mut callback: F,
+    context: &BacktraceContext,
+) -> io::Result<bool>
+where
+    F: FnMut(&[u8], u32) -> io::Result<()>,
+    G: FnMut(c::HANDLE, u64, c::ULONG, *mut c::IMAGEHLP_LINE64) -> c::BOOL,
+{
     unsafe {
         let mut line: c::IMAGEHLP_LINE64 = mem::zeroed();
         line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32;
 
-        let mut displacement = 0u32;
-        let ret = SymGetLineFromAddr64(context.handle,
-                                       frame.exact_position as u64,
-                                       &mut displacement,
-                                       &mut line);
+        let ret = line_getter(
+            context.handle,
+            frame.exact_position as u64,
+            frame.inline_context,
+            &mut line,
+        );
         if ret == c::TRUE {
             let name = CStr::from_ptr(line.Filename).to_bytes();
-            f(name, line.LineNumber as u32)?;
+            callback(name, line.LineNumber as u32)?;
         }
         Ok(false)
     }
diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs
index 66b44f1402f..e514a56dcc4 100644
--- a/src/libstd/sys/windows/c.rs
+++ b/src/libstd/sys/windows/c.rs
@@ -280,6 +280,9 @@ pub const IMAGE_FILE_MACHINE_I386: DWORD = 0x014c;
 #[cfg(target_arch = "x86_64")]
 #[cfg(feature = "backtrace")]
 pub const IMAGE_FILE_MACHINE_AMD64: DWORD = 0x8664;
+#[cfg(target_arch = "aarch64")]
+#[cfg(feature = "backtrace")]
+pub const IMAGE_FILE_MACHINE_ARM64: DWORD = 0xAA64;
 
 pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
 pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
@@ -296,6 +299,8 @@ pub const PIPE_READMODE_BYTE: DWORD = 0x00000000;
 
 pub const FD_SETSIZE: usize = 64;
 
+pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000;
+
 #[repr(C)]
 #[cfg(not(target_pointer_width = "64"))]
 pub struct WSADATA {
@@ -619,6 +624,24 @@ pub struct ADDRESS64 {
 
 #[repr(C)]
 #[cfg(feature = "backtrace")]
+pub struct STACKFRAME_EX {
+    pub AddrPC: ADDRESS64,
+    pub AddrReturn: ADDRESS64,
+    pub AddrFrame: ADDRESS64,
+    pub AddrStack: ADDRESS64,
+    pub AddrBStore: ADDRESS64,
+    pub FuncTableEntry: *mut c_void,
+    pub Params: [u64; 4],
+    pub Far: BOOL,
+    pub Virtual: BOOL,
+    pub Reserved: [u64; 3],
+    pub KdHelp: KDHELP64,
+    pub StackFrameSize: DWORD,
+    pub InlineFrameContext: DWORD,
+}
+
+#[repr(C)]
+#[cfg(feature = "backtrace")]
 pub struct STACKFRAME64 {
     pub AddrPC: ADDRESS64,
     pub AddrReturn: ADDRESS64,
@@ -771,9 +794,68 @@ pub struct FLOATING_SAVE_AREA {
 // will not appear in the final documentation. This should be also defined for
 // other architectures supported by Windows such as ARM, and for historical
 // interest, maybe MIPS and PowerPC as well.
-#[cfg(all(dox, not(any(target_arch = "x86_64", target_arch = "x86"))))]
+#[cfg(all(dox, not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))))]
 pub enum CONTEXT {}
 
+#[cfg(target_arch = "aarch64")]
+pub const ARM64_MAX_BREAKPOINTS: usize = 8;
+
+#[cfg(target_arch = "aarch64")]
+pub const ARM64_MAX_WATCHPOINTS: usize = 2;
+
+#[cfg(target_arch = "aarch64")]
+#[repr(C)]
+pub struct ARM64_NT_NEON128 {
+    pub D: [f64; 2],
+}
+
+#[cfg(target_arch = "aarch64")]
+#[repr(C, align(16))]
+pub struct CONTEXT {
+    pub ContextFlags: DWORD,
+    pub Cpsr: DWORD,
+    pub X0: u64,
+    pub X1: u64,
+    pub X2: u64,
+    pub X3: u64,
+    pub X4: u64,
+    pub X5: u64,
+    pub X6: u64,
+    pub X7: u64,
+    pub X8: u64,
+    pub X9: u64,
+    pub X10: u64,
+    pub X11: u64,
+    pub X12: u64,
+    pub X13: u64,
+    pub X14: u64,
+    pub X15: u64,
+    pub X16: u64,
+    pub X17: u64,
+    pub X18: u64,
+    pub X19: u64,
+    pub X20: u64,
+    pub X21: u64,
+    pub X22: u64,
+    pub X23: u64,
+    pub X24: u64,
+    pub X25: u64,
+    pub X26: u64,
+    pub X27: u64,
+    pub X28: u64,
+    pub Fp: u64,
+    pub Lr: u64,
+    pub Sp: u64,
+    pub Pc: u64,
+    pub V: [ARM64_NT_NEON128; 32],
+    pub Fpcr: DWORD,
+    pub Fpsr: DWORD,
+    pub Bcr: [DWORD; ARM64_MAX_BREAKPOINTS],
+    pub Bvr: [DWORD; ARM64_MAX_BREAKPOINTS],
+    pub Wcr: [DWORD; ARM64_MAX_WATCHPOINTS],
+    pub Wvr: [DWORD; ARM64_MAX_WATCHPOINTS],
+}
+
 #[repr(C)]
 pub struct SOCKADDR_STORAGE_LH {
     pub ss_family: ADDRESS_FAMILY,
diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs
index d6b8896ac09..bae0d02786a 100644
--- a/src/libstd/sys/windows/ext/ffi.rs
+++ b/src/libstd/sys/windows/ext/ffi.rs
@@ -31,7 +31,7 @@
 //!
 //! If Rust code *does* need to look into those strings, it can
 //! convert them to valid UTF-8, possibly lossily, by substituting
-//! invalid sequences with U+FFFD REPLACEMENT CHARACTER, as is
+//! invalid sequences with [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD], as is
 //! conventionally done in other Rust APIs that deal with string
 //! encodings.
 //!
@@ -65,6 +65,7 @@
 //! [`from_wide`]: trait.OsStringExt.html#tymethod.from_wide
 //! [`encode_wide`]: trait.OsStrExt.html#tymethod.encode_wide
 //! [`collect`]: ../../../iter/trait.Iterator.html#method.collect
+//! [U+FFFD]: ../../../char/constant.REPLACEMENT_CHARACTER.html
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -76,7 +77,9 @@ use sys_common::{FromInner, AsInner};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use sys_common::wtf8::EncodeWide;
 
-/// Windows-specific extensions to `OsString`.
+/// Windows-specific extensions to [`OsString`].
+///
+/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait OsStringExt {
     /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of
@@ -109,7 +112,9 @@ impl OsStringExt for OsString {
     }
 }
 
-/// Windows-specific extensions to `OsStr`.
+/// Windows-specific extensions to [`OsStr`].
+///
+/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait OsStrExt {
     /// Re-encodes an `OsStr` as a wide character sequence, i.e. potentially
diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs
index 24c41046f26..78c9e95a055 100644
--- a/src/libstd/sys/windows/ext/fs.rs
+++ b/src/libstd/sys/windows/ext/fs.rs
@@ -45,15 +45,15 @@ pub trait FileExt {
     /// use std::fs::File;
     /// use std::os::windows::prelude::*;
     ///
-    /// # fn foo() -> io::Result<()> {
-    /// let mut file = File::open("foo.txt")?;
-    /// let mut buffer = [0; 10];
-    ///
-    /// // Read 10 bytes, starting 72 bytes from the
-    /// // start of the file.
-    /// file.seek_read(&mut buffer[..], 72)?;
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let mut file = File::open("foo.txt")?;
+    ///     let mut buffer = [0; 10];
+    ///
+    ///     // Read 10 bytes, starting 72 bytes from the
+    ///     // start of the file.
+    ///     file.seek_read(&mut buffer[..], 72)?;
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "file_offset", since = "1.15.0")]
     fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
@@ -79,14 +79,14 @@ pub trait FileExt {
     /// use std::fs::File;
     /// use std::os::windows::prelude::*;
     ///
-    /// # fn foo() -> std::io::Result<()> {
-    /// let mut buffer = File::create("foo.txt")?;
+    /// fn main() -> std::io::Result<()> {
+    ///     let mut buffer = File::create("foo.txt")?;
     ///
-    /// // Write a byte string starting 72 bytes from
-    /// // the start of the file.
-    /// buffer.seek_write(b"some bytes", 72)?;
-    /// # Ok(())
-    /// # }
+    ///     // Write a byte string starting 72 bytes from
+    ///     // the start of the file.
+    ///     buffer.seek_write(b"some bytes", 72)?;
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "file_offset", since = "1.15.0")]
     fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
@@ -103,9 +103,9 @@ impl FileExt for fs::File {
     }
 }
 
-/// Windows-specific extensions to [`OpenOptions`].
+/// Windows-specific extensions to [`fs::OpenOptions`].
 ///
-/// [`OpenOptions`]: ../../../fs/struct.OpenOptions.html
+/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
 #[stable(feature = "open_options_ext", since = "1.10.0")]
 pub trait OpenOptionsExt {
     /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`]
@@ -281,13 +281,12 @@ impl OpenOptionsExt for OpenOptions {
     }
 }
 
-/// Extension methods for [`fs::Metadata`] to access the raw fields contained
-/// within.
+/// Windows-specific extensions to [`fs::Metadata`].
 ///
 /// The data members that this trait exposes correspond to the members
 /// of the [`BY_HANDLE_FILE_INFORMATION`] structure.
 ///
-/// [`fs::Metadata`]: ../../../fs/struct.Metadata.html
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
 /// [`BY_HANDLE_FILE_INFORMATION`]:
 ///     https://msdn.microsoft.com/en-us/library/windows/desktop/aa363788.aspx
 #[stable(feature = "metadata_ext", since = "1.1.0")]
@@ -305,11 +304,11 @@ pub trait MetadataExt {
     /// use std::fs;
     /// use std::os::windows::prelude::*;
     ///
-    /// # fn foo() -> io::Result<()> {
-    /// let metadata = fs::metadata("foo.txt")?;
-    /// let attributes = metadata.file_attributes();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let metadata = fs::metadata("foo.txt")?;
+    ///     let attributes = metadata.file_attributes();
+    ///     Ok(())
+    /// }
     /// ```
     ///
     /// [File Attribute Constants]:
@@ -335,11 +334,11 @@ pub trait MetadataExt {
     /// use std::fs;
     /// use std::os::windows::prelude::*;
     ///
-    /// # fn foo() -> io::Result<()> {
-    /// let metadata = fs::metadata("foo.txt")?;
-    /// let creation_time = metadata.creation_time();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let metadata = fs::metadata("foo.txt")?;
+    ///     let creation_time = metadata.creation_time();
+    ///     Ok(())
+    /// }
     /// ```
     ///
     /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx
@@ -370,11 +369,11 @@ pub trait MetadataExt {
     /// use std::fs;
     /// use std::os::windows::prelude::*;
     ///
-    /// # fn foo() -> io::Result<()> {
-    /// let metadata = fs::metadata("foo.txt")?;
-    /// let last_access_time = metadata.last_access_time();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let metadata = fs::metadata("foo.txt")?;
+    ///     let last_access_time = metadata.last_access_time();
+    ///     Ok(())
+    /// }
     /// ```
     ///
     /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx
@@ -403,11 +402,11 @@ pub trait MetadataExt {
     /// use std::fs;
     /// use std::os::windows::prelude::*;
     ///
-    /// # fn foo() -> io::Result<()> {
-    /// let metadata = fs::metadata("foo.txt")?;
-    /// let last_write_time = metadata.last_write_time();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let metadata = fs::metadata("foo.txt")?;
+    ///     let last_write_time = metadata.last_write_time();
+    ///     Ok(())
+    /// }
     /// ```
     ///
     /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx
@@ -426,11 +425,11 @@ pub trait MetadataExt {
     /// use std::fs;
     /// use std::os::windows::prelude::*;
     ///
-    /// # fn foo() -> io::Result<()> {
-    /// let metadata = fs::metadata("foo.txt")?;
-    /// let file_size = metadata.file_size();
-    /// # Ok(())
-    /// # }
+    /// fn main() -> io::Result<()> {
+    ///     let metadata = fs::metadata("foo.txt")?;
+    ///     let file_size = metadata.file_size();
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn file_size(&self) -> u64;
@@ -445,6 +444,27 @@ impl MetadataExt for Metadata {
     fn file_size(&self) -> u64 { self.as_inner().size() }
 }
 
+/// Windows-specific extensions to [`FileType`].
+///
+/// On Windows, a symbolic link knows whether it is a file or directory.
+///
+/// [`FileType`]: ../../../../std/fs/struct.FileType.html
+#[unstable(feature = "windows_file_type_ext", issue = "0")]
+pub trait FileTypeExt {
+    /// Returns whether this file type is a symbolic link that is also a directory.
+    #[unstable(feature = "windows_file_type_ext", issue = "0")]
+    fn is_symlink_dir(&self) -> bool;
+    /// Returns whether this file type is a symbolic link that is also a file.
+    #[unstable(feature = "windows_file_type_ext", issue = "0")]
+    fn is_symlink_file(&self) -> bool;
+}
+
+#[unstable(feature = "windows_file_type_ext", issue = "0")]
+impl FileTypeExt for fs::FileType {
+    fn is_symlink_dir(&self) -> bool { self.as_inner().is_symlink_dir() }
+    fn is_symlink_file(&self) -> bool { self.as_inner().is_symlink_file() }
+}
+
 /// Creates a new file symbolic link on the filesystem.
 ///
 /// The `dst` path will be a file symbolic link pointing to the `src`
@@ -455,10 +475,10 @@ impl MetadataExt for Metadata {
 /// ```no_run
 /// use std::os::windows::fs;
 ///
-/// # fn foo() -> std::io::Result<()> {
-/// fs::symlink_file("a.txt", "b.txt")?;
-/// # Ok(())
-/// # }
+/// fn main() -> std::io::Result<()> {
+///     fs::symlink_file("a.txt", "b.txt")?;
+///     Ok(())
+/// }
 /// ```
 #[stable(feature = "symlink", since = "1.1.0")]
 pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q)
@@ -476,10 +496,10 @@ pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q)
 /// ```no_run
 /// use std::os::windows::fs;
 ///
-/// # fn foo() -> std::io::Result<()> {
-/// fs::symlink_dir("a", "b")?;
-/// # Ok(())
-/// # }
+/// fn main() -> std::io::Result<()> {
+///     fs::symlink_dir("a", "b")?;
+///     Ok(())
+/// }
 /// ```
 #[stable(feature = "symlink", since = "1.1.0")]
 pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q)
diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs
index 4b458d293bc..1f10609f32c 100644
--- a/src/libstd/sys/windows/ext/mod.rs
+++ b/src/libstd/sys/windows/ext/mod.rs
@@ -18,6 +18,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 #![doc(cfg(windows))]
+#![allow(missing_docs)]
 
 pub mod ffi;
 pub mod fs;
diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs
index 759f055c4b1..a02bcbe0c87 100644
--- a/src/libstd/sys/windows/ext/process.rs
+++ b/src/libstd/sys/windows/ext/process.rs
@@ -82,7 +82,9 @@ impl IntoRawHandle for process::ChildStderr {
     }
 }
 
-/// Windows-specific extensions to `std::process::ExitStatus`
+/// Windows-specific extensions to [`process::ExitStatus`].
+///
+/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
 #[stable(feature = "exit_status_from", since = "1.12.0")]
 pub trait ExitStatusExt {
     /// Creates a new `ExitStatus` from the raw underlying `u32` return value of
@@ -98,7 +100,9 @@ impl ExitStatusExt for process::ExitStatus {
     }
 }
 
-/// Windows-specific extensions to the `std::process::Command` builder
+/// Windows-specific extensions to the [`process::Command`] builder.
+///
+/// [`process::Command`]: ../../../../std/process/struct.Command.html
 #[stable(feature = "windows_process_extensions", since = "1.16.0")]
 pub trait CommandExt {
     /// Sets the [process creation flags][1] to be passed to `CreateProcess`.
diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs
index 165e1b0609b..082d4689c7b 100644
--- a/src/libstd/sys/windows/fs.rs
+++ b/src/libstd/sys/windows/fs.rs
@@ -38,8 +38,9 @@ pub struct FileAttr {
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-pub enum FileType {
-    Dir, File, SymlinkFile, SymlinkDir, ReparsePoint, MountPoint,
+pub struct FileType {
+    attributes: c::DWORD,
+    reparse_tag: c::DWORD,
 }
 
 pub struct ReadDir {
@@ -516,30 +517,34 @@ impl FilePermissions {
 
 impl FileType {
     fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType {
-        match (attrs & c::FILE_ATTRIBUTE_DIRECTORY != 0,
-               attrs & c::FILE_ATTRIBUTE_REPARSE_POINT != 0,
-               reparse_tag) {
-            (false, false, _) => FileType::File,
-            (true, false, _) => FileType::Dir,
-            (false, true, c::IO_REPARSE_TAG_SYMLINK) => FileType::SymlinkFile,
-            (true, true, c::IO_REPARSE_TAG_SYMLINK) => FileType::SymlinkDir,
-            (true, true, c::IO_REPARSE_TAG_MOUNT_POINT) => FileType::MountPoint,
-            (_, true, _) => FileType::ReparsePoint,
-            // Note: if a _file_ has a reparse tag of the type IO_REPARSE_TAG_MOUNT_POINT it is
-            // invalid, as junctions always have to be dirs. We set the filetype to ReparsePoint
-            // to indicate it is something symlink-like, but not something you can follow.
+        FileType {
+            attributes: attrs,
+            reparse_tag: reparse_tag,
         }
     }
-
-    pub fn is_dir(&self) -> bool { *self == FileType::Dir }
-    pub fn is_file(&self) -> bool { *self == FileType::File }
+    pub fn is_dir(&self) -> bool {
+        !self.is_symlink() && self.is_directory()
+    }
+    pub fn is_file(&self) -> bool {
+        !self.is_symlink() && !self.is_directory()
+    }
     pub fn is_symlink(&self) -> bool {
-        *self == FileType::SymlinkFile ||
-        *self == FileType::SymlinkDir ||
-        *self == FileType::MountPoint
+        self.is_reparse_point() && self.is_reparse_tag_name_surrogate()
     }
     pub fn is_symlink_dir(&self) -> bool {
-        *self == FileType::SymlinkDir || *self == FileType::MountPoint
+        self.is_symlink() && self.is_directory()
+    }
+    pub fn is_symlink_file(&self) -> bool {
+        self.is_symlink() && !self.is_directory()
+    }
+    fn is_directory(&self) -> bool {
+        self.attributes & c::FILE_ATTRIBUTE_DIRECTORY != 0
+    }
+    fn is_reparse_point(&self) -> bool {
+        self.attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0
+    }
+    fn is_reparse_tag_name_surrogate(&self) -> bool {
+        self.reparse_tag & 0x20000000 != 0
     }
 }
 
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
index 0d12ecf8fe3..ccf79de909f 100644
--- a/src/libstd/sys/windows/mod.rs
+++ b/src/libstd/sys/windows/mod.rs
@@ -266,8 +266,12 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD {
 // handlers.
 //
 // https://msdn.microsoft.com/en-us/library/dn774154.aspx
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+#[allow(unreachable_code)]
 pub unsafe fn abort_internal() -> ! {
-    asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT
-    ::intrinsics::unreachable();
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    {
+        asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT
+        ::intrinsics::unreachable();
+    }
+    ::intrinsics::abort();
 }
diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs
index 85560368590..9bf9f749d4d 100644
--- a/src/libstd/sys/windows/mutex.rs
+++ b/src/libstd/sys/windows/mutex.rs
@@ -117,7 +117,7 @@ impl Mutex {
             0 => {}
             n => return n as *mut _,
         }
-        let mut re = Box::new(ReentrantMutex::uninitialized());
+        let mut re = box ReentrantMutex::uninitialized();
         re.init();
         let re = Box::into_raw(re);
         match self.lock.compare_and_swap(0, re as usize, Ordering::SeqCst) {
diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs
index 414c9c5418e..bcc66b9954b 100644
--- a/src/libstd/sys/windows/os_str.rs
+++ b/src/libstd/sys/windows/os_str.rs
@@ -114,6 +114,11 @@ impl Buf {
     }
 
     #[inline]
+    pub fn shrink_to(&mut self, min_capacity: usize) {
+        self.inner.shrink_to(min_capacity)
+    }
+
+    #[inline]
     pub fn into_box(self) -> Box<Slice> {
         unsafe { mem::transmute(self.inner.into_box()) }
     }
diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs
index f3b1185c6ea..df1dd7401af 100644
--- a/src/libstd/sys/windows/pipe.rs
+++ b/src/libstd/sys/windows/pipe.rs
@@ -236,7 +236,7 @@ enum State {
 impl<'a> AsyncPipe<'a> {
     fn new(pipe: Handle, dst: &'a mut Vec<u8>) -> io::Result<AsyncPipe<'a>> {
         // Create an event which we'll use to coordinate our overlapped
-        // opreations, this event will be used in WaitForMultipleObjects
+        // operations, this event will be used in WaitForMultipleObjects
         // and passed as part of the OVERLAPPED handle.
         //
         // Note that we do a somewhat clever thing here by flagging the
diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs
index c93179869a6..4974a8de89c 100644
--- a/src/libstd/sys/windows/process.rs
+++ b/src/libstd/sys/windows/process.rs
@@ -10,7 +10,6 @@
 
 #![unstable(feature = "process_internals", issue = "0")]
 
-use ascii::AsciiExt;
 use collections::BTreeMap;
 use env::split_paths;
 use env;
@@ -18,7 +17,7 @@ use ffi::{OsString, OsStr};
 use fmt;
 use fs;
 use io::{self, Error, ErrorKind};
-use libc::c_void;
+use libc::{c_void, EXIT_SUCCESS, EXIT_FAILURE};
 use mem;
 use os::windows::ffi::OsStrExt;
 use path::Path;
@@ -32,7 +31,7 @@ use sys::stdio;
 use sys::cvt;
 use sys_common::{AsInner, FromInner, IntoInner};
 use sys_common::process::{CommandEnv, EnvKey};
-use alloc::borrow::Borrow;
+use borrow::Borrow;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Command
@@ -408,6 +407,19 @@ impl fmt::Display for ExitStatus {
     }
 }
 
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(c::DWORD);
+
+impl ExitCode {
+    pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
+    pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);
+
+    #[inline]
+    pub fn as_i32(&self) -> i32 {
+        self.0 as i32
+    }
+}
+
 fn zeroed_startupinfo() -> c::STARTUPINFO {
     c::STARTUPINFO {
         cb: 0,
@@ -475,9 +487,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
             } else {
                 if x == '"' as u16 {
                     // Add n+1 backslashes to total 2n+1 before internal '"'.
-                    for _ in 0..(backslashes+1) {
-                        cmd.push('\\' as u16);
-                    }
+                    cmd.extend((0..(backslashes + 1)).map(|_| '\\' as u16));
                 }
                 backslashes = 0;
             }
@@ -486,9 +496,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
 
         if quote {
             // Add n backslashes to total 2n before ending '"'.
-            for _ in 0..backslashes {
-                cmd.push('\\' as u16);
-            }
+            cmd.extend((0..backslashes).map(|_| '\\' as u16));
             cmd.push('"' as u16);
         }
         Ok(())
diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs
index b43df20bddd..81b89da21d3 100644
--- a/src/libstd/sys/windows/stdio.rs
+++ b/src/libstd/sys/windows/stdio.rs
@@ -227,3 +227,7 @@ pub fn is_ebadf(err: &io::Error) -> bool {
 // idea is that on windows we use a slightly smaller buffer that's
 // been seen to be acceptable.
 pub const STDIN_BUF_SIZE: usize = 8 * 1024;
+
+pub fn stderr_prints_nothing() -> bool {
+    false
+}
diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs
index 74786d09285..85588cc6c8e 100644
--- a/src/libstd/sys/windows/thread.rs
+++ b/src/libstd/sys/windows/thread.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use alloc::boxed::FnBox;
+use boxed::FnBox;
 use io;
 use ffi::CStr;
 use mem;
@@ -28,7 +28,7 @@ pub struct Thread {
 }
 
 impl Thread {
-    pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
+    pub unsafe fn new<'a>(stack: usize, p: Box<dyn FnBox() + 'a>)
                           -> io::Result<Thread> {
         let p = box p;
 
@@ -42,7 +42,8 @@ impl Thread {
         let stack_size = (stack + 0xfffe) & (!0xfffe);
         let ret = c::CreateThread(ptr::null_mut(), stack_size,
                                   thread_start, &*p as *const _ as *mut _,
-                                  0, ptr::null_mut());
+                                  c::STACK_SIZE_PARAM_IS_A_RESERVATION,
+                                  ptr::null_mut());
 
         return if ret as usize == 0 {
             Err(io::Error::last_os_error())
@@ -93,6 +94,8 @@ impl Thread {
 
 #[cfg_attr(test, allow(dead_code))]
 pub mod guard {
-    pub unsafe fn current() -> Option<usize> { None }
-    pub unsafe fn init() -> Option<usize> { None }
+    pub type Guard = !;
+    pub unsafe fn current() -> Option<Guard> { None }
+    pub unsafe fn init() -> Option<Guard> { None }
+    pub unsafe fn deinit() {}
 }