about summary refs log tree commit diff
path: root/src/libstd/sys
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-07-17 00:09:49 +0000
committerbors <bors@rust-lang.org>2020-07-17 00:09:49 +0000
commit8534be72fc3b9c5f2f2dc4e4ee7b651a008e9a3e (patch)
tree9b6f6432be9c4a78fd4677f7a3125f3eb93e1a0a /src/libstd/sys
parent5c9e5df3a097e094641f16dab501ab1c4da10e9f (diff)
parent5bb9bef79577b9629b12800dcdae1d8fd52998c0 (diff)
downloadrust-8534be72fc3b9c5f2f2dc4e4ee7b651a008e9a3e.tar.gz
rust-8534be72fc3b9c5f2f2dc4e4ee7b651a008e9a3e.zip
Auto merge of #74422 - Manishearth:rollup-7mfrf6g, r=Manishearth
Rollup of 8 pull requests

Successful merges:

 - #73101 (Resolve items for cross-crate imports relative to the original module)
 - #73269 (Enable some timeouts in SGX platform)
 - #74033 (Add build support for Cargo's build-std feature.)
 - #74351 (Do not render unstable items for rustc doc)
 - #74357 (Some `Symbol` related improvements)
 - #74371 (Improve ayu rustdoc theme)
 - #74386 (Add RISC-V GNU/Linux to src/tools/build-manifest as a host platform)
 - #74398 (Clean up E0723 explanation)

Failed merges:

r? @ghost
Diffstat (limited to 'src/libstd/sys')
-rw-r--r--src/libstd/sys/mod.rs3
-rw-r--r--src/libstd/sys/sgx/abi/usercalls/mod.rs92
-rw-r--r--src/libstd/sys/sgx/condvar.rs6
-rw-r--r--src/libstd/sys/sgx/mod.rs9
-rw-r--r--src/libstd/sys/sgx/thread.rs4
-rw-r--r--src/libstd/sys/sgx/waitqueue.rs129
-rw-r--r--src/libstd/sys/unsupported/alloc.rs22
-rw-r--r--src/libstd/sys/unsupported/args.rs38
-rw-r--r--src/libstd/sys/unsupported/cmath.rs (renamed from src/libstd/sys/wasm/cmath.rs)0
-rw-r--r--src/libstd/sys/unsupported/common.rs48
-rw-r--r--src/libstd/sys/unsupported/condvar.rs (renamed from src/libstd/sys/wasm/condvar.rs)4
-rw-r--r--src/libstd/sys/unsupported/env.rs9
-rw-r--r--src/libstd/sys/unsupported/fs.rs (renamed from src/libstd/sys/wasm/fs.rs)0
-rw-r--r--src/libstd/sys/unsupported/io.rs (renamed from src/libstd/sys/wasm/io.rs)0
-rw-r--r--src/libstd/sys/unsupported/mod.rs24
-rw-r--r--src/libstd/sys/unsupported/mutex.rs (renamed from src/libstd/sys/wasm/mutex.rs)7
-rw-r--r--src/libstd/sys/unsupported/net.rs (renamed from src/libstd/sys/wasm/net.rs)0
-rw-r--r--src/libstd/sys/unsupported/os.rs (renamed from src/libstd/sys/wasm/os.rs)21
-rw-r--r--src/libstd/sys/unsupported/path.rs (renamed from src/libstd/sys/wasm/path.rs)0
-rw-r--r--src/libstd/sys/unsupported/pipe.rs (renamed from src/libstd/sys/wasm/pipe.rs)0
-rw-r--r--src/libstd/sys/unsupported/process.rs (renamed from src/libstd/sys/wasm/process.rs)0
-rw-r--r--src/libstd/sys/unsupported/rwlock.rs (renamed from src/libstd/sys/wasm/rwlock.rs)2
-rw-r--r--src/libstd/sys/unsupported/stack_overflow.rs (renamed from src/libstd/sys/wasm/stack_overflow.rs)0
-rw-r--r--src/libstd/sys/unsupported/stdio.rs (renamed from src/libstd/sys/wasm/stdio.rs)0
-rw-r--r--src/libstd/sys/unsupported/thread.rs41
-rw-r--r--src/libstd/sys/unsupported/thread_local_dtor.rs (renamed from src/libstd/sys/wasm/thread_local_dtor.rs)0
-rw-r--r--src/libstd/sys/unsupported/thread_local_key.rs (renamed from src/libstd/sys/wasm/thread_local_key.rs)10
-rw-r--r--src/libstd/sys/unsupported/time.rs (renamed from src/libstd/sys/wasm/time.rs)4
-rw-r--r--src/libstd/sys/wasi/mod.rs45
-rw-r--r--src/libstd/sys/wasm/memchr.rs1
-rw-r--r--src/libstd/sys/wasm/mod.rs63
31 files changed, 450 insertions, 132 deletions
diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs
index 875ff1af920..7b5fac922d0 100644
--- a/src/libstd/sys/mod.rs
+++ b/src/libstd/sys/mod.rs
@@ -48,7 +48,8 @@ cfg_if::cfg_if! {
         mod sgx;
         pub use self::sgx::*;
     } else {
-        compile_error!("libstd doesn't compile for this platform yet");
+        mod unsupported;
+        pub use self::unsupported::*;
     }
 }
 
diff --git a/src/libstd/sys/sgx/abi/usercalls/mod.rs b/src/libstd/sys/sgx/abi/usercalls/mod.rs
index ae803ee47a6..73f1b951e74 100644
--- a/src/libstd/sys/sgx/abi/usercalls/mod.rs
+++ b/src/libstd/sys/sgx/abi/usercalls/mod.rs
@@ -1,6 +1,8 @@
 use crate::cmp;
-use crate::io::{Error as IoError, IoSlice, IoSliceMut, Result as IoResult};
-use crate::time::Duration;
+use crate::convert::TryFrom;
+use crate::io::{Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult};
+use crate::sys::rand::rdrand64;
+use crate::time::{Duration, Instant};
 
 pub(crate) mod alloc;
 #[macro_use]
@@ -149,10 +151,94 @@ pub fn exit(panic: bool) -> ! {
 
 /// Usercall `wait`. See the ABI documentation for more information.
 #[unstable(feature = "sgx_platform", issue = "56975")]
-pub fn wait(event_mask: u64, timeout: u64) -> IoResult<u64> {
+pub fn wait(event_mask: u64, mut timeout: u64) -> IoResult<u64> {
+    if timeout != WAIT_NO && timeout != WAIT_INDEFINITE {
+        // We don't want people to rely on accuracy of timeouts to make
+        // security decisions in an SGX enclave. That's why we add a random
+        // amount not exceeding +/- 10% to the timeout value to discourage
+        // people from relying on accuracy of timeouts while providing a way
+        // to make things work in other cases. Note that in the SGX threat
+        // model the enclave runner which is serving the wait usercall is not
+        // trusted to ensure accurate timeouts.
+        if let Ok(timeout_signed) = i64::try_from(timeout) {
+            let tenth = timeout_signed / 10;
+            let deviation = (rdrand64() as i64).checked_rem(tenth).unwrap_or(0);
+            timeout = timeout_signed.saturating_add(deviation) as _;
+        }
+    }
     unsafe { raw::wait(event_mask, timeout).from_sgx_result() }
 }
 
+/// This function makes an effort to wait for a non-spurious event at least as
+/// long as `duration`. Note that in general there is no guarantee about accuracy
+/// of time and timeouts in SGX model. The enclave runner serving usercalls may
+/// lie about current time and/or ignore timeout values.
+///
+/// Once the event is observed, `should_wake_up` will be used to determine
+/// whether or not the event was spurious.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn wait_timeout<F>(event_mask: u64, duration: Duration, should_wake_up: F)
+where
+    F: Fn() -> bool,
+{
+    // Calls the wait usercall and checks the result. Returns true if event was
+    // returned, and false if WouldBlock/TimedOut was returned.
+    // If duration is None, it will use WAIT_NO.
+    fn wait_checked(event_mask: u64, duration: Option<Duration>) -> bool {
+        let timeout = duration.map_or(raw::WAIT_NO, |duration| {
+            cmp::min((u64::MAX - 1) as u128, duration.as_nanos()) as u64
+        });
+        match wait(event_mask, timeout) {
+            Ok(eventset) => {
+                if event_mask == 0 {
+                    rtabort!("expected wait() to return Err, found Ok.");
+                }
+                rtassert!(eventset != 0 && eventset & !event_mask == 0);
+                true
+            }
+            Err(e) => {
+                rtassert!(e.kind() == ErrorKind::TimedOut || e.kind() == ErrorKind::WouldBlock);
+                false
+            }
+        }
+    }
+
+    match wait_checked(event_mask, Some(duration)) {
+        false => return,                    // timed out
+        true if should_wake_up() => return, // woken up
+        true => {}                          // spurious event
+    }
+
+    // Drain all cached events.
+    // Note that `event_mask != 0` is implied if we get here.
+    loop {
+        match wait_checked(event_mask, None) {
+            false => break,                     // no more cached events
+            true if should_wake_up() => return, // woken up
+            true => {}                          // spurious event
+        }
+    }
+
+    // Continue waiting, but take note of time spent waiting so we don't wait
+    // forever. We intentionally don't call `Instant::now()` before this point
+    // to avoid the cost of the `insecure_time` usercall in case there are no
+    // spurious wakeups.
+
+    let start = Instant::now();
+    let mut remaining = duration;
+    loop {
+        match wait_checked(event_mask, Some(remaining)) {
+            false => return,                    // timed out
+            true if should_wake_up() => return, // woken up
+            true => {}                          // spurious event
+        }
+        remaining = match duration.checked_sub(start.elapsed()) {
+            Some(remaining) => remaining,
+            None => break,
+        }
+    }
+}
+
 /// Usercall `send`. See the ABI documentation for more information.
 #[unstable(feature = "sgx_platform", issue = "56975")]
 pub fn send(event_set: u64, tcs: Option<Tcs>) -> IoResult<()> {
diff --git a/src/libstd/sys/sgx/condvar.rs b/src/libstd/sys/sgx/condvar.rs
index 9c5c086184d..ed6dbcf4971 100644
--- a/src/libstd/sys/sgx/condvar.rs
+++ b/src/libstd/sys/sgx/condvar.rs
@@ -31,8 +31,10 @@ impl Condvar {
         mutex.lock()
     }
 
-    pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
-        rtabort!("timeout not supported in SGX");
+    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+        let success = WaitQueue::wait_timeout(&self.inner, dur, || mutex.unlock());
+        mutex.lock();
+        success
     }
 
     #[inline]
diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs
index a4968ff7d4f..1d32eb25424 100644
--- a/src/libstd/sys/sgx/mod.rs
+++ b/src/libstd/sys/sgx/mod.rs
@@ -137,8 +137,8 @@ pub extern "C" fn __rust_abort() {
     abort_internal();
 }
 
-pub fn hashmap_random_keys() -> (u64, u64) {
-    fn rdrand64() -> u64 {
+pub mod rand {
+    pub fn rdrand64() -> u64 {
         unsafe {
             let mut ret: u64 = 0;
             for _ in 0..10 {
@@ -149,7 +149,10 @@ pub fn hashmap_random_keys() -> (u64, u64) {
             rtabort!("Failed to obtain random data");
         }
     }
-    (rdrand64(), rdrand64())
+}
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+    (self::rand::rdrand64(), self::rand::rdrand64())
 }
 
 pub use crate::sys_common::{AsInner, FromInner, IntoInner};
diff --git a/src/libstd/sys/sgx/thread.rs b/src/libstd/sys/sgx/thread.rs
index 9b515eb82de..5895f70436e 100644
--- a/src/libstd/sys/sgx/thread.rs
+++ b/src/libstd/sys/sgx/thread.rs
@@ -73,8 +73,8 @@ impl Thread {
         // FIXME: could store this pointer in TLS somewhere
     }
 
-    pub fn sleep(_dur: Duration) {
-        rtabort!("can't sleep"); // FIXME
+    pub fn sleep(dur: Duration) {
+        usercalls::wait_timeout(0, dur, || true);
     }
 
     pub fn join(self) {
diff --git a/src/libstd/sys/sgx/waitqueue.rs b/src/libstd/sys/sgx/waitqueue.rs
index 6e50f161b3b..070afa55f30 100644
--- a/src/libstd/sys/sgx/waitqueue.rs
+++ b/src/libstd/sys/sgx/waitqueue.rs
@@ -1,16 +1,17 @@
+//! A simple queue implementation for synchronization primitives.
+//!
+//! This queue is used to implement condition variable and mutexes.
+//!
+//! Users of this API are expected to use the `WaitVariable<T>` type. Since
+//! that type is not `Sync`, it needs to be protected by e.g., a `SpinMutex` to
+//! allow shared access.
+//!
+//! Since userspace may send spurious wake-ups, the wakeup event state is
+//! recorded in the enclave. The wakeup event state is protected by a spinlock.
+//! The queue and associated wait state are stored in a `WaitVariable`.
 use crate::num::NonZeroUsize;
-/// A simple queue implementation for synchronization primitives.
-///
-/// This queue is used to implement condition variable and mutexes.
-///
-/// Users of this API are expected to use the `WaitVariable<T>` type. Since
-/// that type is not `Sync`, it needs to be protected by e.g., a `SpinMutex` to
-/// allow shared access.
-///
-/// Since userspace may send spurious wake-ups, the wakeup event state is
-/// recorded in the enclave. The wakeup event state is protected by a spinlock.
-/// The queue and associated wait state are stored in a `WaitVariable`.
 use crate::ops::{Deref, DerefMut};
+use crate::time::Duration;
 
 use super::abi::thread;
 use super::abi::usercalls;
@@ -158,6 +159,34 @@ impl WaitQueue {
         }
     }
 
+    /// Adds the calling thread to the `WaitVariable`'s wait queue, then wait
+    /// until a wakeup event or timeout. If event was observed, returns true.
+    /// If not, it will remove the calling thread from the wait queue.
+    pub fn wait_timeout<T, F: FnOnce()>(
+        lock: &SpinMutex<WaitVariable<T>>,
+        timeout: Duration,
+        before_wait: F,
+    ) -> bool {
+        // very unsafe: check requirements of UnsafeList::push
+        unsafe {
+            let mut entry = UnsafeListEntry::new(SpinMutex::new(WaitEntry {
+                tcs: thread::current(),
+                wake: false,
+            }));
+            let entry_lock = lock.lock().queue.inner.push(&mut entry);
+            before_wait();
+            usercalls::wait_timeout(EV_UNPARK, timeout, || entry_lock.lock().wake);
+            // acquire the wait queue's lock first to avoid deadlock.
+            let mut guard = lock.lock();
+            let success = entry_lock.lock().wake;
+            if !success {
+                // nobody is waking us up, so remove our entry from the wait queue.
+                guard.queue.inner.remove(&mut entry);
+            }
+            success
+        }
+    }
+
     /// Either find the next waiter on the wait queue, or return the mutex
     /// guard unchanged.
     ///
@@ -325,6 +354,31 @@ mod unsafe_list {
                 Some((*first.as_ptr()).value.as_ref().unwrap())
             }
         }
+
+        /// Removes an entry from the list.
+        ///
+        /// # Safety
+        ///
+        /// The caller must ensure that `entry` has been pushed onto `self`
+        /// prior to this call and has not moved since then.
+        pub unsafe fn remove(&mut self, entry: &mut UnsafeListEntry<T>) {
+            rtassert!(!self.is_empty());
+            // BEFORE:
+            //     /----\ next ---> /-----\ next ---> /----\
+            // ... |prev|           |entry|           |next| ...
+            //     \----/ <--- prev \-----/ <--- prev \----/
+            //
+            // AFTER:
+            //     /----\ next ---> /----\
+            // ... |prev|           |next| ...
+            //     \----/ <--- prev \----/
+            let mut prev = entry.prev;
+            let mut next = entry.next;
+            prev.as_mut().next = next;
+            next.as_mut().prev = prev;
+            entry.next = NonNull::dangling();
+            entry.prev = NonNull::dangling();
+        }
     }
 
     #[cfg(test)]
@@ -355,6 +409,51 @@ mod unsafe_list {
         }
 
         #[test]
+        fn push_remove() {
+            unsafe {
+                let mut node = UnsafeListEntry::new(1234);
+                let mut list = UnsafeList::new();
+                assert_eq!(list.push(&mut node), &1234);
+                list.remove(&mut node);
+                assert_empty(&mut list);
+            }
+        }
+
+        #[test]
+        fn push_remove_pop() {
+            unsafe {
+                let mut node1 = UnsafeListEntry::new(11);
+                let mut node2 = UnsafeListEntry::new(12);
+                let mut node3 = UnsafeListEntry::new(13);
+                let mut node4 = UnsafeListEntry::new(14);
+                let mut node5 = UnsafeListEntry::new(15);
+                let mut list = UnsafeList::new();
+                assert_eq!(list.push(&mut node1), &11);
+                assert_eq!(list.push(&mut node2), &12);
+                assert_eq!(list.push(&mut node3), &13);
+                assert_eq!(list.push(&mut node4), &14);
+                assert_eq!(list.push(&mut node5), &15);
+
+                list.remove(&mut node1);
+                assert_eq!(list.pop().unwrap(), &12);
+                list.remove(&mut node3);
+                assert_eq!(list.pop().unwrap(), &14);
+                list.remove(&mut node5);
+                assert_empty(&mut list);
+
+                assert_eq!(list.push(&mut node1), &11);
+                assert_eq!(list.pop().unwrap(), &11);
+                assert_empty(&mut list);
+
+                assert_eq!(list.push(&mut node3), &13);
+                assert_eq!(list.push(&mut node4), &14);
+                list.remove(&mut node3);
+                list.remove(&mut node4);
+                assert_empty(&mut list);
+            }
+        }
+
+        #[test]
         fn complex_pushes_pops() {
             unsafe {
                 let mut node1 = UnsafeListEntry::new(1234);
@@ -474,7 +573,7 @@ mod spin_mutex {
         use super::*;
         use crate::sync::Arc;
         use crate::thread;
-        use crate::time::{Duration, SystemTime};
+        use crate::time::Duration;
 
         #[test]
         fn sleep() {
@@ -485,11 +584,7 @@ mod spin_mutex {
                 *mutex2.lock() = 1;
             });
 
-            // "sleep" for 50ms
-            // FIXME: https://github.com/fortanix/rust-sgx/issues/31
-            let start = SystemTime::now();
-            let max = Duration::from_millis(50);
-            while start.elapsed().unwrap() < max {}
+            thread::sleep(Duration::from_millis(50));
 
             assert_eq!(*guard, 0);
             drop(guard);
diff --git a/src/libstd/sys/unsupported/alloc.rs b/src/libstd/sys/unsupported/alloc.rs
new file mode 100644
index 00000000000..8d5d0a2f5cc
--- /dev/null
+++ b/src/libstd/sys/unsupported/alloc.rs
@@ -0,0 +1,22 @@
+use crate::alloc::{GlobalAlloc, Layout, System};
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+    #[inline]
+    unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
+        0 as *mut u8
+    }
+
+    #[inline]
+    unsafe fn alloc_zeroed(&self, _layout: Layout) -> *mut u8 {
+        0 as *mut u8
+    }
+
+    #[inline]
+    unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
+
+    #[inline]
+    unsafe fn realloc(&self, _ptr: *mut u8, _layout: Layout, _new_size: usize) -> *mut u8 {
+        0 as *mut u8
+    }
+}
diff --git a/src/libstd/sys/unsupported/args.rs b/src/libstd/sys/unsupported/args.rs
new file mode 100644
index 00000000000..71d0c5fa13e
--- /dev/null
+++ b/src/libstd/sys/unsupported/args.rs
@@ -0,0 +1,38 @@
+use crate::ffi::OsString;
+
+pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
+pub unsafe fn cleanup() {}
+
+pub struct Args {}
+
+pub fn args() -> Args {
+    Args {}
+}
+
+impl Args {
+    pub fn inner_debug(&self) -> &[OsString] {
+        &[]
+    }
+}
+
+impl Iterator for Args {
+    type Item = OsString;
+    fn next(&mut self) -> Option<OsString> {
+        None
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (0, Some(0))
+    }
+}
+
+impl ExactSizeIterator for Args {
+    fn len(&self) -> usize {
+        0
+    }
+}
+
+impl DoubleEndedIterator for Args {
+    fn next_back(&mut self) -> Option<OsString> {
+        None
+    }
+}
diff --git a/src/libstd/sys/wasm/cmath.rs b/src/libstd/sys/unsupported/cmath.rs
index 304cf906b2a..304cf906b2a 100644
--- a/src/libstd/sys/wasm/cmath.rs
+++ b/src/libstd/sys/unsupported/cmath.rs
diff --git a/src/libstd/sys/unsupported/common.rs b/src/libstd/sys/unsupported/common.rs
new file mode 100644
index 00000000000..80311d26819
--- /dev/null
+++ b/src/libstd/sys/unsupported/common.rs
@@ -0,0 +1,48 @@
+use crate::io as std_io;
+
+pub mod memchr {
+    pub use core::slice::memchr::{memchr, memrchr};
+}
+
+pub use crate::sys_common::os_str_bytes as os_str;
+
+// This is not necessarily correct. May want to consider making it part of the
+// spec definition?
+use crate::os::raw::c_char;
+
+#[cfg(not(test))]
+pub fn init() {}
+
+pub fn unsupported<T>() -> std_io::Result<T> {
+    Err(unsupported_err())
+}
+
+pub fn unsupported_err() -> std_io::Error {
+    std_io::Error::new(std_io::ErrorKind::Other, "operation not supported on this platform")
+}
+
+pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind {
+    crate::io::ErrorKind::Other
+}
+
+pub fn abort_internal() -> ! {
+    core::intrinsics::abort();
+}
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+    (1, 2)
+}
+
+// This enum is used as the storage for a bunch of types which can't actually
+// exist.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub enum Void {}
+
+pub unsafe fn strlen(mut s: *const c_char) -> usize {
+    let mut n = 0;
+    while *s != 0 {
+        n += 1;
+        s = s.offset(1);
+    }
+    return n;
+}
diff --git a/src/libstd/sys/wasm/condvar.rs b/src/libstd/sys/unsupported/condvar.rs
index 9fd781c7282..a578eee8ccc 100644
--- a/src/libstd/sys/wasm/condvar.rs
+++ b/src/libstd/sys/unsupported/condvar.rs
@@ -18,11 +18,11 @@ impl Condvar {
     pub unsafe fn notify_all(&self) {}
 
     pub unsafe fn wait(&self, _mutex: &Mutex) {
-        panic!("can't block with web assembly")
+        panic!("condvar wait not supported")
     }
 
     pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
-        panic!("can't block with web assembly");
+        panic!("condvar wait not supported");
     }
 
     #[inline]
diff --git a/src/libstd/sys/unsupported/env.rs b/src/libstd/sys/unsupported/env.rs
new file mode 100644
index 00000000000..d2efec506c5
--- /dev/null
+++ b/src/libstd/sys/unsupported/env.rs
@@ -0,0 +1,9 @@
+pub mod os {
+    pub const FAMILY: &str = "";
+    pub const OS: &str = "";
+    pub const DLL_PREFIX: &str = "";
+    pub const DLL_SUFFIX: &str = "";
+    pub const DLL_EXTENSION: &str = "";
+    pub const EXE_SUFFIX: &str = "";
+    pub const EXE_EXTENSION: &str = "";
+}
diff --git a/src/libstd/sys/wasm/fs.rs b/src/libstd/sys/unsupported/fs.rs
index ecb5b51cccd..ecb5b51cccd 100644
--- a/src/libstd/sys/wasm/fs.rs
+++ b/src/libstd/sys/unsupported/fs.rs
diff --git a/src/libstd/sys/wasm/io.rs b/src/libstd/sys/unsupported/io.rs
index d5f475b4310..d5f475b4310 100644
--- a/src/libstd/sys/wasm/io.rs
+++ b/src/libstd/sys/unsupported/io.rs
diff --git a/src/libstd/sys/unsupported/mod.rs b/src/libstd/sys/unsupported/mod.rs
new file mode 100644
index 00000000000..87f655eecd5
--- /dev/null
+++ b/src/libstd/sys/unsupported/mod.rs
@@ -0,0 +1,24 @@
+pub mod alloc;
+pub mod args;
+pub mod cmath;
+pub mod condvar;
+pub mod env;
+pub mod fs;
+pub mod io;
+pub mod mutex;
+pub mod net;
+pub mod os;
+pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod rwlock;
+pub mod stack_overflow;
+pub mod stdio;
+pub mod thread;
+#[cfg(target_thread_local)]
+pub mod thread_local_dtor;
+pub mod thread_local_key;
+pub mod time;
+
+mod common;
+pub use common::*;
diff --git a/src/libstd/sys/wasm/mutex.rs b/src/libstd/sys/unsupported/mutex.rs
index 7aaf1b3a343..9ef8af52eb5 100644
--- a/src/libstd/sys/wasm/mutex.rs
+++ b/src/libstd/sys/unsupported/mutex.rs
@@ -5,9 +5,10 @@ pub struct Mutex {
 }
 
 unsafe impl Send for Mutex {}
-unsafe impl Sync for Mutex {} // no threads on wasm
+unsafe impl Sync for Mutex {} // no threads on this platform
 
 impl Mutex {
+    #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")]
     pub const fn new() -> Mutex {
         Mutex { locked: UnsafeCell::new(false) }
     }
@@ -42,8 +43,8 @@ impl Mutex {
     pub unsafe fn destroy(&self) {}
 }
 
-// All empty stubs because wasm has no threads yet, so lock acquisition always
-// succeeds.
+// All empty stubs because this platform does not yet support threads, so lock
+// acquisition always succeeds.
 pub struct ReentrantMutex {}
 
 impl ReentrantMutex {
diff --git a/src/libstd/sys/wasm/net.rs b/src/libstd/sys/unsupported/net.rs
index 5c9f1098f9b..5c9f1098f9b 100644
--- a/src/libstd/sys/wasm/net.rs
+++ b/src/libstd/sys/unsupported/net.rs
diff --git a/src/libstd/sys/wasm/os.rs b/src/libstd/sys/unsupported/os.rs
index 91afdc8a5a0..0615780c242 100644
--- a/src/libstd/sys/wasm/os.rs
+++ b/src/libstd/sys/unsupported/os.rs
@@ -1,10 +1,9 @@
+use super::{unsupported, Void};
 use crate::error::Error as StdError;
 use crate::ffi::{OsStr, OsString};
 use crate::fmt;
 use crate::io;
 use crate::path::{self, PathBuf};
-use crate::str;
-use crate::sys::{unsupported, Void};
 
 pub fn errno() -> i32 {
     0
@@ -48,14 +47,14 @@ where
 
 impl fmt::Display for JoinPathsError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        "not supported on wasm yet".fmt(f)
+        "not supported on this platform yet".fmt(f)
     }
 }
 
 impl StdError for JoinPathsError {
     #[allow(deprecated)]
     fn description(&self) -> &str {
-        "not supported on wasm yet"
+        "not supported on this platform yet"
     }
 }
 
@@ -73,7 +72,7 @@ impl Iterator for Env {
 }
 
 pub fn env() -> Env {
-    panic!("not supported on web assembly")
+    panic!("not supported on this platform")
 }
 
 pub fn getenv(_: &OsStr) -> io::Result<Option<OsString>> {
@@ -81,15 +80,15 @@ pub fn getenv(_: &OsStr) -> io::Result<Option<OsString>> {
 }
 
 pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
-    Err(io::Error::new(io::ErrorKind::Other, "cannot set env vars on wasm32-unknown-unknown"))
+    Err(io::Error::new(io::ErrorKind::Other, "cannot set env vars on this platform"))
 }
 
 pub fn unsetenv(_: &OsStr) -> io::Result<()> {
-    Err(io::Error::new(io::ErrorKind::Other, "cannot unset env vars on wasm32-unknown-unknown"))
+    Err(io::Error::new(io::ErrorKind::Other, "cannot unset env vars on this platform"))
 }
 
 pub fn temp_dir() -> PathBuf {
-    panic!("no filesystem on wasm")
+    panic!("no filesystem on this platform")
 }
 
 pub fn home_dir() -> Option<PathBuf> {
@@ -97,11 +96,9 @@ pub fn home_dir() -> Option<PathBuf> {
 }
 
 pub fn exit(_code: i32) -> ! {
-    unsafe {
-        crate::arch::wasm32::unreachable();
-    }
+    crate::intrinsics::abort()
 }
 
 pub fn getpid() -> u32 {
-    panic!("no pids on wasm")
+    panic!("no pids on this platform")
 }
diff --git a/src/libstd/sys/wasm/path.rs b/src/libstd/sys/unsupported/path.rs
index 840a7ae0426..840a7ae0426 100644
--- a/src/libstd/sys/wasm/path.rs
+++ b/src/libstd/sys/unsupported/path.rs
diff --git a/src/libstd/sys/wasm/pipe.rs b/src/libstd/sys/unsupported/pipe.rs
index 10d0925823e..10d0925823e 100644
--- a/src/libstd/sys/wasm/pipe.rs
+++ b/src/libstd/sys/unsupported/pipe.rs
diff --git a/src/libstd/sys/wasm/process.rs b/src/libstd/sys/unsupported/process.rs
index 4702e5c5492..4702e5c5492 100644
--- a/src/libstd/sys/wasm/process.rs
+++ b/src/libstd/sys/unsupported/process.rs
diff --git a/src/libstd/sys/wasm/rwlock.rs b/src/libstd/sys/unsupported/rwlock.rs
index a59944482e9..d37f34ac935 100644
--- a/src/libstd/sys/wasm/rwlock.rs
+++ b/src/libstd/sys/unsupported/rwlock.rs
@@ -5,7 +5,7 @@ pub struct RWLock {
 }
 
 unsafe impl Send for RWLock {}
-unsafe impl Sync for RWLock {} // no threads on wasm
+unsafe impl Sync for RWLock {} // no threads on this platform
 
 impl RWLock {
     pub const fn new() -> RWLock {
diff --git a/src/libstd/sys/wasm/stack_overflow.rs b/src/libstd/sys/unsupported/stack_overflow.rs
index 32555394cd5..32555394cd5 100644
--- a/src/libstd/sys/wasm/stack_overflow.rs
+++ b/src/libstd/sys/unsupported/stack_overflow.rs
diff --git a/src/libstd/sys/wasm/stdio.rs b/src/libstd/sys/unsupported/stdio.rs
index 5a4e4505e93..5a4e4505e93 100644
--- a/src/libstd/sys/wasm/stdio.rs
+++ b/src/libstd/sys/unsupported/stdio.rs
diff --git a/src/libstd/sys/unsupported/thread.rs b/src/libstd/sys/unsupported/thread.rs
new file mode 100644
index 00000000000..20ae309db30
--- /dev/null
+++ b/src/libstd/sys/unsupported/thread.rs
@@ -0,0 +1,41 @@
+use super::{unsupported, Void};
+use crate::ffi::CStr;
+use crate::io;
+use crate::time::Duration;
+
+pub struct Thread(Void);
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
+
+impl Thread {
+    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
+    pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+        unsupported()
+    }
+
+    pub fn yield_now() {
+        // do nothing
+    }
+
+    pub fn set_name(_name: &CStr) {
+        // nope
+    }
+
+    pub fn sleep(_dur: Duration) {
+        panic!("can't sleep");
+    }
+
+    pub fn join(self) {
+        match self.0 {}
+    }
+}
+
+pub mod guard {
+    pub type Guard = !;
+    pub unsafe fn current() -> Option<Guard> {
+        None
+    }
+    pub unsafe fn init() -> Option<Guard> {
+        None
+    }
+}
diff --git a/src/libstd/sys/wasm/thread_local_dtor.rs b/src/libstd/sys/unsupported/thread_local_dtor.rs
index 85d66098302..85d66098302 100644
--- a/src/libstd/sys/wasm/thread_local_dtor.rs
+++ b/src/libstd/sys/unsupported/thread_local_dtor.rs
diff --git a/src/libstd/sys/wasm/thread_local_key.rs b/src/libstd/sys/unsupported/thread_local_key.rs
index f8be9863ed5..c31b61cbf56 100644
--- a/src/libstd/sys/wasm/thread_local_key.rs
+++ b/src/libstd/sys/unsupported/thread_local_key.rs
@@ -2,25 +2,25 @@ pub type Key = usize;
 
 #[inline]
 pub unsafe fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
-    panic!("should not be used on the wasm target");
+    panic!("should not be used on this target");
 }
 
 #[inline]
 pub unsafe fn set(_key: Key, _value: *mut u8) {
-    panic!("should not be used on the wasm target");
+    panic!("should not be used on this target");
 }
 
 #[inline]
 pub unsafe fn get(_key: Key) -> *mut u8 {
-    panic!("should not be used on the wasm target");
+    panic!("should not be used on this target");
 }
 
 #[inline]
 pub unsafe fn destroy(_key: Key) {
-    panic!("should not be used on the wasm target");
+    panic!("should not be used on this target");
 }
 
 #[inline]
 pub fn requires_synchronized_create() -> bool {
-    panic!("should not be used on the wasm target");
+    panic!("should not be used on this target");
 }
diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/unsupported/time.rs
index d9edc7fdc44..8aaf1777f24 100644
--- a/src/libstd/sys/wasm/time.rs
+++ b/src/libstd/sys/unsupported/time.rs
@@ -10,7 +10,7 @@ pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
 
 impl Instant {
     pub fn now() -> Instant {
-        panic!("time not implemented on wasm32-unknown-unknown")
+        panic!("time not implemented on this platform")
     }
 
     pub const fn zero() -> Instant {
@@ -36,7 +36,7 @@ impl Instant {
 
 impl SystemTime {
     pub fn now() -> SystemTime {
-        panic!("time not implemented on wasm32-unknown-unknown")
+        panic!("time not implemented on this platform")
     }
 
     pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs
index 85f5282034f..2704ff484f9 100644
--- a/src/libstd/sys/wasi/mod.rs
+++ b/src/libstd/sys/wasi/mod.rs
@@ -16,21 +16,18 @@
 
 use crate::io as std_io;
 use crate::mem;
-use crate::os::raw::c_char;
 
 pub mod alloc;
 pub mod args;
-#[path = "../wasm/cmath.rs"]
+#[path = "../unsupported/cmath.rs"]
 pub mod cmath;
-#[path = "../wasm/condvar.rs"]
+#[path = "../unsupported/condvar.rs"]
 pub mod condvar;
 pub mod env;
 pub mod fd;
 pub mod fs;
 pub mod io;
-#[path = "../wasm/memchr.rs"]
-pub mod memchr;
-#[path = "../wasm/mutex.rs"]
+#[path = "../unsupported/mutex.rs"]
 pub mod mutex;
 pub mod net;
 pub mod os;
@@ -39,28 +36,22 @@ pub mod ext;
 pub mod path;
 pub mod pipe;
 pub mod process;
-#[path = "../wasm/rwlock.rs"]
+#[path = "../unsupported/rwlock.rs"]
 pub mod rwlock;
-#[path = "../wasm/stack_overflow.rs"]
+#[path = "../unsupported/stack_overflow.rs"]
 pub mod stack_overflow;
 pub mod stdio;
 pub mod thread;
-#[path = "../wasm/thread_local_dtor.rs"]
+#[path = "../unsupported/thread_local_dtor.rs"]
 pub mod thread_local_dtor;
-#[path = "../wasm/thread_local_key.rs"]
+#[path = "../unsupported/thread_local_key.rs"]
 pub mod thread_local_key;
 pub mod time;
 
-#[cfg(not(test))]
-pub fn init() {}
-
-pub fn unsupported<T>() -> std_io::Result<T> {
-    Err(unsupported_err())
-}
-
-pub fn unsupported_err() -> std_io::Error {
-    std_io::Error::new(std_io::ErrorKind::Other, "operation not supported on wasm yet")
-}
+#[path = "../unsupported/common.rs"]
+#[allow(unused)]
+mod common;
+pub use common::*;
 
 pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
     use std_io::ErrorKind::*;
@@ -86,20 +77,6 @@ pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
     }
 }
 
-// This enum is used as the storage for a bunch of types which can't actually
-// exist.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub enum Void {}
-
-pub unsafe fn strlen(mut s: *const c_char) -> usize {
-    let mut n = 0;
-    while *s != 0 {
-        n += 1;
-        s = s.offset(1);
-    }
-    return n;
-}
-
 pub fn abort_internal() -> ! {
     unsafe { libc::abort() }
 }
diff --git a/src/libstd/sys/wasm/memchr.rs b/src/libstd/sys/wasm/memchr.rs
deleted file mode 100644
index 9967482197e..00000000000
--- a/src/libstd/sys/wasm/memchr.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub use core::slice::memchr::{memchr, memrchr};
diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs
index 6939596e52d..3de58904043 100644
--- a/src/libstd/sys/wasm/mod.rs
+++ b/src/libstd/sys/wasm/mod.rs
@@ -14,25 +14,35 @@
 //! compiling for wasm. That way it's a compile time error for something that's
 //! guaranteed to be a runtime error!
 
-use crate::os::raw::c_char;
-
 pub mod alloc;
 pub mod args;
+#[path = "../unsupported/cmath.rs"]
 pub mod cmath;
 pub mod env;
+#[path = "../unsupported/fs.rs"]
 pub mod fs;
+#[path = "../unsupported/io.rs"]
 pub mod io;
-pub mod memchr;
+#[path = "../unsupported/net.rs"]
 pub mod net;
+#[path = "../unsupported/os.rs"]
 pub mod os;
+#[path = "../unsupported/path.rs"]
 pub mod path;
+#[path = "../unsupported/pipe.rs"]
 pub mod pipe;
+#[path = "../unsupported/process.rs"]
 pub mod process;
+#[path = "../unsupported/stack_overflow.rs"]
 pub mod stack_overflow;
+#[path = "../unsupported/stdio.rs"]
 pub mod stdio;
 pub mod thread;
+#[path = "../unsupported/thread_local_dtor.rs"]
 pub mod thread_local_dtor;
+#[path = "../unsupported/thread_local_key.rs"]
 pub mod thread_local_key;
+#[path = "../unsupported/time.rs"]
 pub mod time;
 
 pub use crate::sys_common::os_str_bytes as os_str;
@@ -46,50 +56,15 @@ cfg_if::cfg_if! {
         #[path = "rwlock_atomics.rs"]
         pub mod rwlock;
     } else {
+        #[path = "../unsupported/condvar.rs"]
         pub mod condvar;
+        #[path = "../unsupported/mutex.rs"]
         pub mod mutex;
+        #[path = "../unsupported/rwlock.rs"]
         pub mod rwlock;
     }
 }
 
-#[cfg(not(test))]
-pub fn init() {}
-
-pub fn unsupported<T>() -> crate::io::Result<T> {
-    Err(unsupported_err())
-}
-
-pub fn unsupported_err() -> crate::io::Error {
-    crate::io::Error::new(crate::io::ErrorKind::Other, "operation not supported on wasm yet")
-}
-
-pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind {
-    crate::io::ErrorKind::Other
-}
-
-// This enum is used as the storage for a bunch of types which can't actually
-// exist.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub enum Void {}
-
-pub unsafe fn strlen(mut s: *const c_char) -> usize {
-    let mut n = 0;
-    while *s != 0 {
-        n += 1;
-        s = s.offset(1);
-    }
-    return n;
-}
-
-pub fn abort_internal() -> ! {
-    unsafe { crate::arch::wasm32::unreachable() }
-}
-
-// We don't have randomness yet, but I totally used a random number generator to
-// generate these numbers.
-//
-// More seriously though this is just for DOS protection in hash maps. It's ok
-// if we don't do that on wasm just yet.
-pub fn hashmap_random_keys() -> (u64, u64) {
-    (1, 2)
-}
+#[path = "../unsupported/common.rs"]
+mod common;
+pub use common::*;