about summary refs log tree commit diff
path: root/src/libstd/sys
diff options
context:
space:
mode:
authorBaoshan <pangbw@gmail.com>2019-09-10 21:21:48 -0700
committerGitHub <noreply@github.com>2019-09-10 21:21:48 -0700
commit5e8bf872f6adf145b75610dc216e942a84343179 (patch)
treefba9fd9e3b84c88b19e650ba1da44075f23b7220 /src/libstd/sys
parent76f17219c71973fd4a58f2f8020eec4d8f5dcd11 (diff)
parent34e82a7b793a6cdd27df762bf46bab8cdc92b14a (diff)
downloadrust-5e8bf872f6adf145b75610dc216e942a84343179.tar.gz
rust-5e8bf872f6adf145b75610dc216e942a84343179.zip
Merge pull request #21 from rust-lang/master
Sync with rust-lang/rust master branch
Diffstat (limited to 'src/libstd/sys')
-rw-r--r--src/libstd/sys/cloudabi/shims/process.rs8
-rw-r--r--src/libstd/sys/sgx/condvar.rs3
-rw-r--r--src/libstd/sys/sgx/mutex.rs4
-rw-r--r--src/libstd/sys/sgx/process.rs8
-rw-r--r--src/libstd/sys/sgx/rwlock.rs34
-rw-r--r--src/libstd/sys/sgx/waitqueue.rs11
-rw-r--r--src/libstd/sys/unix/process/mod.rs1
-rw-r--r--src/libstd/sys/unix/process/process_common.rs36
-rw-r--r--src/libstd/sys/unix/process/process_fuchsia.rs63
-rw-r--r--src/libstd/sys/unix/process/process_unix.rs25
-rw-r--r--src/libstd/sys/unix/process/zircon.rs12
-rw-r--r--src/libstd/sys/unix/time.rs1
-rw-r--r--src/libstd/sys/vxworks/backtrace/mod.rs110
-rw-r--r--src/libstd/sys/vxworks/backtrace/printing/dladdr.rs35
-rw-r--r--src/libstd/sys/vxworks/backtrace/printing/mod.rs33
-rw-r--r--src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs39
-rw-r--r--src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs99
-rw-r--r--src/libstd/sys/vxworks/backtrace/tracing/mod.rs8
-rw-r--r--src/libstd/sys/vxworks/fast_thread_local.rs27
-rw-r--r--src/libstd/sys/vxworks/process/process_common.rs10
-rw-r--r--src/libstd/sys/vxworks/thread.rs2
-rw-r--r--src/libstd/sys/wasi/args.rs41
-rw-r--r--src/libstd/sys/wasi/ext/fs.rs10
-rw-r--r--src/libstd/sys/wasi/ext/io.rs8
-rw-r--r--src/libstd/sys/wasi/fd.rs280
-rw-r--r--src/libstd/sys/wasi/fs.rs186
-rw-r--r--src/libstd/sys/wasi/io.rs11
-rw-r--r--src/libstd/sys/wasi/mod.rs79
-rw-r--r--src/libstd/sys/wasi/os.rs33
-rw-r--r--src/libstd/sys/wasi/process.rs8
-rw-r--r--src/libstd/sys/wasi/stdio.rs11
-rw-r--r--src/libstd/sys/wasi/thread.rs54
-rw-r--r--src/libstd/sys/wasi/time.rs30
-rw-r--r--src/libstd/sys/wasm/args.rs4
-rw-r--r--src/libstd/sys/wasm/mod.rs222
-rw-r--r--src/libstd/sys/wasm/os.rs18
-rw-r--r--src/libstd/sys/wasm/process.rs8
-rw-r--r--src/libstd/sys/wasm/stdio.rs15
-rw-r--r--src/libstd/sys/wasm/time.rs5
-rw-r--r--src/libstd/sys/windows/process.rs24
40 files changed, 508 insertions, 1108 deletions
diff --git a/src/libstd/sys/cloudabi/shims/process.rs b/src/libstd/sys/cloudabi/shims/process.rs
index e719b362cbf..03a59d6d7c8 100644
--- a/src/libstd/sys/cloudabi/shims/process.rs
+++ b/src/libstd/sys/cloudabi/shims/process.rs
@@ -4,14 +4,16 @@ use crate::io;
 use crate::sys::fs::File;
 use crate::sys::pipe::AnonPipe;
 use crate::sys::{unsupported, Void};
-use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
+use crate::sys_common::process::CommandEnv;
+
+pub use crate::ffi::OsString as EnvKey;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Command
 ////////////////////////////////////////////////////////////////////////////////
 
 pub struct Command {
-    env: CommandEnv<DefaultEnvKey>,
+    env: CommandEnv,
 }
 
 // passed back to std::process with the pipes connected to the child, if any
@@ -37,7 +39,7 @@ impl Command {
 
     pub fn arg(&mut self, _arg: &OsStr) {}
 
-    pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+    pub fn env_mut(&mut self) -> &mut CommandEnv {
         &mut self.env
     }
 
diff --git a/src/libstd/sys/sgx/condvar.rs b/src/libstd/sys/sgx/condvar.rs
index 000bb19f269..cc1c04a83e7 100644
--- a/src/libstd/sys/sgx/condvar.rs
+++ b/src/libstd/sys/sgx/condvar.rs
@@ -27,8 +27,7 @@ impl Condvar {
 
     pub unsafe fn wait(&self, mutex: &Mutex) {
         let guard = self.inner.lock();
-        mutex.unlock();
-        WaitQueue::wait(guard);
+        WaitQueue::wait(guard, || mutex.unlock());
         mutex.lock()
     }
 
diff --git a/src/libstd/sys/sgx/mutex.rs b/src/libstd/sys/sgx/mutex.rs
index f325fb1dd58..662da8b3f66 100644
--- a/src/libstd/sys/sgx/mutex.rs
+++ b/src/libstd/sys/sgx/mutex.rs
@@ -22,7 +22,7 @@ impl Mutex {
         let mut guard = self.inner.lock();
         if *guard.lock_var() {
             // Another thread has the lock, wait
-            WaitQueue::wait(guard)
+            WaitQueue::wait(guard, ||{})
             // Another thread has passed the lock to us
         } else {
             // We are just now obtaining the lock
@@ -83,7 +83,7 @@ impl ReentrantMutex {
         match guard.lock_var().owner {
             Some(tcs) if tcs != thread::current() => {
                 // Another thread has the lock, wait
-                WaitQueue::wait(guard);
+                WaitQueue::wait(guard, ||{});
                 // Another thread has passed the lock to us
             },
             _ => {
diff --git a/src/libstd/sys/sgx/process.rs b/src/libstd/sys/sgx/process.rs
index a02e009d953..edf933d10e0 100644
--- a/src/libstd/sys/sgx/process.rs
+++ b/src/libstd/sys/sgx/process.rs
@@ -4,14 +4,16 @@ use crate::io;
 use crate::sys::fs::File;
 use crate::sys::pipe::AnonPipe;
 use crate::sys::{unsupported, Void};
-use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
+use crate::sys_common::process::CommandEnv;
+
+pub use crate::ffi::OsString as EnvKey;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Command
 ////////////////////////////////////////////////////////////////////////////////
 
 pub struct Command {
-    env: CommandEnv<DefaultEnvKey>
+    env: CommandEnv,
 }
 
 // passed back to std::process with the pipes connected to the child, if any
@@ -38,7 +40,7 @@ impl Command {
     pub fn arg(&mut self, _arg: &OsStr) {
     }
 
-    pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+    pub fn env_mut(&mut self) -> &mut CommandEnv {
         &mut self.env
     }
 
diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs
index 30c47e44eef..e2f94b1d928 100644
--- a/src/libstd/sys/sgx/rwlock.rs
+++ b/src/libstd/sys/sgx/rwlock.rs
@@ -31,7 +31,7 @@ impl RWLock {
         if *wguard.lock_var() || !wguard.queue_empty() {
             // Another thread has or is waiting for the write lock, wait
             drop(wguard);
-            WaitQueue::wait(rguard);
+            WaitQueue::wait(rguard, ||{});
             // Another thread has passed the lock to us
         } else {
             // No waiting writers, acquire the read lock
@@ -62,7 +62,7 @@ impl RWLock {
         if *wguard.lock_var() || rguard.lock_var().is_some() {
             // Another thread has the lock, wait
             drop(rguard);
-            WaitQueue::wait(wguard);
+            WaitQueue::wait(wguard, ||{});
             // Another thread has passed the lock to us
         } else {
             // We are just now obtaining the lock
@@ -97,6 +97,7 @@ impl RWLock {
             if let Ok(mut wguard) = WaitQueue::notify_one(wguard) {
                 // A writer was waiting, pass the lock
                 *wguard.lock_var_mut() = true;
+                wguard.drop_after(rguard);
             } else {
                 // No writers were waiting, the lock is released
                 rtassert!(rguard.queue_empty());
@@ -117,21 +118,26 @@ impl RWLock {
         rguard: SpinMutexGuard<'_, WaitVariable<Option<NonZeroUsize>>>,
         wguard: SpinMutexGuard<'_, WaitVariable<bool>>,
     ) {
-        if let Err(mut wguard) = WaitQueue::notify_one(wguard) {
-            // No writers waiting, release the write lock
-            *wguard.lock_var_mut() = false;
-            if let Ok(mut rguard) = WaitQueue::notify_all(rguard) {
-                // One or more readers were waiting, pass the lock to them
-                if let NotifiedTcs::All { count } = rguard.notified_tcs() {
-                    *rguard.lock_var_mut() = Some(count)
+        match WaitQueue::notify_one(wguard) {
+            Err(mut wguard) => {
+                // No writers waiting, release the write lock
+                *wguard.lock_var_mut() = false;
+                if let Ok(mut rguard) = WaitQueue::notify_all(rguard) {
+                    // One or more readers were waiting, pass the lock to them
+                    if let NotifiedTcs::All { count } = rguard.notified_tcs() {
+                        *rguard.lock_var_mut() = Some(count)
+                    } else {
+                        unreachable!() // called notify_all
+                    }
+                    rguard.drop_after(wguard);
                 } else {
-                    unreachable!() // called notify_all
+                    // No readers waiting, the lock is released
                 }
-            } else {
-                // No readers waiting, the lock is released
+            },
+            Ok(wguard) => {
+                // There was a thread waiting for write, just pass the lock
+                wguard.drop_after(rguard);
             }
-        } else {
-            // There was a thread waiting for write, just pass the lock
         }
     }
 
diff --git a/src/libstd/sys/sgx/waitqueue.rs b/src/libstd/sys/sgx/waitqueue.rs
index d542f9b4101..3cb40e509b6 100644
--- a/src/libstd/sys/sgx/waitqueue.rs
+++ b/src/libstd/sys/sgx/waitqueue.rs
@@ -98,6 +98,12 @@ impl<'a, T> WaitGuard<'a, T> {
     pub fn notified_tcs(&self) -> NotifiedTcs {
         self.notified_tcs
     }
+
+    /// Drop this `WaitGuard`, after dropping another `guard`.
+    pub fn drop_after<U>(self, guard: U) {
+        drop(guard);
+        drop(self);
+    }
 }
 
 impl<'a, T> Deref for WaitGuard<'a, T> {
@@ -140,7 +146,7 @@ impl WaitQueue {
     /// until a wakeup event.
     ///
     /// This function does not return until this thread has been awoken.
-    pub fn wait<T>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>) {
+    pub fn wait<T, F: FnOnce()>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>, before_wait: F) {
         // very unsafe: check requirements of UnsafeList::push
         unsafe {
             let mut entry = UnsafeListEntry::new(SpinMutex::new(WaitEntry {
@@ -149,6 +155,7 @@ impl WaitQueue {
             }));
             let entry = guard.queue.inner.push(&mut entry);
             drop(guard);
+            before_wait();
             while !entry.lock().wake {
                 // don't panic, this would invalidate `entry` during unwinding
                 let eventset = rtunwrap!(Ok, usercalls::wait(EV_UNPARK, WAIT_INDEFINITE));
@@ -545,7 +552,7 @@ mod tests {
             assert!(WaitQueue::notify_one(wq2.lock()).is_ok());
         });
 
-        WaitQueue::wait(locked);
+        WaitQueue::wait(locked, ||{});
 
         t1.join().unwrap();
     }
diff --git a/src/libstd/sys/unix/process/mod.rs b/src/libstd/sys/unix/process/mod.rs
index bba4b21c462..056a20345f4 100644
--- a/src/libstd/sys/unix/process/mod.rs
+++ b/src/libstd/sys/unix/process/mod.rs
@@ -1,5 +1,6 @@
 pub use self::process_common::{Command, ExitStatus, ExitCode, Stdio, StdioPipes};
 pub use self::process_inner::Process;
+pub use crate::ffi::OsString as EnvKey;
 
 mod process_common;
 #[cfg(not(target_os = "fuchsia"))]
diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs
index 21fca23a8fe..713d3085559 100644
--- a/src/libstd/sys/unix/process/process_common.rs
+++ b/src/libstd/sys/unix/process/process_common.rs
@@ -1,19 +1,27 @@
 use crate::os::unix::prelude::*;
 
-use crate::ffi::{OsString, OsStr, CString, CStr};
+use crate::ffi::{OsString, OsStr, CString};
 use crate::fmt;
 use crate::io;
 use crate::ptr;
 use crate::sys::fd::FileDesc;
-use crate::sys::fs::{File, OpenOptions};
+use crate::sys::fs::File;
 use crate::sys::pipe::{self, AnonPipe};
-use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
+use crate::sys_common::process::CommandEnv;
 use crate::collections::BTreeMap;
 
+#[cfg(not(target_os = "fuchsia"))]
+use {
+    crate::ffi::CStr,
+    crate::sys::fs::OpenOptions,
+};
+
 use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};
 
 cfg_if::cfg_if! {
-    if #[cfg(target_os = "redox")] {
+    if #[cfg(target_os = "fuchsia")] {
+        // fuchsia doesn't have /dev/null
+    } else if #[cfg(target_os = "redox")] {
         const DEV_NULL: &'static str = "null:\0";
     } else {
         const DEV_NULL: &'static str = "/dev/null\0";
@@ -69,7 +77,7 @@ pub struct Command {
     program: CString,
     args: Vec<CString>,
     argv: Argv,
-    env: CommandEnv<DefaultEnvKey>,
+    env: CommandEnv,
 
     cwd: Option<CString>,
     uid: Option<uid_t>,
@@ -107,6 +115,11 @@ pub enum ChildStdio {
     Inherit,
     Explicit(c_int),
     Owned(FileDesc),
+
+    // On Fuchsia, null stdio is the default, so we simply don't specify
+    // any actions at the time of spawning.
+    #[cfg(target_os = "fuchsia")]
+    Null,
 }
 
 pub enum Stdio {
@@ -201,7 +214,7 @@ impl Command {
         self.stderr = Some(stderr);
     }
 
-    pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+    pub fn env_mut(&mut self) -> &mut CommandEnv {
         &mut self.env
     }
 
@@ -271,7 +284,7 @@ impl CStringArray {
     }
 }
 
-fn construct_envp(env: BTreeMap<DefaultEnvKey, OsString>, saw_nul: &mut bool) -> CStringArray {
+fn construct_envp(env: BTreeMap<OsString, OsString>, saw_nul: &mut bool) -> CStringArray {
     let mut result = CStringArray::with_capacity(env.len());
     for (k, v) in env {
         let mut k: OsString = k.into();
@@ -325,6 +338,7 @@ impl Stdio {
                 Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
             }
 
+            #[cfg(not(target_os = "fuchsia"))]
             Stdio::Null => {
                 let mut opts = OpenOptions::new();
                 opts.read(readable);
@@ -335,6 +349,11 @@ impl Stdio {
                 let fd = File::open_c(&path, &opts)?;
                 Ok((ChildStdio::Owned(fd.into_fd()), None))
             }
+
+            #[cfg(target_os = "fuchsia")]
+            Stdio::Null => {
+                Ok((ChildStdio::Null, None))
+            }
         }
     }
 }
@@ -357,6 +376,9 @@ impl ChildStdio {
             ChildStdio::Inherit => None,
             ChildStdio::Explicit(fd) => Some(fd),
             ChildStdio::Owned(ref fd) => Some(fd.raw()),
+
+            #[cfg(target_os = "fuchsia")]
+            ChildStdio::Null => None,
         }
     }
 }
diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs
index 7c6be9b0a60..fff9fc6b3bb 100644
--- a/src/libstd/sys/unix/process/process_fuchsia.rs
+++ b/src/libstd/sys/unix/process/process_fuchsia.rs
@@ -48,30 +48,51 @@ impl Command {
         use crate::sys::process::zircon::*;
 
         let envp = match maybe_envp {
-            Some(envp) => envp.as_ptr(),
+            // None means to clone the current environment, which is done in the
+            // flags below.
             None => ptr::null(),
+            Some(envp) => envp.as_ptr(),
         };
 
-        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()
+        let make_action = |local_io: &ChildStdio, target_fd| -> io::Result<fdio_spawn_action_t> {
+            if let Some(local_fd) = local_io.fd() {
+                Ok(fdio_spawn_action_t {
+                    action: FDIO_SPAWN_ACTION_TRANSFER_FD,
+                    local_fd,
+                    target_fd,
+                    ..Default::default()
+                })
+            } else {
+                if let ChildStdio::Null = local_io {
+                    // acts as no-op
+                    return Ok(Default::default());
+                }
+
+                let mut handle = ZX_HANDLE_INVALID;
+                let status = fdio_fd_clone(target_fd, &mut handle);
+                if status == ERR_INVALID_ARGS || status == ERR_NOT_SUPPORTED {
+                    // This descriptor is closed; skip it rather than generating an
+                    // error.
+                    return Ok(Default::default());
+                }
+                zx_cvt(status)?;
+
+                let mut cloned_fd = 0;
+                zx_cvt(fdio_fd_create(handle, &mut cloned_fd))?;
+
+                Ok(fdio_spawn_action_t {
+                    action: FDIO_SPAWN_ACTION_TRANSFER_FD,
+                    local_fd: cloned_fd as i32,
+                    target_fd,
+                    ..Default::default()
+                })
             }
         };
 
         // Clone stdin, stdout, and stderr
-        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 action1 = make_action(&stdio.stdin, 0)?;
+        let action2 = make_action(&stdio.stdout, 1)?;
+        let action3 = make_action(&stdio.stderr, 2)?;
         let actions = [action1, action2, action3];
 
         // We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc
@@ -84,9 +105,11 @@ impl Command {
 
         let mut process_handle: zx_handle_t = 0;
         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(),
+            ZX_HANDLE_INVALID,
+            FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE
+            | FDIO_SPAWN_CLONE_ENVIRON,  // this is ignored when envp is non-null
+            self.get_argv()[0], self.get_argv().as_ptr(), envp,
+            actions.len() as size_t, actions.as_ptr(),
             &mut process_handle,
             ptr::null_mut(),
         ))?;
diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs
index a9711c71b7a..e6a742bd45d 100644
--- a/src/libstd/sys/unix/process/process_unix.rs
+++ b/src/libstd/sys/unix/process/process_unix.rs
@@ -178,23 +178,22 @@ impl Command {
             cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO))?;
         }
 
-        if cfg!(not(any(target_os = "l4re"))) {
+        #[cfg(not(target_os = "l4re"))]
+        {
             if let Some(u) = self.get_gid() {
                 cvt(libc::setgid(u as gid_t))?;
             }
             if let Some(u) = self.get_uid() {
+                // When dropping privileges from root, the `setgroups` call
+                // will remove any extraneous groups. If we don't call this,
+                // then even though our uid has dropped, we may still have
+                // groups that enable us to do super-user things. This will
+                // fail if we aren't root, so don't bother checking the
+                // return value, this is just done as an optimistic
+                // privilege dropping function.
                 //FIXME: Redox kernel does not support setgroups yet
-                if cfg!(not(target_os = "redox")) {
-                    // When dropping privileges from root, the `setgroups` call
-                    // will remove any extraneous groups. If we don't call this,
-                    // then even though our uid has dropped, we may still have
-                    // groups that enable us to do super-user things. This will
-                    // fail if we aren't root, so don't bother checking the
-                    // return value, this is just done as an optimistic
-                    // privilege dropping function.
-                    let _ = libc::setgroups(0, ptr::null());
-                }
-
+                #[cfg(not(target_os = "redox"))]
+                let _ = libc::setgroups(0, ptr::null());
                 cvt(libc::setuid(u as uid_t))?;
             }
         }
@@ -203,7 +202,7 @@ impl Command {
         }
 
         // emscripten has no signal support.
-        #[cfg(not(any(target_os = "emscripten")))]
+        #[cfg(not(target_os = "emscripten"))]
         {
             use crate::mem::MaybeUninit;
             // Reset signal handling so the child process starts in a
diff --git a/src/libstd/sys/unix/process/zircon.rs b/src/libstd/sys/unix/process/zircon.rs
index ec715d5490f..1ba48de3c07 100644
--- a/src/libstd/sys/unix/process/zircon.rs
+++ b/src/libstd/sys/unix/process/zircon.rs
@@ -2,8 +2,9 @@
 
 use crate::convert::TryInto;
 use crate::io;
+use crate::i64;
+use crate::mem::MaybeUninit;
 use crate::os::raw::c_char;
-use crate::u64;
 
 use libc::{c_int, c_void, size_t};
 
@@ -14,8 +15,8 @@ pub type zx_status_t = i32;
 
 pub const ZX_HANDLE_INVALID: zx_handle_t = 0;
 
-pub type zx_time_t = u64;
-pub const ZX_TIME_INFINITE : zx_time_t = u64::MAX;
+pub type zx_time_t = i64;
+pub const ZX_TIME_INFINITE : zx_time_t = i64::MAX;
 
 pub type zx_signals_t = u32;
 
@@ -120,8 +121,11 @@ pub struct fdio_spawn_action_t {
 extern {
     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,
+                          action_count: size_t, actions: *const fdio_spawn_action_t,
                           process: *mut zx_handle_t, err_msg: *mut c_char) -> zx_status_t;
+
+    pub fn fdio_fd_clone(fd: c_int, out_handle: *mut zx_handle_t) -> zx_status_t;
+    pub fn fdio_fd_create(handle: zx_handle_t, fd: *mut c_int) -> zx_status_t;
 }
 
 // fdio_spawn_etc flags
diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs
index 02f377d55c9..fd6796ad22c 100644
--- a/src/libstd/sys/unix/time.rs
+++ b/src/libstd/sys/unix/time.rs
@@ -311,6 +311,7 @@ mod inner {
         pub fn actually_monotonic() -> bool {
             (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64")) ||
             (cfg!(target_os = "linux") && cfg!(target_arch = "x86")) ||
+            cfg!(target_os = "fuchsia") ||
             false // last clause, used so `||` is always trailing above
         }
 
diff --git a/src/libstd/sys/vxworks/backtrace/mod.rs b/src/libstd/sys/vxworks/backtrace/mod.rs
deleted file mode 100644
index 0887e5a4df9..00000000000
--- a/src/libstd/sys/vxworks/backtrace/mod.rs
+++ /dev/null
@@ -1,110 +0,0 @@
-/// Backtrace support built on libgcc with some extra OS-specific support
-///
-/// Some methods of getting a backtrace:
-///
-/// * The backtrace() functions on unix. It turns out this doesn't work very
-///   well for green threads on macOS, and the address to symbol portion of it
-///   suffers problems that are described below.
-///
-/// * Using libunwind. This is more difficult than it sounds because libunwind
-///   isn't installed everywhere by default. It's also a bit of a hefty library,
-///   so possibly not the best option. When testing, libunwind was excellent at
-///   getting both accurate backtraces and accurate symbols across platforms.
-///   This route was not chosen in favor of the next option, however.
-///
-/// * We're already using libgcc_s for exceptions in rust (triggering thread
-///   unwinding and running destructors on the stack), and it turns out that it
-///   conveniently comes with a function that also gives us a backtrace. All of
-///   these functions look like _Unwind_*, but it's not quite the full
-///   repertoire of the libunwind API. Due to it already being in use, this was
-///   the chosen route of getting a backtrace.
-///
-/// After choosing libgcc_s for backtraces, the sad part is that it will only
-/// give us a stack trace of instruction pointers. Thankfully these instruction
-/// pointers are accurate (they work for green and native threads), but it's
-/// then up to us again to figure out how to translate these addresses to
-/// symbols. As with before, we have a few options. Before, that, a little bit
-/// of an interlude about symbols. This is my very limited knowledge about
-/// symbol tables, and this information is likely slightly wrong, but the
-/// general idea should be correct.
-///
-/// When talking about symbols, it's helpful to know a few things about where
-/// symbols are located. Some symbols are located in the dynamic symbol table
-/// of the executable which in theory means that they're available for dynamic
-/// linking and lookup. Other symbols end up only in the local symbol table of
-/// the file. This loosely corresponds to pub and priv functions in Rust.
-///
-/// Armed with this knowledge, we know that our solution for address to symbol
-/// translation will need to consult both the local and dynamic symbol tables.
-/// With that in mind, here's our options of translating an address to
-/// a symbol.
-///
-/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr()
-///   behind the scenes to translate, and this is why backtrace() was not used.
-///   Conveniently, this method works fantastically on macOS. It appears dladdr()
-///   uses magic to consult the local symbol table, or we're putting everything
-///   in the dynamic symbol table anyway. Regardless, for macOS, this is the
-///   method used for translation. It's provided by the system and easy to do.o
-///
-///   Sadly, all other systems have a dladdr() implementation that does not
-///   consult the local symbol table. This means that most functions are blank
-///   because they don't have symbols. This means that we need another solution.
-///
-/// * Use unw_get_proc_name(). This is part of the libunwind api (not the
-///   libgcc_s version of the libunwind api), but involves taking a dependency
-///   to libunwind. We may pursue this route in the future if we bundle
-///   libunwind, but libunwind was unwieldy enough that it was not chosen at
-///   this time to provide this functionality.
-///
-/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a
-///   semi-reasonable solution. The stdlib already knows how to spawn processes,
-///   so in theory it could invoke readelf, parse the output, and consult the
-///   local/dynamic symbol tables from there. This ended up not getting chosen
-///   due to the craziness of the idea plus the advent of the next option.
-///
-/// * Use `libbacktrace`. It turns out that this is a small library bundled in
-///   the gcc repository which provides backtrace and symbol translation
-///   functionality. All we really need from it is the backtrace functionality,
-///   and we only really need this on everything that's not macOS, so this is the
-///   chosen route for now.
-///
-/// In summary, the current situation uses libgcc_s to get a trace of stack
-/// pointers, and we use dladdr() or libbacktrace to translate these addresses
-/// to symbols. This is a bit of a hokey implementation as-is, but it works for
-/// all unix platforms we support right now, so it at least gets the job done.
-
-pub use self::tracing::unwind_backtrace;
-pub use self::printing::{foreach_symbol_fileline, resolve_symname};
-
-// tracing impls:
-mod tracing;
-// symbol resolvers:
-mod printing;
-
-#[cfg(not(target_os = "emscripten"))]
-pub mod gnu {
-    use crate::io;
-    use crate::fs;
-
-    use libc::c_char;
-
-    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
-    pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
-        Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
-    }
-
-    #[cfg(any(target_os = "macos", target_os = "ios"))]
-    pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
-        use crate::env;
-        use crate::os::unix::ffi::OsStrExt;
-
-        let filename = env::current_exe()?;
-        let file = fs::File::open(&filename)?;
-        let mut filename_cstr: Vec<_> = filename.as_os_str().as_bytes().iter()
-            .map(|&x| x as c_char).collect();
-        filename_cstr.push(0); // Null terminate
-        Ok((filename_cstr, file))
-    }
-}
-
-pub struct BacktraceContext;
diff --git a/src/libstd/sys/vxworks/backtrace/printing/dladdr.rs b/src/libstd/sys/vxworks/backtrace/printing/dladdr.rs
deleted file mode 100644
index 202164dd3c4..00000000000
--- a/src/libstd/sys/vxworks/backtrace/printing/dladdr.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-use crate::io;
-use crate::intrinsics;
-use crate::ffi::CStr;
-use crate::sys::backtrace::BacktraceContext;
-use crate::sys_common::backtrace::Frame;
-
-pub fn resolve_symname<F>(frame: Frame,
-                          callback: F,
-                          _: &BacktraceContext) -> io::Result<()>
-    where F: FnOnce(Option<&str>) -> io::Result<()>
-{
-    unsafe {
-        let mut info: Dl_info = intrinsics::init();
-        let symname = if dladdr(frame.exact_position as *mut _, &mut info) == 0 ||
-                         info.dli_sname.is_null() {
-            None
-        } else {
-            CStr::from_ptr(info.dli_sname).to_str().ok()
-        };
-        callback(symname)
-    }
-}
-
-#[repr(C)]
-struct Dl_info {
-    dli_fname: *const libc::c_char,
-    dli_fbase: *mut libc::c_void,
-    dli_sname: *const libc::c_char,
-    dli_saddr: *mut libc::c_void,
-}
-
-extern {
-    #[ link_name = "_rtld_dladdr" ]
-    fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int;
-}
diff --git a/src/libstd/sys/vxworks/backtrace/printing/mod.rs b/src/libstd/sys/vxworks/backtrace/printing/mod.rs
deleted file mode 100644
index d090caede43..00000000000
--- a/src/libstd/sys/vxworks/backtrace/printing/mod.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-mod dladdr;
-
-use crate::sys::backtrace::BacktraceContext;
-use crate::sys_common::backtrace::Frame;
-use crate::io;
-
-#[cfg(target_os = "emscripten")]
-pub use self::dladdr::resolve_symname;
-
-#[cfg(target_os = "emscripten")]
-pub fn foreach_symbol_fileline<F>(_: Frame, _: F, _: &BacktraceContext) -> io::Result<bool>
-where
-    F: FnMut(&[u8], u32) -> io::Result<()>
-{
-    Ok(false)
-}
-
-#[cfg(not(target_os = "emscripten"))]
-pub use crate::sys_common::gnu::libbacktrace::foreach_symbol_fileline;
-
-#[cfg(not(target_os = "emscripten"))]
-pub fn resolve_symname<F>(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()>
-where
-    F: FnOnce(Option<&str>) -> io::Result<()>
-{
-    crate::sys_common::gnu::libbacktrace::resolve_symname(frame, |symname| {
-        if symname.is_some() {
-            callback(symname)
-        } else {
-            dladdr::resolve_symname(frame, callback, bc)
-        }
-    }, bc)
-}
diff --git a/src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs
deleted file mode 100644
index a628d107ad6..00000000000
--- a/src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-/// As always - iOS on arm uses SjLj exceptions and
-/// _Unwind_Backtrace is even not available there. Still,
-/// backtraces could be extracted using a backtrace function,
-/// which thanks god is public
-///
-/// As mentioned in a huge comment block in `super::super`, backtrace
-/// doesn't play well with green threads, so while it is extremely nice and
-/// simple to use it should be used only on iOS devices as the only viable
-/// option.
-
-use crate::io;
-use crate::ptr;
-use crate::sys::backtrace::BacktraceContext;
-use crate::sys_common::backtrace::Frame;
-
-#[inline(never)] // if we know this is a function call, we can skip it when
-                 // tracing
-pub fn unwind_backtrace(frames: &mut [Frame])
-    -> io::Result<(usize, BacktraceContext)>
-{
-    const FRAME_LEN: usize = 100;
-    assert!(FRAME_LEN >= frames.len());
-    let mut raw_frames = [ptr::null_mut(); FRAME_LEN];
-    let nb_frames = unsafe {
-        backtrace(raw_frames.as_mut_ptr(), raw_frames.len() as libc::c_int)
-    } as usize;
-    for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) {
-        *to = Frame {
-            exact_position: *from as *mut u8,
-            symbol_addr: *from as *mut u8,
-            inline_context: 0,
-        };
-    }
-    Ok((nb_frames as usize, BacktraceContext))
-}
-
-extern {
-    fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int;
-}
diff --git a/src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs b/src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs
deleted file mode 100644
index e6379132baf..00000000000
--- a/src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-use crate::error::Error;
-use crate::fmt;
-use crate::io;
-use crate::sys::backtrace::BacktraceContext;
-use crate::sys_common::backtrace::Frame;
-
-use unwind as uw;
-
-struct Context<'a> {
-    idx: usize,
-    frames: &'a mut [Frame],
-}
-
-#[derive(Debug)]
-struct UnwindError(uw::_Unwind_Reason_Code);
-
-impl Error for UnwindError {
-    fn description(&self) -> &'static str {
-        "unexpected return value while unwinding"
-    }
-}
-
-impl fmt::Display for UnwindError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{}: {:?}", self.description(), self.0)
-    }
-}
-
-#[inline(never)] // if we know this is a function call, we can skip it when
-                 // tracing
-pub fn unwind_backtrace(frames: &mut [Frame])
-    -> io::Result<(usize, BacktraceContext)>
-{
-    let mut cx = Context {
-        idx: 0,
-        frames,
-    };
-    let result_unwind = unsafe {
-        uw::_Unwind_Backtrace(trace_fn,
-                              &mut cx as *mut Context<'_>
-                              as *mut libc::c_void)
-    };
-    // See libunwind:src/unwind/Backtrace.c for the return values.
-    // No, there is no doc.
-    match result_unwind {
-        // These return codes seem to be benign and need to be ignored for backtraces
-        // to show up properly on all tested platforms.
-        uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
-            Ok((cx.idx, BacktraceContext))
-        }
-        _ => {
-            Err(io::Error::new(io::ErrorKind::Other,
-                               UnwindError(result_unwind)))
-        }
-    }
-}
-
-extern 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
-    };
-    if !ip.is_null() && ip_before_insn == 0 {
-        // this is a non-signaling frame, so `ip` refers to the address
-        // after the calling instruction. account for that.
-        ip = (ip as usize - 1) as *mut _;
-    }
-
-    // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
-    // it appears to work fine without it, so we only use
-    // FindEnclosingFunction on non-osx platforms. In doing so, we get a
-    // slightly more accurate stack trace in the process.
-    //
-    // This is often because panic involves the last instruction of a
-    // function being "call std::rt::begin_unwind", with no ret
-    // instructions after it. This means that the return instruction
-    // pointer points *outside* of the calling function, and by
-    // unwinding it we go back to the original function.
-    let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
-        ip
-    } else {
-        unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
-    };
-
-    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/vxworks/backtrace/tracing/mod.rs b/src/libstd/sys/vxworks/backtrace/tracing/mod.rs
deleted file mode 100644
index 11863e64545..00000000000
--- a/src/libstd/sys/vxworks/backtrace/tracing/mod.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-pub use self::imp::*;
-
-#[cfg(not(all(target_os = "ios", target_arch = "arm")))]
-#[path = "gcc_s.rs"]
-mod imp;
-#[cfg(all(target_os = "ios", target_arch = "arm"))]
-#[path = "backtrace_fn.rs"]
-mod imp;
diff --git a/src/libstd/sys/vxworks/fast_thread_local.rs b/src/libstd/sys/vxworks/fast_thread_local.rs
index f5a2e263d25..2e021980778 100644
--- a/src/libstd/sys/vxworks/fast_thread_local.rs
+++ b/src/libstd/sys/vxworks/fast_thread_local.rs
@@ -1,33 +1,10 @@
+// Copyright (c) 2019 Wind River Systems, Inc.
+
 #![cfg(target_thread_local)]
 #![unstable(feature = "thread_local_internals", issue = "0")]
 
-// Since what appears to be glibc 2.18 this symbol has been shipped which
-// GCC and clang both use to invoke destructors in thread_local globals, so
-// let's do the same!
-//
-// Note, however, that we run on lots older linuxes, as well as cross
-// compiling from a newer linux to an older linux, so we also have a
-// fallback implementation to use as well.
-//
-// Due to rust-lang/rust#18804, make sure this is not generic!
 pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
-    use crate::mem;
     use crate::sys_common::thread_local::register_dtor_fallback;
-
-    extern {
-        #[linkage = "extern_weak"]
-        static __dso_handle: *mut u8;
-        #[linkage = "extern_weak"]
-        static __cxa_thread_atexit_impl: *const libc::c_void;
-    }
-    if !__cxa_thread_atexit_impl.is_null() {
-        type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8),
-                                  arg: *mut u8,
-                                  dso_handle: *mut u8) -> libc::c_int;
-        mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl)
-            (dtor, t, &__dso_handle as *const _ as *mut _);
-        return
-    }
     register_dtor_fallback(t, dtor);
 }
 
diff --git a/src/libstd/sys/vxworks/process/process_common.rs b/src/libstd/sys/vxworks/process/process_common.rs
index ba797354a73..509140229fd 100644
--- a/src/libstd/sys/vxworks/process/process_common.rs
+++ b/src/libstd/sys/vxworks/process/process_common.rs
@@ -7,11 +7,13 @@ use crate::ptr;
 use crate::sys::fd::FileDesc;
 use crate::sys::fs::{File, OpenOptions};
 use crate::sys::pipe::{self, AnonPipe};
-use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
+use crate::sys_common::process::CommandEnv;
 use crate::collections::BTreeMap;
 
 use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};
 
+pub use crate::ffi::OsString as EnvKey;
+
 ////////////////////////////////////////////////////////////////////////////////
 // Command
 ////////////////////////////////////////////////////////////////////////////////
@@ -37,7 +39,7 @@ pub struct Command {
     program: CString,
     args: Vec<CString>,
     argv: Argv,
-    env: CommandEnv<DefaultEnvKey>,
+    env: CommandEnv,
 
     cwd: Option<CString>,
     uid: Option<uid_t>,
@@ -170,7 +172,7 @@ impl Command {
         self.stderr = Some(stderr);
     }
 
-    pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+    pub fn env_mut(&mut self) -> &mut CommandEnv {
         &mut self.env
     }
 
@@ -240,7 +242,7 @@ impl CStringArray {
     }
 }
 
-fn construct_envp(env: BTreeMap<DefaultEnvKey, OsString>, saw_nul: &mut bool) -> CStringArray {
+fn construct_envp(env: BTreeMap<OsString, OsString>, saw_nul: &mut bool) -> CStringArray {
     let mut result = CStringArray::with_capacity(env.len());
     for (k, v) in env {
         let mut k: OsString = k.into();
diff --git a/src/libstd/sys/vxworks/thread.rs b/src/libstd/sys/vxworks/thread.rs
index 58af8cbe48e..ef896f6a6e8 100644
--- a/src/libstd/sys/vxworks/thread.rs
+++ b/src/libstd/sys/vxworks/thread.rs
@@ -77,7 +77,7 @@ impl Thread {
     }
 
     pub fn set_name(_name: &CStr) {
-        assert!(false, "FIXME: set_name");
+        // VxWorks does not provide a way to set the task name except at creation time
     }
 
     pub fn sleep(dur: Duration) {
diff --git a/src/libstd/sys/wasi/args.rs b/src/libstd/sys/wasi/args.rs
index 8b4b354d9fc..3280c4990dc 100644
--- a/src/libstd/sys/wasi/args.rs
+++ b/src/libstd/sys/wasi/args.rs
@@ -1,11 +1,10 @@
-use crate::ffi::CStr;
-use crate::io;
-use crate::sys::cvt_wasi;
 use crate::ffi::OsString;
 use crate::marker::PhantomData;
 use crate::os::wasi::ffi::OsStringExt;
 use crate::vec;
 
+use ::wasi::wasi_unstable as wasi;
+
 pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
 }
 
@@ -19,31 +18,17 @@ pub struct Args {
 
 /// Returns the command line arguments
 pub fn args() -> Args {
-    maybe_args().unwrap_or_else(|_| {
-        Args {
-            iter: Vec::new().into_iter(),
-            _dont_send_or_sync_me: PhantomData
-        }
-    })
-}
-
-fn maybe_args() -> io::Result<Args> {
-    unsafe {
-        let (mut argc, mut argv_buf_size) = (0, 0);
-        cvt_wasi(libc::__wasi_args_sizes_get(&mut argc, &mut argv_buf_size))?;
-
-        let mut argc = vec![core::ptr::null_mut::<libc::c_char>(); argc];
-        let mut argv_buf = vec![0; argv_buf_size];
-        cvt_wasi(libc::__wasi_args_get(argc.as_mut_ptr(), argv_buf.as_mut_ptr()))?;
-
-        let args = argc.into_iter()
-            .map(|ptr| CStr::from_ptr(ptr).to_bytes().to_vec())
-            .map(|bytes| OsString::from_vec(bytes))
-            .collect::<Vec<_>>();
-        Ok(Args {
-            iter: args.into_iter(),
-            _dont_send_or_sync_me: PhantomData,
-        })
+    let buf = wasi::args_sizes_get().and_then(|args_sizes| {
+        let mut buf = Vec::with_capacity(args_sizes.get_count());
+        wasi::args_get(args_sizes, |arg| {
+            let arg = OsString::from_vec(arg.to_vec());
+            buf.push(arg);
+        })?;
+        Ok(buf)
+    }).unwrap_or(vec![]);
+    Args {
+        iter: buf.into_iter(),
+        _dont_send_or_sync_me: PhantomData
     }
 }
 
diff --git a/src/libstd/sys/wasi/ext/fs.rs b/src/libstd/sys/wasi/ext/fs.rs
index 0ec4122f385..9fa4abfd171 100644
--- a/src/libstd/sys/wasi/ext/fs.rs
+++ b/src/libstd/sys/wasi/ext/fs.rs
@@ -8,6 +8,8 @@ use crate::os::wasi::ffi::OsStrExt;
 use crate::path::{Path, PathBuf};
 use crate::sys_common::{AsInner, AsInnerMut, FromInner};
 
+use ::wasi::wasi_unstable as wasi;
+
 /// WASI-specific extensions to [`File`].
 ///
 /// [`File`]: ../../../../std/fs/struct.File.html
@@ -336,16 +338,16 @@ pub trait FileTypeExt {
 
 impl FileTypeExt for fs::FileType {
     fn is_block_device(&self) -> bool {
-        self.as_inner().bits() == libc::__WASI_FILETYPE_BLOCK_DEVICE
+        self.as_inner().bits() == wasi::FILETYPE_BLOCK_DEVICE
     }
     fn is_character_device(&self) -> bool {
-        self.as_inner().bits() == libc::__WASI_FILETYPE_CHARACTER_DEVICE
+        self.as_inner().bits() == wasi::FILETYPE_CHARACTER_DEVICE
     }
     fn is_socket_dgram(&self) -> bool {
-        self.as_inner().bits() == libc::__WASI_FILETYPE_SOCKET_DGRAM
+        self.as_inner().bits() == wasi::FILETYPE_SOCKET_DGRAM
     }
     fn is_socket_stream(&self) -> bool {
-        self.as_inner().bits() == libc::__WASI_FILETYPE_SOCKET_STREAM
+        self.as_inner().bits() == wasi::FILETYPE_SOCKET_STREAM
     }
 }
 
diff --git a/src/libstd/sys/wasi/ext/io.rs b/src/libstd/sys/wasi/ext/io.rs
index 12afd1d42dc..f1839df3801 100644
--- a/src/libstd/sys/wasi/ext/io.rs
+++ b/src/libstd/sys/wasi/ext/io.rs
@@ -8,6 +8,8 @@ use crate::sys;
 use crate::net;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 
+use ::wasi::wasi_unstable as wasi;
+
 /// Raw file descriptors.
 pub type RawFd = u32;
 
@@ -125,18 +127,18 @@ impl IntoRawFd for fs::File {
 
 impl AsRawFd for io::Stdin {
     fn as_raw_fd(&self) -> RawFd {
-        libc::STDIN_FILENO as u32
+        wasi::STDIN_FD
     }
 }
 
 impl AsRawFd for io::Stdout {
     fn as_raw_fd(&self) -> RawFd {
-        libc::STDOUT_FILENO as u32
+        wasi::STDOUT_FD
     }
 }
 
 impl AsRawFd for io::Stderr {
     fn as_raw_fd(&self) -> RawFd {
-        libc::STDERR_FILENO as u32
+        wasi::STDERR_FD
     }
 }
diff --git a/src/libstd/sys/wasi/fd.rs b/src/libstd/sys/wasi/fd.rs
index 25692ec0868..5b7a8678b66 100644
--- a/src/libstd/sys/wasi/fd.rs
+++ b/src/libstd/sys/wasi/fd.rs
@@ -3,348 +3,248 @@
 use crate::io::{self, IoSlice, IoSliceMut, SeekFrom};
 use crate::mem;
 use crate::net::Shutdown;
-use crate::sys::cvt_wasi;
-use libc::{self, c_char, c_void};
+use super::err2io;
+use ::wasi::wasi_unstable as wasi;
 
 #[derive(Debug)]
 pub struct WasiFd {
-    fd: libc::__wasi_fd_t,
+    fd: wasi::Fd,
 }
 
-// FIXME: these should probably all be fancier structs, builders, enums, etc
-pub type LookupFlags = u32;
-pub type FdFlags = u16;
-pub type Advice = u8;
-pub type Rights = u64;
-pub type Oflags = u16;
-pub type DirCookie = u64;
-pub type Timestamp = u64;
-pub type FstFlags = u16;
-pub type RiFlags = u16;
-pub type RoFlags = u16;
-pub type SiFlags = u16;
-
-fn iovec(a: &mut [IoSliceMut<'_>]) -> (*const libc::__wasi_iovec_t, usize) {
+fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::IoVec] {
     assert_eq!(
         mem::size_of::<IoSliceMut<'_>>(),
-        mem::size_of::<libc::__wasi_iovec_t>()
+        mem::size_of::<wasi::IoVec>()
     );
     assert_eq!(
         mem::align_of::<IoSliceMut<'_>>(),
-        mem::align_of::<libc::__wasi_iovec_t>()
+        mem::align_of::<wasi::IoVec>()
     );
-    (a.as_ptr() as *const libc::__wasi_iovec_t, a.len())
+    /// SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout
+    unsafe { mem::transmute(a) }
 }
 
-fn ciovec(a: &[IoSlice<'_>]) -> (*const libc::__wasi_ciovec_t, usize) {
+fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::CIoVec] {
     assert_eq!(
         mem::size_of::<IoSlice<'_>>(),
-        mem::size_of::<libc::__wasi_ciovec_t>()
+        mem::size_of::<wasi::CIoVec>()
     );
     assert_eq!(
         mem::align_of::<IoSlice<'_>>(),
-        mem::align_of::<libc::__wasi_ciovec_t>()
+        mem::align_of::<wasi::CIoVec>()
     );
-    (a.as_ptr() as *const libc::__wasi_ciovec_t, a.len())
+    /// SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout
+    unsafe { mem::transmute(a) }
 }
 
 impl WasiFd {
-    pub unsafe fn from_raw(fd: libc::__wasi_fd_t) -> WasiFd {
+    pub unsafe fn from_raw(fd: wasi::Fd) -> WasiFd {
         WasiFd { fd }
     }
 
-    pub fn into_raw(self) -> libc::__wasi_fd_t {
+    pub fn into_raw(self) -> wasi::Fd {
         let ret = self.fd;
         mem::forget(self);
         ret
     }
 
-    pub fn as_raw(&self) -> libc::__wasi_fd_t {
+    pub fn as_raw(&self) -> wasi::Fd {
         self.fd
     }
 
     pub fn datasync(&self) -> io::Result<()> {
-        cvt_wasi(unsafe { libc::__wasi_fd_datasync(self.fd) })
+        unsafe { wasi::fd_datasync(self.fd).map_err(err2io) }
     }
 
     pub fn pread(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
-        let mut read = 0;
-        let (ptr, len) = iovec(bufs);
-        cvt_wasi(unsafe { libc::__wasi_fd_pread(self.fd, ptr, len, offset, &mut read) })?;
-        Ok(read)
+        unsafe { wasi::fd_pread(self.fd, iovec(bufs), offset).map_err(err2io) }
     }
 
     pub fn pwrite(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
-        let mut read = 0;
-        let (ptr, len) = ciovec(bufs);
-        cvt_wasi(unsafe { libc::__wasi_fd_pwrite(self.fd, ptr, len, offset, &mut read) })?;
-        Ok(read)
+        unsafe { wasi::fd_pwrite(self.fd, ciovec(bufs), offset).map_err(err2io) }
     }
 
     pub fn read(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        let mut read = 0;
-        let (ptr, len) = iovec(bufs);
-        cvt_wasi(unsafe { libc::__wasi_fd_read(self.fd, ptr, len, &mut read) })?;
-        Ok(read)
+        unsafe { wasi::fd_read(self.fd, iovec(bufs)).map_err(err2io) }
     }
 
     pub fn write(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        let mut read = 0;
-        let (ptr, len) = ciovec(bufs);
-        cvt_wasi(unsafe { libc::__wasi_fd_write(self.fd, ptr, len, &mut read) })?;
-        Ok(read)
+        unsafe { wasi::fd_write(self.fd, ciovec(bufs)).map_err(err2io) }
     }
 
     pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
         let (whence, offset) = match pos {
-            SeekFrom::Start(pos) => (libc::__WASI_WHENCE_SET, pos as i64),
-            SeekFrom::End(pos) => (libc::__WASI_WHENCE_END, pos),
-            SeekFrom::Current(pos) => (libc::__WASI_WHENCE_CUR, pos),
+            SeekFrom::Start(pos) => (wasi::WHENCE_SET, pos as i64),
+            SeekFrom::End(pos) => (wasi::WHENCE_END, pos),
+            SeekFrom::Current(pos) => (wasi::WHENCE_CUR, pos),
         };
-        let mut pos = 0;
-        cvt_wasi(unsafe { libc::__wasi_fd_seek(self.fd, offset, whence, &mut pos) })?;
-        Ok(pos)
+        unsafe { wasi::fd_seek(self.fd, offset, whence).map_err(err2io) }
     }
 
     pub fn tell(&self) -> io::Result<u64> {
-        let mut pos = 0;
-        cvt_wasi(unsafe { libc::__wasi_fd_tell(self.fd, &mut pos) })?;
-        Ok(pos)
+        unsafe { wasi::fd_tell(self.fd).map_err(err2io) }
     }
 
     // FIXME: __wasi_fd_fdstat_get
 
-    pub fn set_flags(&self, flags: FdFlags) -> io::Result<()> {
-        cvt_wasi(unsafe { libc::__wasi_fd_fdstat_set_flags(self.fd, flags) })
+    pub fn set_flags(&self, flags: wasi::FdFlags) -> io::Result<()> {
+        unsafe { wasi::fd_fdstat_set_flags(self.fd, flags).map_err(err2io) }
     }
 
-    pub fn set_rights(&self, base: Rights, inheriting: Rights) -> io::Result<()> {
-        cvt_wasi(unsafe { libc::__wasi_fd_fdstat_set_rights(self.fd, base, inheriting) })
+    pub fn set_rights(&self, base: wasi::Rights, inheriting: wasi::Rights) -> io::Result<()> {
+        unsafe { wasi::fd_fdstat_set_rights(self.fd, base, inheriting).map_err(err2io) }
     }
 
     pub fn sync(&self) -> io::Result<()> {
-        cvt_wasi(unsafe { libc::__wasi_fd_sync(self.fd) })
+        unsafe { wasi::fd_sync(self.fd).map_err(err2io) }
     }
 
-    pub fn advise(&self, offset: u64, len: u64, advice: Advice) -> io::Result<()> {
-        cvt_wasi(unsafe { libc::__wasi_fd_advise(self.fd, offset, len, advice as u8) })
+    pub fn advise(&self, offset: u64, len: u64, advice: wasi::Advice) -> io::Result<()> {
+        unsafe { wasi::fd_advise(self.fd, offset, len, advice).map_err(err2io) }
     }
 
     pub fn allocate(&self, offset: u64, len: u64) -> io::Result<()> {
-        cvt_wasi(unsafe { libc::__wasi_fd_allocate(self.fd, offset, len) })
+        unsafe { wasi::fd_allocate(self.fd, offset, len).map_err(err2io) }
     }
 
     pub fn create_directory(&self, path: &[u8]) -> io::Result<()> {
-        cvt_wasi(unsafe {
-            libc::__wasi_path_create_directory(self.fd, path.as_ptr() as *const c_char, path.len())
-        })
+        unsafe { wasi::path_create_directory(self.fd, path).map_err(err2io) }
     }
 
     pub fn link(
         &self,
-        old_flags: LookupFlags,
+        old_flags: wasi::LookupFlags,
         old_path: &[u8],
         new_fd: &WasiFd,
         new_path: &[u8],
     ) -> io::Result<()> {
-        cvt_wasi(unsafe {
-            libc::__wasi_path_link(
-                self.fd,
-                old_flags,
-                old_path.as_ptr() as *const c_char,
-                old_path.len(),
-                new_fd.fd,
-                new_path.as_ptr() as *const c_char,
-                new_path.len(),
-            )
-        })
+        unsafe {
+            wasi::path_link(self.fd, old_flags, old_path, new_fd.fd, new_path)
+                .map_err(err2io)
+        }
     }
 
     pub fn open(
         &self,
-        dirflags: LookupFlags,
+        dirflags: wasi::LookupFlags,
         path: &[u8],
-        oflags: Oflags,
-        fs_rights_base: Rights,
-        fs_rights_inheriting: Rights,
-        fs_flags: FdFlags,
+        oflags: wasi::OFlags,
+        fs_rights_base: wasi::Rights,
+        fs_rights_inheriting: wasi::Rights,
+        fs_flags: wasi::FdFlags,
     ) -> io::Result<WasiFd> {
         unsafe {
-            let mut fd = 0;
-            cvt_wasi(libc::__wasi_path_open(
+            wasi::path_open(
                 self.fd,
                 dirflags,
-                path.as_ptr() as *const c_char,
-                path.len(),
+                path,
                 oflags,
                 fs_rights_base,
                 fs_rights_inheriting,
                 fs_flags,
-                &mut fd,
-            ))?;
-            Ok(WasiFd::from_raw(fd))
+            ).map(|fd| WasiFd::from_raw(fd)).map_err(err2io)
         }
     }
 
-    pub fn readdir(&self, buf: &mut [u8], cookie: DirCookie) -> io::Result<usize> {
-        let mut used = 0;
-        cvt_wasi(unsafe {
-            libc::__wasi_fd_readdir(
-                self.fd,
-                buf.as_mut_ptr() as *mut c_void,
-                buf.len(),
-                cookie,
-                &mut used,
-            )
-        })?;
-        Ok(used)
+    pub fn readdir(&self, buf: &mut [u8], cookie: wasi::DirCookie) -> io::Result<usize> {
+        unsafe { wasi::fd_readdir(self.fd, buf, cookie).map_err(err2io) }
     }
 
     pub fn readlink(&self, path: &[u8], buf: &mut [u8]) -> io::Result<usize> {
-        let mut used = 0;
-        cvt_wasi(unsafe {
-            libc::__wasi_path_readlink(
-                self.fd,
-                path.as_ptr() as *const c_char,
-                path.len(),
-                buf.as_mut_ptr() as *mut c_char,
-                buf.len(),
-                &mut used,
-            )
-        })?;
-        Ok(used)
+        unsafe { wasi::path_readlink(self.fd, path, buf).map_err(err2io) }
     }
 
     pub fn rename(&self, old_path: &[u8], new_fd: &WasiFd, new_path: &[u8]) -> io::Result<()> {
-        cvt_wasi(unsafe {
-            libc::__wasi_path_rename(
-                self.fd,
-                old_path.as_ptr() as *const c_char,
-                old_path.len(),
-                new_fd.fd,
-                new_path.as_ptr() as *const c_char,
-                new_path.len(),
-            )
-        })
+        unsafe {
+            wasi::path_rename(self.fd, old_path, new_fd.fd, new_path).map_err(err2io)
+        }
     }
 
-    pub fn filestat_get(&self, buf: *mut libc::__wasi_filestat_t) -> io::Result<()> {
-        cvt_wasi(unsafe { libc::__wasi_fd_filestat_get(self.fd, buf) })
+    pub fn filestat_get(&self) -> io::Result<wasi::FileStat> {
+        unsafe { wasi::fd_filestat_get(self.fd).map_err(err2io) }
     }
 
     pub fn filestat_set_times(
         &self,
-        atim: Timestamp,
-        mtim: Timestamp,
-        fstflags: FstFlags,
+        atim: wasi::Timestamp,
+        mtim: wasi::Timestamp,
+        fstflags: wasi::FstFlags,
     ) -> io::Result<()> {
-        cvt_wasi(unsafe { libc::__wasi_fd_filestat_set_times(self.fd, atim, mtim, fstflags) })
+        unsafe {
+            wasi::fd_filestat_set_times(self.fd, atim, mtim, fstflags).map_err(err2io)
+        }
     }
 
     pub fn filestat_set_size(&self, size: u64) -> io::Result<()> {
-        cvt_wasi(unsafe { libc::__wasi_fd_filestat_set_size(self.fd, size) })
+        unsafe { wasi::fd_filestat_set_size(self.fd, size).map_err(err2io) }
     }
 
     pub fn path_filestat_get(
         &self,
-        flags: LookupFlags,
+        flags: wasi::LookupFlags,
         path: &[u8],
-        buf: *mut libc::__wasi_filestat_t,
-    ) -> io::Result<()> {
-        cvt_wasi(unsafe {
-            libc::__wasi_path_filestat_get(
-                self.fd,
-                flags,
-                path.as_ptr() as *const c_char,
-                path.len(),
-                buf,
-            )
-        })
+    ) -> io::Result<wasi::FileStat> {
+        unsafe { wasi::path_filestat_get(self.fd, flags, path).map_err(err2io) }
     }
 
     pub fn path_filestat_set_times(
         &self,
-        flags: LookupFlags,
+        flags: wasi::LookupFlags,
         path: &[u8],
-        atim: Timestamp,
-        mtim: Timestamp,
-        fstflags: FstFlags,
+        atim: wasi::Timestamp,
+        mtim: wasi::Timestamp,
+        fstflags: wasi::FstFlags,
     ) -> io::Result<()> {
-        cvt_wasi(unsafe {
-            libc::__wasi_path_filestat_set_times(
+        unsafe {
+            wasi::path_filestat_set_times(
                 self.fd,
                 flags,
-                path.as_ptr() as *const c_char,
-                path.len(),
+                path,
                 atim,
                 mtim,
                 fstflags,
-            )
-        })
+            ).map_err(err2io)
+        }
     }
 
     pub fn symlink(&self, old_path: &[u8], new_path: &[u8]) -> io::Result<()> {
-        cvt_wasi(unsafe {
-            libc::__wasi_path_symlink(
-                old_path.as_ptr() as *const c_char,
-                old_path.len(),
-                self.fd,
-                new_path.as_ptr() as *const c_char,
-                new_path.len(),
-            )
-        })
+        unsafe { wasi::path_symlink(old_path, self.fd, new_path).map_err(err2io) }
     }
 
     pub fn unlink_file(&self, path: &[u8]) -> io::Result<()> {
-        cvt_wasi(unsafe {
-            libc::__wasi_path_unlink_file(self.fd, path.as_ptr() as *const c_char, path.len())
-        })
+        unsafe { wasi::path_unlink_file(self.fd, path).map_err(err2io) }
     }
 
     pub fn remove_directory(&self, path: &[u8]) -> io::Result<()> {
-        cvt_wasi(unsafe {
-            libc::__wasi_path_remove_directory(self.fd, path.as_ptr() as *const c_char, path.len())
-        })
+        unsafe { wasi::path_remove_directory(self.fd, path).map_err(err2io) }
     }
 
     pub fn sock_recv(
         &self,
         ri_data: &mut [IoSliceMut<'_>],
-        ri_flags: RiFlags,
-    ) -> io::Result<(usize, RoFlags)> {
-        let mut ro_datalen = 0;
-        let mut ro_flags = 0;
-        let (ptr, len) = iovec(ri_data);
-        cvt_wasi(unsafe {
-            libc::__wasi_sock_recv(self.fd, ptr, len, ri_flags, &mut ro_datalen, &mut ro_flags)
-        })?;
-        Ok((ro_datalen, ro_flags))
+        ri_flags: wasi::RiFlags,
+    ) -> io::Result<(usize, wasi::RoFlags)> {
+        unsafe { wasi::sock_recv(self.fd, iovec(ri_data), ri_flags).map_err(err2io) }
     }
 
-    pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: SiFlags) -> io::Result<usize> {
-        let mut so_datalen = 0;
-        let (ptr, len) = ciovec(si_data);
-        cvt_wasi(unsafe { libc::__wasi_sock_send(self.fd, ptr, len, si_flags, &mut so_datalen) })?;
-        Ok(so_datalen)
+    pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: wasi::SiFlags) -> io::Result<usize> {
+        unsafe { wasi::sock_send(self.fd, ciovec(si_data), si_flags).map_err(err2io) }
     }
 
     pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> {
         let how = match how {
-            Shutdown::Read => libc::__WASI_SHUT_RD,
-            Shutdown::Write => libc::__WASI_SHUT_WR,
-            Shutdown::Both => libc::__WASI_SHUT_WR | libc::__WASI_SHUT_RD,
+            Shutdown::Read => wasi::SHUT_RD,
+            Shutdown::Write => wasi::SHUT_WR,
+            Shutdown::Both => wasi::SHUT_WR | wasi::SHUT_RD,
         };
-        cvt_wasi(unsafe { libc::__wasi_sock_shutdown(self.fd, how) })?;
-        Ok(())
+        unsafe { wasi::sock_shutdown(self.fd, how).map_err(err2io) }
     }
 }
 
 impl Drop for WasiFd {
     fn drop(&mut self) {
-        unsafe {
-            // FIXME: can we handle the return code here even though we can't on
-            // unix?
-            libc::__wasi_fd_close(self.fd);
-        }
+        // FIXME: can we handle the return code here even though we can't on
+        // unix?
+        let _ = unsafe { wasi::fd_close(self.fd) };
     }
 }
diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs
index 172c60385b3..4113f6a2e09 100644
--- a/src/libstd/sys/wasi/fs.rs
+++ b/src/libstd/sys/wasi/fs.rs
@@ -7,7 +7,7 @@ use crate::os::wasi::ffi::{OsStrExt, OsStringExt};
 use crate::path::{Path, PathBuf};
 use crate::ptr;
 use crate::sync::Arc;
-use crate::sys::fd::{DirCookie, WasiFd};
+use crate::sys::fd::WasiFd;
 use crate::sys::time::SystemTime;
 use crate::sys::unsupported;
 use crate::sys_common::FromInner;
@@ -15,18 +15,20 @@ use crate::sys_common::FromInner;
 pub use crate::sys_common::fs::copy;
 pub use crate::sys_common::fs::remove_dir_all;
 
+use ::wasi::wasi_unstable as wasi;
+
 pub struct File {
     fd: WasiFd,
 }
 
 #[derive(Clone)]
 pub struct FileAttr {
-    meta: libc::__wasi_filestat_t,
+    meta: wasi::FileStat,
 }
 
 pub struct ReadDir {
     inner: Arc<ReadDirInner>,
-    cookie: Option<DirCookie>,
+    cookie: Option<wasi::DirCookie>,
     buf: Vec<u8>,
     offset: usize,
     cap: usize,
@@ -38,7 +40,7 @@ struct ReadDirInner {
 }
 
 pub struct DirEntry {
-    meta: libc::__wasi_dirent_t,
+    meta: wasi::Dirent,
     name: Vec<u8>,
     inner: Arc<ReadDirInner>,
 }
@@ -47,11 +49,11 @@ pub struct DirEntry {
 pub struct OpenOptions {
     read: bool,
     write: bool,
-    dirflags: libc::__wasi_lookupflags_t,
-    fdflags: libc::__wasi_fdflags_t,
-    oflags: libc::__wasi_oflags_t,
-    rights_base: Option<libc::__wasi_rights_t>,
-    rights_inheriting: Option<libc::__wasi_rights_t>,
+    dirflags: wasi::LookupFlags,
+    fdflags: wasi::FdFlags,
+    oflags: wasi::OFlags,
+    rights_base: Option<wasi::Rights>,
+    rights_inheriting: Option<wasi::Rights>,
 }
 
 #[derive(Clone, PartialEq, Eq, Debug)]
@@ -61,19 +63,13 @@ pub struct FilePermissions {
 
 #[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
 pub struct FileType {
-    bits: libc::__wasi_filetype_t,
+    bits: wasi::FileType,
 }
 
 #[derive(Debug)]
 pub struct DirBuilder {}
 
 impl FileAttr {
-    fn zero() -> FileAttr {
-        FileAttr {
-            meta: unsafe { mem::zeroed() },
-        }
-    }
-
     pub fn size(&self) -> u64 {
         self.meta.st_size
     }
@@ -101,7 +97,7 @@ impl FileAttr {
         Ok(SystemTime::from_wasi_timestamp(self.meta.st_ctim))
     }
 
-    pub fn as_wasi(&self) -> &libc::__wasi_filestat_t {
+    pub fn as_wasi(&self) -> &wasi::FileStat {
         &self.meta
     }
 }
@@ -118,18 +114,18 @@ impl FilePermissions {
 
 impl FileType {
     pub fn is_dir(&self) -> bool {
-        self.bits == libc::__WASI_FILETYPE_DIRECTORY
+        self.bits == wasi::FILETYPE_DIRECTORY
     }
 
     pub fn is_file(&self) -> bool {
-        self.bits == libc::__WASI_FILETYPE_REGULAR_FILE
+        self.bits == wasi::FILETYPE_REGULAR_FILE
     }
 
     pub fn is_symlink(&self) -> bool {
-        self.bits == libc::__WASI_FILETYPE_SYMBOLIC_LINK
+        self.bits == wasi::FILETYPE_SYMBOLIC_LINK
     }
 
-    pub fn bits(&self) -> libc::__wasi_filetype_t {
+    pub fn bits(&self) -> wasi::FileType {
         self.bits
     }
 }
@@ -173,7 +169,7 @@ impl Iterator for ReadDir {
             // must have been truncated at the end of the buffer, so reset our
             // offset so we can go back and reread into the buffer, picking up
             // where we last left off.
-            let dirent_size = mem::size_of::<libc::__wasi_dirent_t>();
+            let dirent_size = mem::size_of::<wasi::Dirent>();
             if data.len() < dirent_size {
                 assert!(self.cookie.is_some());
                 assert!(self.buf.len() >= dirent_size);
@@ -182,7 +178,7 @@ impl Iterator for ReadDir {
             }
             let (dirent, data) = data.split_at(dirent_size);
             let dirent =
-                unsafe { ptr::read_unaligned(dirent.as_ptr() as *const libc::__wasi_dirent_t) };
+                unsafe { ptr::read_unaligned(dirent.as_ptr() as *const wasi::Dirent) };
 
             // If the file name was truncated, then we need to reinvoke
             // `readdir` so we truncate our buffer to start over and reread this
@@ -241,7 +237,7 @@ impl DirEntry {
         })
     }
 
-    pub fn ino(&self) -> libc::__wasi_inode_t {
+    pub fn ino(&self) -> wasi::Inode {
         self.meta.d_ino
     }
 }
@@ -249,7 +245,7 @@ impl DirEntry {
 impl OpenOptions {
     pub fn new() -> OpenOptions {
         let mut base = OpenOptions::default();
-        base.dirflags = libc::__WASI_LOOKUP_SYMLINK_FOLLOW;
+        base.dirflags = wasi::LOOKUP_SYMLINK_FOLLOW;
         return base;
     }
 
@@ -262,23 +258,23 @@ impl OpenOptions {
     }
 
     pub fn truncate(&mut self, truncate: bool) {
-        self.oflag(libc::__WASI_O_TRUNC, truncate);
+        self.oflag(wasi::O_TRUNC, truncate);
     }
 
     pub fn create(&mut self, create: bool) {
-        self.oflag(libc::__WASI_O_CREAT, create);
+        self.oflag(wasi::O_CREAT, create);
     }
 
     pub fn create_new(&mut self, create_new: bool) {
-        self.oflag(libc::__WASI_O_EXCL, create_new);
-        self.oflag(libc::__WASI_O_CREAT, create_new);
+        self.oflag(wasi::O_EXCL, create_new);
+        self.oflag(wasi::O_CREAT, create_new);
     }
 
     pub fn directory(&mut self, directory: bool) {
-        self.oflag(libc::__WASI_O_DIRECTORY, directory);
+        self.oflag(wasi::O_DIRECTORY, directory);
     }
 
-    fn oflag(&mut self, bit: libc::__wasi_oflags_t, set: bool) {
+    fn oflag(&mut self, bit: wasi::OFlags, set: bool) {
         if set {
             self.oflags |= bit;
         } else {
@@ -287,26 +283,26 @@ impl OpenOptions {
     }
 
     pub fn append(&mut self, set: bool) {
-        self.fdflag(libc::__WASI_FDFLAG_APPEND, set);
+        self.fdflag(wasi::FDFLAG_APPEND, set);
     }
 
     pub fn dsync(&mut self, set: bool) {
-        self.fdflag(libc::__WASI_FDFLAG_DSYNC, set);
+        self.fdflag(wasi::FDFLAG_DSYNC, set);
     }
 
     pub fn nonblock(&mut self, set: bool) {
-        self.fdflag(libc::__WASI_FDFLAG_NONBLOCK, set);
+        self.fdflag(wasi::FDFLAG_NONBLOCK, set);
     }
 
     pub fn rsync(&mut self, set: bool) {
-        self.fdflag(libc::__WASI_FDFLAG_RSYNC, set);
+        self.fdflag(wasi::FDFLAG_RSYNC, set);
     }
 
     pub fn sync(&mut self, set: bool) {
-        self.fdflag(libc::__WASI_FDFLAG_SYNC, set);
+        self.fdflag(wasi::FDFLAG_SYNC, set);
     }
 
-    fn fdflag(&mut self, bit: libc::__wasi_fdflags_t, set: bool) {
+    fn fdflag(&mut self, bit: wasi::FdFlags, set: bool) {
         if set {
             self.fdflags |= bit;
         } else {
@@ -314,15 +310,15 @@ impl OpenOptions {
         }
     }
 
-    pub fn fs_rights_base(&mut self, rights: libc::__wasi_rights_t) {
+    pub fn fs_rights_base(&mut self, rights: wasi::Rights) {
         self.rights_base = Some(rights);
     }
 
-    pub fn fs_rights_inheriting(&mut self, rights: libc::__wasi_rights_t) {
+    pub fn fs_rights_inheriting(&mut self, rights: wasi::Rights) {
         self.rights_inheriting = Some(rights);
     }
 
-    fn rights_base(&self) -> libc::__wasi_rights_t {
+    fn rights_base(&self) -> wasi::Rights {
         if let Some(rights) = self.rights_base {
             return rights;
         }
@@ -334,52 +330,52 @@ impl OpenOptions {
         // based on that.
         let mut base = 0;
         if self.read {
-            base |= libc::__WASI_RIGHT_FD_READ;
-            base |= libc::__WASI_RIGHT_FD_READDIR;
+            base |= wasi::RIGHT_FD_READ;
+            base |= wasi::RIGHT_FD_READDIR;
         }
         if self.write {
-            base |= libc::__WASI_RIGHT_FD_WRITE;
-            base |= libc::__WASI_RIGHT_FD_DATASYNC;
-            base |= libc::__WASI_RIGHT_FD_ALLOCATE;
-            base |= libc::__WASI_RIGHT_FD_FILESTAT_SET_SIZE;
+            base |= wasi::RIGHT_FD_WRITE;
+            base |= wasi::RIGHT_FD_DATASYNC;
+            base |= wasi::RIGHT_FD_ALLOCATE;
+            base |= wasi::RIGHT_FD_FILESTAT_SET_SIZE;
         }
 
         // FIXME: some of these should probably be read-only or write-only...
-        base |= libc::__WASI_RIGHT_FD_ADVISE;
-        base |= libc::__WASI_RIGHT_FD_FDSTAT_SET_FLAGS;
-        base |= libc::__WASI_RIGHT_FD_FILESTAT_SET_TIMES;
-        base |= libc::__WASI_RIGHT_FD_SEEK;
-        base |= libc::__WASI_RIGHT_FD_SYNC;
-        base |= libc::__WASI_RIGHT_FD_TELL;
-        base |= libc::__WASI_RIGHT_PATH_CREATE_DIRECTORY;
-        base |= libc::__WASI_RIGHT_PATH_CREATE_FILE;
-        base |= libc::__WASI_RIGHT_PATH_FILESTAT_GET;
-        base |= libc::__WASI_RIGHT_PATH_LINK_SOURCE;
-        base |= libc::__WASI_RIGHT_PATH_LINK_TARGET;
-        base |= libc::__WASI_RIGHT_PATH_OPEN;
-        base |= libc::__WASI_RIGHT_PATH_READLINK;
-        base |= libc::__WASI_RIGHT_PATH_REMOVE_DIRECTORY;
-        base |= libc::__WASI_RIGHT_PATH_RENAME_SOURCE;
-        base |= libc::__WASI_RIGHT_PATH_RENAME_TARGET;
-        base |= libc::__WASI_RIGHT_PATH_SYMLINK;
-        base |= libc::__WASI_RIGHT_PATH_UNLINK_FILE;
-        base |= libc::__WASI_RIGHT_POLL_FD_READWRITE;
+        base |= wasi::RIGHT_FD_ADVISE;
+        base |= wasi::RIGHT_FD_FDSTAT_SET_FLAGS;
+        base |= wasi::RIGHT_FD_FILESTAT_SET_TIMES;
+        base |= wasi::RIGHT_FD_SEEK;
+        base |= wasi::RIGHT_FD_SYNC;
+        base |= wasi::RIGHT_FD_TELL;
+        base |= wasi::RIGHT_PATH_CREATE_DIRECTORY;
+        base |= wasi::RIGHT_PATH_CREATE_FILE;
+        base |= wasi::RIGHT_PATH_FILESTAT_GET;
+        base |= wasi::RIGHT_PATH_LINK_SOURCE;
+        base |= wasi::RIGHT_PATH_LINK_TARGET;
+        base |= wasi::RIGHT_PATH_OPEN;
+        base |= wasi::RIGHT_PATH_READLINK;
+        base |= wasi::RIGHT_PATH_REMOVE_DIRECTORY;
+        base |= wasi::RIGHT_PATH_RENAME_SOURCE;
+        base |= wasi::RIGHT_PATH_RENAME_TARGET;
+        base |= wasi::RIGHT_PATH_SYMLINK;
+        base |= wasi::RIGHT_PATH_UNLINK_FILE;
+        base |= wasi::RIGHT_POLL_FD_READWRITE;
 
         return base;
     }
 
-    fn rights_inheriting(&self) -> libc::__wasi_rights_t {
+    fn rights_inheriting(&self) -> wasi::Rights {
         self.rights_inheriting.unwrap_or_else(|| self.rights_base())
     }
 
-    pub fn lookup_flags(&mut self, flags: libc::__wasi_lookupflags_t) {
+    pub fn lookup_flags(&mut self, flags: wasi::LookupFlags) {
         self.dirflags = flags;
     }
 }
 
 impl File {
     pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
-        let (dir, file) = open_parent(path, libc::__WASI_RIGHT_PATH_OPEN)?;
+        let (dir, file) = open_parent(path, wasi::RIGHT_PATH_OPEN)?;
         open_at(&dir, &file, opts)
     }
 
@@ -388,14 +384,12 @@ impl File {
     }
 
     pub fn file_attr(&self) -> io::Result<FileAttr> {
-        let mut ret = FileAttr::zero();
-        self.fd.filestat_get(&mut ret.meta)?;
-        Ok(ret)
+        self.fd.filestat_get().map(|meta| FileAttr { meta })
     }
 
     pub fn metadata_at(
         &self,
-        flags: libc::__wasi_lookupflags_t,
+        flags: wasi::LookupFlags,
         path: &Path,
     ) -> io::Result<FileAttr> {
         metadata_at(&self.fd, flags, path)
@@ -477,7 +471,7 @@ impl DirBuilder {
     }
 
     pub fn mkdir(&self, p: &Path) -> io::Result<()> {
-        let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_CREATE_DIRECTORY)?;
+        let (dir, file) = open_parent(p, wasi::RIGHT_PATH_CREATE_DIRECTORY)?;
         dir.create_directory(file.as_os_str().as_bytes())
     }
 }
@@ -508,13 +502,13 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
 }
 
 pub fn unlink(p: &Path) -> io::Result<()> {
-    let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_UNLINK_FILE)?;
+    let (dir, file) = open_parent(p, wasi::RIGHT_PATH_UNLINK_FILE)?;
     dir.unlink_file(file.as_os_str().as_bytes())
 }
 
 pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
-    let (old, old_file) = open_parent(old, libc::__WASI_RIGHT_PATH_RENAME_SOURCE)?;
-    let (new, new_file) = open_parent(new, libc::__WASI_RIGHT_PATH_RENAME_TARGET)?;
+    let (old, old_file) = open_parent(old, wasi::RIGHT_PATH_RENAME_SOURCE)?;
+    let (new, new_file) = open_parent(new, wasi::RIGHT_PATH_RENAME_TARGET)?;
     old.rename(
         old_file.as_os_str().as_bytes(),
         &new,
@@ -529,12 +523,12 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
 }
 
 pub fn rmdir(p: &Path) -> io::Result<()> {
-    let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_REMOVE_DIRECTORY)?;
+    let (dir, file) = open_parent(p, wasi::RIGHT_PATH_REMOVE_DIRECTORY)?;
     dir.remove_directory(file.as_os_str().as_bytes())
 }
 
 pub fn readlink(p: &Path) -> io::Result<PathBuf> {
-    let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_READLINK)?;
+    let (dir, file) = open_parent(p, wasi::RIGHT_PATH_READLINK)?;
     read_link(&dir, &file)
 }
 
@@ -570,15 +564,15 @@ fn read_link(fd: &WasiFd, file: &Path) -> io::Result<PathBuf> {
 }
 
 pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
-    let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_SYMLINK)?;
+    let (dst, dst_file) = open_parent(dst, wasi::RIGHT_PATH_SYMLINK)?;
     dst.symlink(src.as_os_str().as_bytes(), dst_file.as_os_str().as_bytes())
 }
 
 pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
-    let (src, src_file) = open_parent(src, libc::__WASI_RIGHT_PATH_LINK_SOURCE)?;
-    let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_LINK_TARGET)?;
+    let (src, src_file) = open_parent(src, wasi::RIGHT_PATH_LINK_SOURCE)?;
+    let (dst, dst_file) = open_parent(dst, wasi::RIGHT_PATH_LINK_TARGET)?;
     src.link(
-        libc::__WASI_LOOKUP_SYMLINK_FOLLOW,
+        wasi::LOOKUP_SYMLINK_FOLLOW,
         src_file.as_os_str().as_bytes(),
         &dst,
         dst_file.as_os_str().as_bytes(),
@@ -586,23 +580,22 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
 }
 
 pub fn stat(p: &Path) -> io::Result<FileAttr> {
-    let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?;
-    metadata_at(&dir, libc::__WASI_LOOKUP_SYMLINK_FOLLOW, &file)
+    let (dir, file) = open_parent(p, wasi::RIGHT_PATH_FILESTAT_GET)?;
+    metadata_at(&dir, wasi::LOOKUP_SYMLINK_FOLLOW, &file)
 }
 
 pub fn lstat(p: &Path) -> io::Result<FileAttr> {
-    let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?;
+    let (dir, file) = open_parent(p, wasi::RIGHT_PATH_FILESTAT_GET)?;
     metadata_at(&dir, 0, &file)
 }
 
 fn metadata_at(
     fd: &WasiFd,
-    flags: libc::__wasi_lookupflags_t,
+    flags: wasi::LookupFlags,
     path: &Path,
 ) -> io::Result<FileAttr> {
-    let mut ret = FileAttr::zero();
-    fd.path_filestat_get(flags, path.as_os_str().as_bytes(), &mut ret.meta)?;
-    Ok(ret)
+    fd.path_filestat_get(flags, path.as_os_str().as_bytes())
+        .map(|meta| FileAttr { meta })
 }
 
 pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
@@ -652,12 +645,12 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result<File> {
 /// to any preopened file descriptor.
 fn open_parent(
     p: &Path,
-    rights: libc::__wasi_rights_t,
+    rights: wasi::Rights,
 ) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
     let p = CString::new(p.as_os_str().as_bytes())?;
     unsafe {
         let mut ret = ptr::null();
-        let fd = __wasilibc_find_relpath(p.as_ptr(), rights, 0, &mut ret);
+        let fd = libc::__wasilibc_find_relpath(p.as_ptr(), rights, 0, &mut ret);
         if fd == -1 {
             let msg = format!(
                 "failed to find a preopened file descriptor \
@@ -677,15 +670,4 @@ fn open_parent(
 
         return Ok((ManuallyDrop::new(WasiFd::from_raw(fd as u32)), path));
     }
-
-    // FIXME(rust-lang/libc#1314) use the `libc` crate for this when the API
-    // there is published
-    extern "C" {
-        pub fn __wasilibc_find_relpath(
-            path: *const libc::c_char,
-            rights_base: libc::__wasi_rights_t,
-            rights_inheriting: libc::__wasi_rights_t,
-            relative_path: *mut *const libc::c_char,
-        ) -> libc::c_int;
-    }
 }
diff --git a/src/libstd/sys/wasi/io.rs b/src/libstd/sys/wasi/io.rs
index ffecca5d1b6..4be92faed30 100644
--- a/src/libstd/sys/wasi/io.rs
+++ b/src/libstd/sys/wasi/io.rs
@@ -1,11 +1,12 @@
 use crate::marker::PhantomData;
 use crate::slice;
 
-use libc::{__wasi_ciovec_t, __wasi_iovec_t, c_void};
+use ::wasi::wasi_unstable as wasi;
+use core::ffi::c_void;
 
 #[repr(transparent)]
 pub struct IoSlice<'a> {
-    vec: __wasi_ciovec_t,
+    vec: wasi::CIoVec,
     _p: PhantomData<&'a [u8]>,
 }
 
@@ -13,7 +14,7 @@ impl<'a> IoSlice<'a> {
     #[inline]
     pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
         IoSlice {
-            vec: __wasi_ciovec_t {
+            vec: wasi::CIoVec {
                 buf: buf.as_ptr() as *const c_void,
                 buf_len: buf.len(),
             },
@@ -43,7 +44,7 @@ impl<'a> IoSlice<'a> {
 
 #[repr(transparent)]
 pub struct IoSliceMut<'a> {
-    vec: __wasi_iovec_t,
+    vec: wasi::IoVec,
     _p: PhantomData<&'a mut [u8]>,
 }
 
@@ -51,7 +52,7 @@ impl<'a> IoSliceMut<'a> {
     #[inline]
     pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
         IoSliceMut {
-            vec: __wasi_iovec_t {
+            vec: wasi::IoVec {
                 buf: buf.as_mut_ptr() as *mut c_void,
                 buf_len: buf.len()
             },
diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs
index f842869e08e..517e3be9cb5 100644
--- a/src/libstd/sys/wasi/mod.rs
+++ b/src/libstd/sys/wasi/mod.rs
@@ -14,10 +14,10 @@
 //! compiling for wasm. That way it's a compile time error for something that's
 //! guaranteed to be a runtime error!
 
-use libc;
-use crate::io::{Error, ErrorKind};
+use crate::io as std_io;
 use crate::mem;
 use crate::os::raw::c_char;
+use ::wasi::wasi_unstable as wasi;
 
 pub mod alloc;
 pub mod args;
@@ -56,16 +56,43 @@ pub mod ext;
 pub fn init() {
 }
 
-pub fn unsupported<T>() -> crate::io::Result<T> {
+pub fn unsupported<T>() -> std_io::Result<T> {
     Err(unsupported_err())
 }
 
-pub fn unsupported_err() -> Error {
-    Error::new(ErrorKind::Other, "operation not supported on wasm yet")
+pub fn unsupported_err() -> std_io::Error {
+    std_io::Error::new(
+        std_io::ErrorKind::Other,
+        "operation not supported on wasm yet",
+    )
 }
 
-pub fn decode_error_kind(_code: i32) -> ErrorKind {
-    ErrorKind::Other
+pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
+    use std_io::ErrorKind::*;
+    if errno > u16::max_value() as i32 || errno < 0 {
+        return Other;
+    }
+    let code = match wasi::Error::new(errno as u16) {
+        Some(code) => code,
+        None => return Other,
+    };
+    match code {
+        wasi::ECONNREFUSED => ConnectionRefused,
+        wasi::ECONNRESET => ConnectionReset,
+        wasi::EPERM | wasi::EACCES => PermissionDenied,
+        wasi::EPIPE => BrokenPipe,
+        wasi::ENOTCONN => NotConnected,
+        wasi::ECONNABORTED => ConnectionAborted,
+        wasi::EADDRNOTAVAIL => AddrNotAvailable,
+        wasi::EADDRINUSE => AddrInUse,
+        wasi::ENOENT => NotFound,
+        wasi::EINTR => Interrupted,
+        wasi::EINVAL => InvalidInput,
+        wasi::ETIMEDOUT => TimedOut,
+        wasi::EEXIST => AlreadyExists,
+        wasi::EAGAIN => WouldBlock,
+        _ => Other,
+    }
 }
 
 // This enum is used as the storage for a bunch of types which can't actually
@@ -89,40 +116,16 @@ pub unsafe fn abort_internal() -> ! {
 pub fn hashmap_random_keys() -> (u64, u64) {
     let mut ret = (0u64, 0u64);
     unsafe {
-        let base = &mut ret as *mut (u64, u64) as *mut libc::c_void;
+        let base = &mut ret as *mut (u64, u64) as *mut core::ffi::c_void;
         let len = mem::size_of_val(&ret);
-        cvt_wasi(libc::__wasi_random_get(base, len)).unwrap();
-    }
-    return ret
-}
-
-#[doc(hidden)]
-pub trait IsMinusOne {
-    fn is_minus_one(&self) -> bool;
-}
-
-macro_rules! impl_is_minus_one {
-    ($($t:ident)*) => ($(impl IsMinusOne for $t {
-        fn is_minus_one(&self) -> bool {
-            *self == -1
+        let ret = wasi::raw::__wasi_random_get(base, len);
+        if ret != 0 {
+            panic!("__wasi_random_get failure")
         }
-    })*)
-}
-
-impl_is_minus_one! { i8 i16 i32 i64 isize }
-
-pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
-    if t.is_minus_one() {
-        Err(Error::last_os_error())
-    } else {
-        Ok(t)
     }
+    return ret
 }
 
-pub fn cvt_wasi(r: u16) -> crate::io::Result<()> {
-    if r != libc::__WASI_ESUCCESS {
-        Err(Error::from_raw_os_error(r as i32))
-    } else {
-        Ok(())
-    }
+fn err2io(err: wasi::Error) -> std_io::Error {
+    std_io::Error::from_raw_os_error(err.get() as i32)
 }
diff --git a/src/libstd/sys/wasi/os.rs b/src/libstd/sys/wasi/os.rs
index 822ea02a11b..feee8407825 100644
--- a/src/libstd/sys/wasi/os.rs
+++ b/src/libstd/sys/wasi/os.rs
@@ -9,7 +9,7 @@ use crate::path::{self, PathBuf};
 use crate::ptr;
 use crate::str;
 use crate::sys::memchr;
-use crate::sys::{cvt, unsupported, Void};
+use crate::sys::{unsupported, Void};
 use crate::vec;
 
 #[cfg(not(target_feature = "atomics"))]
@@ -28,16 +28,11 @@ pub fn errno() -> i32 {
 }
 
 pub fn error_string(errno: i32) -> String {
-    extern {
-        fn strerror_r(errnum: libc::c_int, buf: *mut libc::c_char,
-                      buflen: libc::size_t) -> libc::c_int;
-    }
-
     let mut buf = [0 as libc::c_char; 1024];
 
     let p = buf.as_mut_ptr();
     unsafe {
-        if strerror_r(errno as libc::c_int, p, buf.len()) < 0 {
+        if libc::strerror_r(errno as libc::c_int, p, buf.len()) < 0 {
             panic!("strerror_r failure");
         }
         str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned()
@@ -89,7 +84,6 @@ impl StdError for JoinPathsError {
 pub fn current_exe() -> io::Result<PathBuf> {
     unsupported()
 }
-
 pub struct Env {
     iter: vec::IntoIter<(OsString, OsString)>,
     _dont_send_or_sync_me: PhantomData<*mut ()>,
@@ -182,3 +176,26 @@ pub fn exit(code: i32) -> ! {
 pub fn getpid() -> u32 {
     panic!("unsupported");
 }
+
+#[doc(hidden)]
+pub trait IsMinusOne {
+    fn is_minus_one(&self) -> bool;
+}
+
+macro_rules! impl_is_minus_one {
+    ($($t:ident)*) => ($(impl IsMinusOne for $t {
+        fn is_minus_one(&self) -> bool {
+            *self == -1
+        }
+    })*)
+}
+
+impl_is_minus_one! { i8 i16 i32 i64 isize }
+
+fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> {
+    if t.is_minus_one() {
+        Err(io::Error::last_os_error())
+    } else {
+        Ok(t)
+    }
+}
diff --git a/src/libstd/sys/wasi/process.rs b/src/libstd/sys/wasi/process.rs
index 788b829f4ba..1c4d028b761 100644
--- a/src/libstd/sys/wasi/process.rs
+++ b/src/libstd/sys/wasi/process.rs
@@ -4,14 +4,16 @@ use crate::io;
 use crate::sys::fs::File;
 use crate::sys::pipe::AnonPipe;
 use crate::sys::{unsupported, Void};
-use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
+use crate::sys_common::process::CommandEnv;
+
+pub use crate::ffi::OsString as EnvKey;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Command
 ////////////////////////////////////////////////////////////////////////////////
 
 pub struct Command {
-    env: CommandEnv<DefaultEnvKey>
+    env: CommandEnv
 }
 
 // passed back to std::process with the pipes connected to the child, if any
@@ -38,7 +40,7 @@ impl Command {
     pub fn arg(&mut self, _arg: &OsStr) {
     }
 
-    pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+    pub fn env_mut(&mut self) -> &mut CommandEnv {
         &mut self.env
     }
 
diff --git a/src/libstd/sys/wasi/stdio.rs b/src/libstd/sys/wasi/stdio.rs
index 2bf8d803c01..1d57b9922e5 100644
--- a/src/libstd/sys/wasi/stdio.rs
+++ b/src/libstd/sys/wasi/stdio.rs
@@ -1,8 +1,9 @@
 use crate::io::{self, IoSlice, IoSliceMut};
-use crate::libc;
 use crate::mem::ManuallyDrop;
 use crate::sys::fd::WasiFd;
 
+use ::wasi::wasi_unstable as wasi;
+
 pub struct Stdin;
 pub struct Stdout;
 pub struct Stderr;
@@ -17,7 +18,7 @@ impl Stdin {
     }
 
     pub fn read_vectored(&self, data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDIN_FILENO as u32) })
+        ManuallyDrop::new(unsafe { WasiFd::from_raw(wasi::STDIN_FD) })
             .read(data)
     }
 }
@@ -32,7 +33,7 @@ impl Stdout {
     }
 
     pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
-        ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDOUT_FILENO as u32) })
+        ManuallyDrop::new(unsafe { WasiFd::from_raw(wasi::STDOUT_FD) })
             .write(data)
     }
 
@@ -51,7 +52,7 @@ impl Stderr {
     }
 
     pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
-        ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDERR_FILENO as u32) })
+        ManuallyDrop::new(unsafe { WasiFd::from_raw(wasi::STDERR_FD) })
             .write(data)
     }
 
@@ -73,7 +74,7 @@ impl io::Write for Stderr {
 pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
 
 pub fn is_ebadf(err: &io::Error) -> bool {
-    err.raw_os_error() == Some(libc::__WASI_EBADF as i32)
+    err.raw_os_error() == Some(wasi::EBADF.get() as i32)
 }
 
 pub fn panic_output() -> Option<impl io::Write> {
diff --git a/src/libstd/sys/wasi/thread.rs b/src/libstd/sys/wasi/thread.rs
index 5e69e4d948f..28a504f1979 100644
--- a/src/libstd/sys/wasi/thread.rs
+++ b/src/libstd/sys/wasi/thread.rs
@@ -1,10 +1,10 @@
-use crate::cmp;
 use crate::ffi::CStr;
 use crate::io;
-use crate::sys::cvt;
+use crate::mem;
 use crate::sys::{unsupported, Void};
 use crate::time::Duration;
-use libc;
+
+use ::wasi::wasi_unstable as wasi;
 
 pub struct Thread(Void);
 
@@ -19,8 +19,8 @@ impl Thread {
     }
 
     pub fn yield_now() {
-        let ret = unsafe { libc::__wasi_sched_yield() };
-        debug_assert_eq!(ret, 0);
+        let ret = wasi::sched_yield();
+        debug_assert_eq!(ret, Ok(()));
     }
 
     pub fn set_name(_name: &CStr) {
@@ -28,19 +28,37 @@ impl Thread {
     }
 
     pub fn sleep(dur: Duration) {
-        let mut secs = dur.as_secs();
-        let mut nsecs = dur.subsec_nanos() as i32;
-
-        unsafe {
-            while secs > 0 || nsecs > 0 {
-                let mut ts = libc::timespec {
-                    tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t,
-                    tv_nsec: nsecs,
-                };
-                secs -= ts.tv_sec as u64;
-                cvt(libc::nanosleep(&ts, &mut ts)).unwrap();
-                nsecs = 0;
-            }
+        let nanos = dur.as_nanos();
+        assert!(nanos <= u64::max_value() as u128);
+
+        const CLOCK_ID: wasi::Userdata = 0x0123_45678;
+
+        let clock = wasi::raw::__wasi_subscription_u_clock_t {
+            identifier: CLOCK_ID,
+            clock_id: wasi::CLOCK_MONOTONIC,
+            timeout: nanos as u64,
+            precision: 0,
+            flags: 0,
+        };
+
+        let in_ = [wasi::Subscription {
+            userdata: 0,
+            type_: wasi::EVENTTYPE_CLOCK,
+            u: wasi::raw::__wasi_subscription_u { clock: clock },
+        }];
+        let (res, event) = unsafe {
+            let mut out: [wasi::Event; 1] = mem::zeroed();
+            let res = wasi::poll_oneoff(&in_, &mut out);
+            (res, out[0])
+        };
+        match (res, event) {
+            (Ok(1), wasi::Event {
+                userdata: CLOCK_ID,
+                error: 0,
+                type_: wasi::EVENTTYPE_CLOCK,
+                ..
+            }) => {}
+            _ => panic!("thread::sleep(): unexpected result of poll_oneoff"),
         }
     }
 
diff --git a/src/libstd/sys/wasi/time.rs b/src/libstd/sys/wasi/time.rs
index 3f14c80928c..4394a22f9c2 100644
--- a/src/libstd/sys/wasi/time.rs
+++ b/src/libstd/sys/wasi/time.rs
@@ -1,7 +1,5 @@
 use crate::time::Duration;
-use crate::mem;
-use crate::sys::cvt_wasi;
-use libc;
+use ::wasi::wasi_unstable as wasi;
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
 pub struct Instant(Duration);
@@ -12,23 +10,19 @@ pub struct SystemTime(Duration);
 pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
 
 fn current_time(clock: u32) -> Duration {
-    unsafe {
-        let mut ts = mem::zeroed();
-        cvt_wasi(libc::__wasi_clock_time_get(
-            clock,
-            1, // precision... seems ignored though?
-            &mut ts,
-        )).unwrap();
-        Duration::new(
-            (ts / 1_000_000_000) as u64,
-            (ts % 1_000_000_000) as u32,
-        )
-    }
+    let ts = wasi::clock_time_get(
+        clock,
+        1, // precision... seems ignored though?
+    ).unwrap();
+    Duration::new(
+        (ts / 1_000_000_000) as u64,
+        (ts % 1_000_000_000) as u32,
+    )
 }
 
 impl Instant {
     pub fn now() -> Instant {
-        Instant(current_time(libc::__WASI_CLOCK_MONOTONIC))
+        Instant(current_time(wasi::CLOCK_MONOTONIC))
     }
 
     pub const fn zero() -> Instant {
@@ -54,10 +48,10 @@ impl Instant {
 
 impl SystemTime {
     pub fn now() -> SystemTime {
-        SystemTime(current_time(libc::__WASI_CLOCK_REALTIME))
+        SystemTime(current_time(wasi::CLOCK_REALTIME))
     }
 
-    pub fn from_wasi_timestamp(ts: libc::__wasi_timestamp_t) -> SystemTime {
+    pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime {
         SystemTime(Duration::from_nanos(ts))
     }
 
diff --git a/src/libstd/sys/wasm/args.rs b/src/libstd/sys/wasm/args.rs
index b3c77b86995..8279e5280e9 100644
--- a/src/libstd/sys/wasm/args.rs
+++ b/src/libstd/sys/wasm/args.rs
@@ -1,7 +1,6 @@
 use crate::ffi::OsString;
 use crate::marker::PhantomData;
 use crate::vec;
-use crate::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
@@ -11,9 +10,8 @@ pub unsafe fn cleanup() {
 }
 
 pub fn args() -> Args {
-    let v = ArgsSysCall::perform();
     Args {
-        iter: v.into_iter(),
+        iter: Vec::new().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 56cbafcfdb8..de0bb38dc31 100644
--- a/src/libstd/sys/wasm/mod.rs
+++ b/src/libstd/sys/wasm/mod.rs
@@ -15,11 +15,6 @@
 //! guaranteed to be a runtime error!
 
 use crate::os::raw::c_char;
-use crate::ptr;
-use crate::sys::os_str::Buf;
-use crate::sys_common::{AsInner, FromInner};
-use crate::ffi::{OsString, OsStr};
-use crate::time::Duration;
 
 pub mod alloc;
 pub mod args;
@@ -89,7 +84,7 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize {
 }
 
 pub unsafe fn abort_internal() -> ! {
-    ExitSysCall::perform(1)
+    crate::arch::wasm32::unreachable()
 }
 
 // We don't have randomness yet, but I totally used a random number generator to
@@ -100,218 +95,3 @@ 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);
-            crate::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 5d21999a991..890049e8bfa 100644
--- a/src/libstd/sys/wasm/os.rs
+++ b/src/libstd/sys/wasm/os.rs
@@ -4,7 +4,7 @@ use crate::fmt;
 use crate::io;
 use crate::path::{self, PathBuf};
 use crate::str;
-use crate::sys::{unsupported, Void, ExitSysCall, GetEnvSysCall, SetEnvSysCall};
+use crate::sys::{unsupported, Void};
 
 pub fn errno() -> i32 {
     0
@@ -73,16 +73,16 @@ pub fn env() -> Env {
     panic!("not supported on web assembly")
 }
 
-pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
-    Ok(GetEnvSysCall::perform(k))
+pub fn getenv(_: &OsStr) -> io::Result<Option<OsString>> {
+    Ok(None)
 }
 
-pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
-    Ok(SetEnvSysCall::perform(k, Some(v)))
+pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
+    Err(io::Error::new(io::ErrorKind::Other, "cannot set env vars on wasm32-unknown-unknown"))
 }
 
-pub fn unsetenv(k: &OsStr) -> io::Result<()> {
-    Ok(SetEnvSysCall::perform(k, None))
+pub fn unsetenv(_: &OsStr) -> io::Result<()> {
+    Err(io::Error::new(io::ErrorKind::Other, "cannot unset env vars on wasm32-unknown-unknown"))
 }
 
 pub fn temp_dir() -> PathBuf {
@@ -94,7 +94,9 @@ pub fn home_dir() -> Option<PathBuf> {
 }
 
 pub fn exit(_code: i32) -> ! {
-    ExitSysCall::perform(_code as isize as usize)
+    unsafe {
+        crate::arch::wasm32::unreachable();
+    }
 }
 
 pub fn getpid() -> u32 {
diff --git a/src/libstd/sys/wasm/process.rs b/src/libstd/sys/wasm/process.rs
index a02e009d953..edf933d10e0 100644
--- a/src/libstd/sys/wasm/process.rs
+++ b/src/libstd/sys/wasm/process.rs
@@ -4,14 +4,16 @@ use crate::io;
 use crate::sys::fs::File;
 use crate::sys::pipe::AnonPipe;
 use crate::sys::{unsupported, Void};
-use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
+use crate::sys_common::process::CommandEnv;
+
+pub use crate::ffi::OsString as EnvKey;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Command
 ////////////////////////////////////////////////////////////////////////////////
 
 pub struct Command {
-    env: CommandEnv<DefaultEnvKey>
+    env: CommandEnv,
 }
 
 // passed back to std::process with the pipes connected to the child, if any
@@ -38,7 +40,7 @@ impl Command {
     pub fn arg(&mut self, _arg: &OsStr) {
     }
 
-    pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+    pub fn env_mut(&mut self) -> &mut CommandEnv {
         &mut self.env
     }
 
diff --git a/src/libstd/sys/wasm/stdio.rs b/src/libstd/sys/wasm/stdio.rs
index b8899a9c847..5a4e4505e93 100644
--- a/src/libstd/sys/wasm/stdio.rs
+++ b/src/libstd/sys/wasm/stdio.rs
@@ -1,5 +1,4 @@
 use crate::io;
-use crate::sys::{ReadSysCall, WriteSysCall};
 
 pub struct Stdin;
 pub struct Stdout;
@@ -12,8 +11,8 @@ impl Stdin {
 }
 
 impl io::Read for Stdin {
-    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
-        Ok(ReadSysCall::perform(0, buf))
+    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
+        Ok(0)
     }
 }
 
@@ -25,7 +24,6 @@ impl Stdout {
 
 impl io::Write for Stdout {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        WriteSysCall::perform(1, buf);
         Ok(buf.len())
     }
 
@@ -42,7 +40,6 @@ impl Stderr {
 
 impl io::Write for Stderr {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        WriteSysCall::perform(2, buf);
         Ok(buf.len())
     }
 
@@ -57,10 +54,6 @@ pub fn is_ebadf(_err: &io::Error) -> bool {
     true
 }
 
-pub fn panic_output() -> Option<impl io::Write> {
-    if cfg!(feature = "wasm_syscall") {
-        Stderr::new().ok()
-    } else {
-        None
-    }
+pub fn panic_output() -> Option<Vec<u8>> {
+    None
 }
diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/wasm/time.rs
index 3f71461eea4..dd9ad3760b0 100644
--- a/src/libstd/sys/wasm/time.rs
+++ b/src/libstd/sys/wasm/time.rs
@@ -1,5 +1,4 @@
 use crate::time::Duration;
-use crate::sys::{TimeSysCall, TimeClock};
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
 pub struct Instant(Duration);
@@ -11,7 +10,7 @@ pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
 
 impl Instant {
     pub fn now() -> Instant {
-        Instant(TimeSysCall::perform(TimeClock::Monotonic))
+        panic!("time not implemented on wasm32-unknown-unknown")
     }
 
     pub const fn zero() -> Instant {
@@ -37,7 +36,7 @@ impl Instant {
 
 impl SystemTime {
     pub fn now() -> SystemTime {
-        SystemTime(TimeSysCall::perform(TimeClock::System))
+        panic!("time not implemented on wasm32-unknown-unknown")
     }
 
     pub fn sub_time(&self, other: &SystemTime)
diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs
index 05e0ca67064..8658deb8546 100644
--- a/src/libstd/sys/windows/process.rs
+++ b/src/libstd/sys/windows/process.rs
@@ -19,7 +19,7 @@ use crate::sys::pipe::{self, AnonPipe};
 use crate::sys::stdio;
 use crate::sys::cvt;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
-use crate::sys_common::process::{CommandEnv, EnvKey};
+use crate::sys_common::process::CommandEnv;
 use crate::borrow::Borrow;
 
 use libc::{c_void, EXIT_SUCCESS, EXIT_FAILURE};
@@ -30,30 +30,28 @@ use libc::{c_void, EXIT_SUCCESS, EXIT_FAILURE};
 
 #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
 #[doc(hidden)]
-pub struct WindowsEnvKey(OsString);
+pub struct EnvKey(OsString);
 
-impl From<OsString> for WindowsEnvKey {
+impl From<OsString> for EnvKey {
     fn from(k: OsString) -> Self {
         let mut buf = k.into_inner().into_inner();
         buf.make_ascii_uppercase();
-        WindowsEnvKey(FromInner::from_inner(FromInner::from_inner(buf)))
+        EnvKey(FromInner::from_inner(FromInner::from_inner(buf)))
     }
 }
 
-impl From<WindowsEnvKey> for OsString {
-    fn from(k: WindowsEnvKey) -> Self { k.0 }
+impl From<EnvKey> for OsString {
+    fn from(k: EnvKey) -> Self { k.0 }
 }
 
-impl Borrow<OsStr> for WindowsEnvKey {
+impl Borrow<OsStr> for EnvKey {
     fn borrow(&self) -> &OsStr { &self.0 }
 }
 
-impl AsRef<OsStr> for WindowsEnvKey {
+impl AsRef<OsStr> for EnvKey {
     fn as_ref(&self) -> &OsStr { &self.0 }
 }
 
-impl EnvKey for WindowsEnvKey {}
-
 
 fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
     if str.as_ref().encode_wide().any(|b| b == 0) {
@@ -66,7 +64,7 @@ fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
 pub struct Command {
     program: OsString,
     args: Vec<OsString>,
-    env: CommandEnv<WindowsEnvKey>,
+    env: CommandEnv,
     cwd: Option<OsString>,
     flags: u32,
     detach: bool, // not currently exposed in std::process
@@ -110,7 +108,7 @@ impl Command {
     pub fn arg(&mut self, arg: &OsStr) {
         self.args.push(arg.to_os_string())
     }
-    pub fn env_mut(&mut self) -> &mut CommandEnv<WindowsEnvKey> {
+    pub fn env_mut(&mut self) -> &mut CommandEnv {
         &mut self.env
     }
     pub fn cwd(&mut self, dir: &OsStr) {
@@ -498,7 +496,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
     }
 }
 
-fn make_envp(maybe_env: Option<BTreeMap<WindowsEnvKey, OsString>>)
+fn make_envp(maybe_env: Option<BTreeMap<EnvKey, OsString>>)
              -> io::Result<(*mut c_void, Vec<u16>)> {
     // On Windows we pass an "environment block" which is not a char**, but
     // rather a concatenation of null-terminated k=v\0 sequences, with a final