about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/alloc.rs20
-rw-r--r--library/std/src/collections/hash/map.rs114
-rw-r--r--library/std/src/error.rs4
-rw-r--r--library/std/src/io/lazy.rs63
-rw-r--r--library/std/src/io/mod.rs1
-rw-r--r--library/std/src/io/stdio.rs76
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/os/linux/raw.rs1
-rw-r--r--library/std/src/panic.rs3
-rw-r--r--library/std/src/panic/tests.rs56
-rw-r--r--library/std/src/path.rs2
-rw-r--r--library/std/src/sync/condvar.rs4
-rw-r--r--library/std/src/sync/mutex.rs30
-rw-r--r--library/std/src/sys/hermit/args.rs4
-rw-r--r--library/std/src/sys/sgx/abi/mem.rs11
-rw-r--r--library/std/src/sys/sgx/ext/arch.rs29
-rw-r--r--library/std/src/sys/unix/args.rs4
-rw-r--r--library/std/src/sys/unix/ext/io.rs19
-rw-r--r--library/std/src/sys/unix/futex.rs37
-rw-r--r--library/std/src/sys/unix/mod.rs64
-rw-r--r--library/std/src/sys/unix/os.rs9
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs2
-rw-r--r--library/std/src/sys/vxworks/args.rs4
-rw-r--r--library/std/src/sys/vxworks/ext/io.rs19
-rw-r--r--library/std/src/sys/vxworks/os.rs9
-rw-r--r--library/std/src/sys/wasi/ext/io.rs19
-rw-r--r--library/std/src/sys/windows/c.rs2
-rw-r--r--library/std/src/sys/windows/compat.rs75
-rw-r--r--library/std/src/sys/windows/mutex.rs21
-rw-r--r--library/std/src/sys_common/alloc.rs1
-rw-r--r--library/std/src/sys_common/at_exit_imp.rs7
-rw-r--r--library/std/src/sys_common/condvar.rs10
-rw-r--r--library/std/src/sys_common/mod.rs1
-rw-r--r--library/std/src/sys_common/mutex.rs127
-rw-r--r--library/std/src/sys_common/thread_local_key.rs4
-rw-r--r--library/std/src/sys_common/thread_parker/futex.rs93
-rw-r--r--library/std/src/sys_common/thread_parker/generic.rs119
-rw-r--r--library/std/src/sys_common/thread_parker/mod.rs9
-rw-r--r--library/std/src/thread/mod.rs133
-rw-r--r--library/std/src/time.rs4
40 files changed, 798 insertions, 413 deletions
diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs
index ba158511f64..dd760062380 100644
--- a/library/std/src/alloc.rs
+++ b/library/std/src/alloc.rs
@@ -133,7 +133,7 @@ pub struct System;
 
 impl System {
     #[inline]
-    fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocErr> {
+    fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
         match layout.size() {
             0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
             // SAFETY: `layout` is non-zero in size,
@@ -143,7 +143,7 @@ impl System {
                 } else {
                     GlobalAlloc::alloc(self, layout)
                 };
-                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
+                let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
                 Ok(NonNull::slice_from_raw_parts(ptr, size))
             },
         }
@@ -157,7 +157,7 @@ impl System {
         old_layout: Layout,
         new_layout: Layout,
         zeroed: bool,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         debug_assert!(
             new_layout.size() >= old_layout.size(),
             "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
@@ -175,7 +175,7 @@ impl System {
                 intrinsics::assume(new_size >= old_layout.size());
 
                 let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size);
-                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
+                let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
                 if zeroed {
                     raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
                 }
@@ -202,12 +202,12 @@ impl System {
 #[unstable(feature = "allocator_api", issue = "32838")]
 unsafe impl AllocRef for System {
     #[inline]
-    fn alloc(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+    fn alloc(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
         self.alloc_impl(layout, false)
     }
 
     #[inline]
-    fn alloc_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+    fn alloc_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
         self.alloc_impl(layout, true)
     }
 
@@ -226,7 +226,7 @@ unsafe impl AllocRef for System {
         ptr: NonNull<u8>,
         old_layout: Layout,
         new_layout: Layout,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         // SAFETY: all conditions must be upheld by the caller
         unsafe { self.grow_impl(ptr, old_layout, new_layout, false) }
     }
@@ -237,7 +237,7 @@ unsafe impl AllocRef for System {
         ptr: NonNull<u8>,
         old_layout: Layout,
         new_layout: Layout,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         // SAFETY: all conditions must be upheld by the caller
         unsafe { self.grow_impl(ptr, old_layout, new_layout, true) }
     }
@@ -248,7 +248,7 @@ unsafe impl AllocRef for System {
         ptr: NonNull<u8>,
         old_layout: Layout,
         new_layout: Layout,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         debug_assert!(
             new_layout.size() <= old_layout.size(),
             "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
@@ -267,7 +267,7 @@ unsafe impl AllocRef for System {
                 intrinsics::assume(new_size <= old_layout.size());
 
                 let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size);
-                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
+                let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
                 Ok(NonNull::slice_from_raw_parts(ptr, new_size))
             },
 
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index 61d71d55d65..4424a4c1992 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -1102,6 +1102,16 @@ where
 /// documentation for more.
 ///
 /// [`iter`]: HashMap::iter
+///
+/// # Example
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// let mut map = HashMap::new();
+/// map.insert("a", 1);
+/// let iter = map.iter();
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, K: 'a, V: 'a> {
     base: base::Iter<'a, K, V>,
@@ -1129,6 +1139,16 @@ impl<K: Debug, V: Debug> fmt::Debug for Iter<'_, K, V> {
 /// documentation for more.
 ///
 /// [`iter_mut`]: HashMap::iter_mut
+///
+/// # Example
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// let mut map = HashMap::new();
+/// map.insert("a", 1);
+/// let iter = map.iter_mut();
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IterMut<'a, K: 'a, V: 'a> {
     base: base::IterMut<'a, K, V>,
@@ -1148,6 +1168,16 @@ impl<'a, K, V> IterMut<'a, K, V> {
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
 /// [`into_iter`]: IntoIterator::into_iter
+///
+/// # Example
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// let mut map = HashMap::new();
+/// map.insert("a", 1);
+/// let iter = map.into_iter();
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IntoIter<K, V> {
     base: base::IntoIter<K, V>,
@@ -1167,6 +1197,16 @@ impl<K, V> IntoIter<K, V> {
 /// documentation for more.
 ///
 /// [`keys`]: HashMap::keys
+///
+/// # Example
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// let mut map = HashMap::new();
+/// map.insert("a", 1);
+/// let iter_keys = map.keys();
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Keys<'a, K: 'a, V: 'a> {
     inner: Iter<'a, K, V>,
@@ -1194,6 +1234,16 @@ impl<K: Debug, V> fmt::Debug for Keys<'_, K, V> {
 /// documentation for more.
 ///
 /// [`values`]: HashMap::values
+///
+/// # Example
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// let mut map = HashMap::new();
+/// map.insert("a", 1);
+/// let iter_values = map.values();
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Values<'a, K: 'a, V: 'a> {
     inner: Iter<'a, K, V>,
@@ -1221,6 +1271,16 @@ impl<K, V: Debug> fmt::Debug for Values<'_, K, V> {
 /// documentation for more.
 ///
 /// [`drain`]: HashMap::drain
+///
+/// # Example
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// let mut map = HashMap::new();
+/// map.insert("a", 1);
+/// let iter = map.drain();
+/// ```
 #[stable(feature = "drain", since = "1.6.0")]
 pub struct Drain<'a, K: 'a, V: 'a> {
     base: base::Drain<'a, K, V>,
@@ -1239,6 +1299,18 @@ impl<'a, K, V> Drain<'a, K, V> {
 /// This `struct` is created by the [`drain_filter`] method on [`HashMap`].
 ///
 /// [`drain_filter`]: HashMap::drain_filter
+///
+/// # Example
+///
+/// ```
+/// #![feature(hash_drain_filter)]
+///
+/// use std::collections::HashMap;
+///
+/// let mut map = HashMap::new();
+/// map.insert("a", 1);
+/// let iter = map.drain_filter(|_k, v| *v % 2 == 0);
+/// ```
 #[unstable(feature = "hash_drain_filter", issue = "59618")]
 pub struct DrainFilter<'a, K, V, F>
 where
@@ -1253,6 +1325,16 @@ where
 /// documentation for more.
 ///
 /// [`values_mut`]: HashMap::values_mut
+///
+/// # Example
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// let mut map = HashMap::new();
+/// map.insert("a", 1);
+/// let iter_values = map.values_mut();
+/// ```
 #[stable(feature = "map_values_mut", since = "1.10.0")]
 pub struct ValuesMut<'a, K: 'a, V: 'a> {
     inner: IterMut<'a, K, V>,
@@ -1264,6 +1346,18 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> {
 /// See its documentation for more.
 ///
 /// [`into_keys`]: HashMap::into_keys
+///
+/// # Example
+///
+/// ```
+/// #![feature(map_into_keys_values)]
+///
+/// use std::collections::HashMap;
+///
+/// let mut map = HashMap::new();
+/// map.insert("a", 1);
+/// let iter_keys = map.into_keys();
+/// ```
 #[unstable(feature = "map_into_keys_values", issue = "75294")]
 pub struct IntoKeys<K, V> {
     inner: IntoIter<K, V>,
@@ -1275,6 +1369,18 @@ pub struct IntoKeys<K, V> {
 /// See its documentation for more.
 ///
 /// [`into_values`]: HashMap::into_values
+///
+/// # Example
+///
+/// ```
+/// #![feature(map_into_keys_values)]
+///
+/// use std::collections::HashMap;
+///
+/// let mut map = HashMap::new();
+/// map.insert("a", 1);
+/// let iter_keys = map.into_values();
+/// ```
 #[unstable(feature = "map_into_keys_values", issue = "75294")]
 pub struct IntoValues<K, V> {
     inner: IntoIter<K, V>,
@@ -1285,7 +1391,6 @@ pub struct IntoValues<K, V> {
 /// See the [`HashMap::raw_entry_mut`] docs for usage examples.
 ///
 /// [`HashMap::raw_entry_mut`]: HashMap::raw_entry_mut
-
 #[unstable(feature = "hash_raw_entry", issue = "56167")]
 pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> {
     map: &'a mut HashMap<K, V, S>,
@@ -2731,11 +2836,10 @@ impl DefaultHasher {
 
 #[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
 impl Default for DefaultHasher {
-    // FIXME: here should link `new` to [DefaultHasher::new], but it occurs intra-doc link
-    // resolution failure when re-exporting libstd items. When #56922 fixed,
-    // link `new` to [DefaultHasher::new] again.
-    /// Creates a new `DefaultHasher` using `new`.
+    /// Creates a new `DefaultHasher` using [`new`].
     /// See its documentation for more.
+    ///
+    /// [`new`]: DefaultHasher::new
     fn default() -> DefaultHasher {
         DefaultHasher::new()
     }
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index ee25311d3b7..5771ca758af 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -19,7 +19,7 @@ mod tests;
 use core::array;
 use core::convert::Infallible;
 
-use crate::alloc::{AllocErr, LayoutErr};
+use crate::alloc::{AllocError, LayoutErr};
 use crate::any::TypeId;
 use crate::backtrace::Backtrace;
 use crate::borrow::Cow;
@@ -387,7 +387,7 @@ impl Error for ! {}
     reason = "the precise API and guarantees it provides may be tweaked.",
     issue = "32838"
 )]
-impl Error for AllocErr {}
+impl Error for AllocError {}
 
 #[stable(feature = "alloc_layout", since = "1.28.0")]
 impl Error for LayoutErr {}
diff --git a/library/std/src/io/lazy.rs b/library/std/src/io/lazy.rs
deleted file mode 100644
index 1968d498bbe..00000000000
--- a/library/std/src/io/lazy.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-use crate::cell::Cell;
-use crate::ptr;
-use crate::sync::Arc;
-use crate::sys_common;
-use crate::sys_common::mutex::Mutex;
-
-pub struct Lazy<T> {
-    // We never call `lock.init()`, so it is UB to attempt to acquire this mutex reentrantly!
-    lock: Mutex,
-    ptr: Cell<*mut Arc<T>>,
-}
-
-#[inline]
-const fn done<T>() -> *mut Arc<T> {
-    1_usize as *mut _
-}
-
-unsafe impl<T> Sync for Lazy<T> {}
-
-impl<T> Lazy<T> {
-    pub const fn new() -> Lazy<T> {
-        Lazy { lock: Mutex::new(), ptr: Cell::new(ptr::null_mut()) }
-    }
-}
-
-impl<T: Send + Sync + 'static> Lazy<T> {
-    /// Safety: `init` must not call `get` on the variable that is being
-    /// initialized.
-    pub unsafe fn get(&'static self, init: fn() -> Arc<T>) -> Option<Arc<T>> {
-        let _guard = self.lock.lock();
-        let ptr = self.ptr.get();
-        if ptr.is_null() {
-            Some(self.init(init))
-        } else if ptr == done() {
-            None
-        } else {
-            Some((*ptr).clone())
-        }
-    }
-
-    // Must only be called with `lock` held
-    unsafe fn init(&'static self, init: fn() -> Arc<T>) -> Arc<T> {
-        // If we successfully register an at exit handler, then we cache the
-        // `Arc` allocation in our own internal box (it will get deallocated by
-        // the at exit handler). Otherwise we just return the freshly allocated
-        // `Arc`.
-        let registered = sys_common::at_exit(move || {
-            let ptr = {
-                let _guard = self.lock.lock();
-                self.ptr.replace(done())
-            };
-            drop(Box::from_raw(ptr))
-        });
-        // This could reentrantly call `init` again, which is a problem
-        // because our `lock` allows reentrancy!
-        // That's why `get` is unsafe and requires the caller to ensure no reentrancy happens.
-        let ret = init();
-        if registered.is_ok() {
-            self.ptr.set(Box::into_raw(Box::new(ret.clone())));
-        }
-        ret
-    }
-}
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index adea8a804e3..d9d03807819 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -285,7 +285,6 @@ mod buffered;
 mod cursor;
 mod error;
 mod impls;
-mod lazy;
 pub mod prelude;
 mod stdio;
 mod util;
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 71ed2d84cad..61ccc6f13c8 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -7,10 +7,11 @@ use crate::io::prelude::*;
 
 use crate::cell::RefCell;
 use crate::fmt;
-use crate::io::lazy::Lazy;
 use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter};
-use crate::sync::{Arc, Mutex, MutexGuard, Once};
+use crate::lazy::SyncOnceCell;
+use crate::sync::{Mutex, MutexGuard};
 use crate::sys::stdio;
+use crate::sys_common;
 use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
 use crate::thread::LocalKey;
 
@@ -217,7 +218,7 @@ fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Stdin {
-    inner: Arc<Mutex<BufReader<StdinRaw>>>,
+    inner: &'static Mutex<BufReader<StdinRaw>>,
 }
 
 /// A locked reference to the `Stdin` handle.
@@ -292,15 +293,11 @@ pub struct StdinLock<'a> {
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn stdin() -> Stdin {
-    static INSTANCE: Lazy<Mutex<BufReader<StdinRaw>>> = Lazy::new();
-    return Stdin {
-        inner: unsafe { INSTANCE.get(stdin_init).expect("cannot access stdin during shutdown") },
-    };
-
-    fn stdin_init() -> Arc<Mutex<BufReader<StdinRaw>>> {
-        // This must not reentrantly access `INSTANCE`
-        let stdin = stdin_raw();
-        Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin)))
+    static INSTANCE: SyncOnceCell<Mutex<BufReader<StdinRaw>>> = SyncOnceCell::new();
+    Stdin {
+        inner: INSTANCE.get_or_init(|| {
+            Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin_raw()))
+        }),
     }
 }
 
@@ -476,7 +473,7 @@ pub struct Stdout {
     // FIXME: this should be LineWriter or BufWriter depending on the state of
     //        stdout (tty or not). Note that if this is not line buffered it
     //        should also flush-on-panic or some form of flush-on-abort.
-    inner: Arc<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>>,
+    inner: &'static ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>,
 }
 
 /// A locked reference to the `Stdout` handle.
@@ -534,19 +531,27 @@ pub struct StdoutLock<'a> {
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn stdout() -> Stdout {
-    static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = Lazy::new();
-    return Stdout {
-        inner: unsafe { INSTANCE.get(stdout_init).expect("cannot access stdout during shutdown") },
-    };
-
-    fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> {
-        // This must not reentrantly access `INSTANCE`
-        let stdout = stdout_raw();
-        unsafe {
-            let ret = Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout))));
-            ret.init();
-            ret
-        }
+    static INSTANCE: SyncOnceCell<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> =
+        SyncOnceCell::new();
+    Stdout {
+        inner: INSTANCE.get_or_init(|| unsafe {
+            let _ = sys_common::at_exit(|| {
+                if let Some(instance) = INSTANCE.get() {
+                    // Flush the data and disable buffering during shutdown
+                    // by replacing the line writer by one with zero
+                    // buffering capacity.
+                    // We use try_lock() instead of lock(), because someone
+                    // might have leaked a StdoutLock, which would
+                    // otherwise cause a deadlock here.
+                    if let Some(lock) = instance.try_lock() {
+                        *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw());
+                    }
+                }
+            });
+            let r = ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw())));
+            r.init();
+            r
+        }),
     }
 }
 
@@ -741,16 +746,15 @@ pub fn stderr() -> Stderr {
     //
     // This has the added benefit of allowing `stderr` to be usable during
     // process shutdown as well!
-    static INSTANCE: ReentrantMutex<RefCell<StderrRaw>> =
-        unsafe { ReentrantMutex::new(RefCell::new(stderr_raw())) };
-
-    // When accessing stderr we need one-time initialization of the reentrant
-    // mutex. Afterwards we can just always use the now-filled-in `INSTANCE` value.
-    static INIT: Once = Once::new();
-    INIT.call_once(|| unsafe {
-        INSTANCE.init();
-    });
-    Stderr { inner: &INSTANCE }
+    static INSTANCE: SyncOnceCell<ReentrantMutex<RefCell<StderrRaw>>> = SyncOnceCell::new();
+
+    Stderr {
+        inner: INSTANCE.get_or_init(|| unsafe {
+            let r = ReentrantMutex::new(RefCell::new(stderr_raw()));
+            r.init();
+            r
+        }),
+    }
 }
 
 impl Stderr {
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index d03428dd082..e343eef9112 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -239,6 +239,7 @@
 #![cfg_attr(not(bootstrap), feature(const_fn_floating_point_arithmetic))]
 #![feature(const_fn_transmute)]
 #![feature(const_fn)]
+#![cfg_attr(not(bootstrap), feature(const_fn_fn_ptr_basics))]
 #![feature(const_ip)]
 #![feature(const_ipv6)]
 #![feature(const_raw_ptr_deref)]
diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs
index 4ff3a6e5789..617c4098aa9 100644
--- a/library/std/src/os/linux/raw.rs
+++ b/library/std/src/os/linux/raw.rs
@@ -29,6 +29,7 @@ pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
     target_arch = "x86",
     target_arch = "le32",
     target_arch = "powerpc",
+    target_arch = "sparc",
     target_arch = "arm",
     target_arch = "asmjs",
     target_arch = "wasm32"
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index 18d9c2f11b5..4281867314c 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -411,3 +411,6 @@ pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
 pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! {
     panicking::rust_panic_without_hook(payload)
 }
+
+#[cfg(test)]
+mod tests;
diff --git a/library/std/src/panic/tests.rs b/library/std/src/panic/tests.rs
new file mode 100644
index 00000000000..b37d74011cc
--- /dev/null
+++ b/library/std/src/panic/tests.rs
@@ -0,0 +1,56 @@
+#![allow(dead_code)]
+
+use crate::cell::RefCell;
+use crate::panic::{AssertUnwindSafe, UnwindSafe};
+use crate::rc::Rc;
+use crate::sync::{Arc, Mutex, RwLock};
+
+struct Foo {
+    a: i32,
+}
+
+fn assert<T: UnwindSafe + ?Sized>() {}
+
+#[test]
+fn panic_safety_traits() {
+    assert::<i32>();
+    assert::<&i32>();
+    assert::<*mut i32>();
+    assert::<*const i32>();
+    assert::<usize>();
+    assert::<str>();
+    assert::<&str>();
+    assert::<Foo>();
+    assert::<&Foo>();
+    assert::<Vec<i32>>();
+    assert::<String>();
+    assert::<RefCell<i32>>();
+    assert::<Box<i32>>();
+    assert::<Mutex<i32>>();
+    assert::<RwLock<i32>>();
+    assert::<&Mutex<i32>>();
+    assert::<&RwLock<i32>>();
+    assert::<Rc<i32>>();
+    assert::<Arc<i32>>();
+    assert::<Box<[u8]>>();
+
+    {
+        trait Trait: UnwindSafe {}
+        assert::<Box<dyn Trait>>();
+    }
+
+    fn bar<T>() {
+        assert::<Mutex<T>>();
+        assert::<RwLock<T>>();
+    }
+
+    fn baz<T: UnwindSafe>() {
+        assert::<Box<T>>();
+        assert::<Vec<T>>();
+        assert::<RefCell<T>>();
+        assert::<AssertUnwindSafe<T>>();
+        assert::<&AssertUnwindSafe<T>>();
+        assert::<Rc<AssertUnwindSafe<T>>>();
+        assert::<Arc<AssertUnwindSafe<T>>>();
+    }
+}
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index b83c1e9628d..6fa73042a30 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1838,7 +1838,7 @@ impl Path {
             // FIXME: Allow Redox prefixes
             self.has_root() || has_redox_scheme(self.as_u8_slice())
         } else {
-            self.has_root() && (cfg!(unix) || self.prefix().is_some())
+            self.has_root() && (cfg!(any(unix, target_os = "wasi")) || self.prefix().is_some())
         }
     }
 
diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs
index 7e2155dae6f..1376d8ebe8f 100644
--- a/library/std/src/sync/condvar.rs
+++ b/library/std/src/sync/condvar.rs
@@ -553,8 +553,8 @@ impl Condvar {
         unsafe { self.inner.notify_all() }
     }
 
-    fn verify(&self, mutex: &sys_mutex::Mutex) {
-        let addr = mutex as *const _ as usize;
+    fn verify(&self, mutex: &sys_mutex::MovableMutex) {
+        let addr = mutex.raw() as *const _ as usize;
         match self.mutex.compare_and_swap(0, addr, Ordering::SeqCst) {
             // If we got out 0, then we have successfully bound the mutex to
             // this cvar.
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index a1703c731d4..e8f5a6f4294 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -166,12 +166,7 @@ use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult};
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "mutex_type")]
 pub struct Mutex<T: ?Sized> {
-    // Note that this mutex is in a *box*, not inlined into the struct itself.
-    // Once a native mutex has been used once, its address can never change (it
-    // can't be moved). This mutex type can be safely moved at any time, so to
-    // ensure that the native mutex is used correctly we box the inner mutex to
-    // give it a constant address.
-    inner: Box<sys::Mutex>,
+    inner: sys::MovableMutex,
     poison: poison::Flag,
     data: UnsafeCell<T>,
 }
@@ -218,15 +213,11 @@ impl<T> Mutex<T> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new(t: T) -> Mutex<T> {
-        let mut m = Mutex {
-            inner: box sys::Mutex::new(),
+        Mutex {
+            inner: sys::MovableMutex::new(),
             poison: poison::Flag::new(),
             data: UnsafeCell::new(t),
-        };
-        unsafe {
-            m.inner.init();
         }
-        m
     }
 }
 
@@ -378,7 +369,6 @@ impl<T: ?Sized> Mutex<T> {
                 (ptr::read(inner), ptr::read(poison), ptr::read(data))
             };
             mem::forget(self);
-            inner.destroy(); // Keep in sync with the `Drop` impl.
             drop(inner);
 
             poison::map_result(poison.borrow(), |_| data.into_inner())
@@ -411,18 +401,6 @@ impl<T: ?Sized> Mutex<T> {
     }
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<#[may_dangle] T: ?Sized> Drop for Mutex<T> {
-    fn drop(&mut self) {
-        // This is actually safe b/c we know that there is no further usage of
-        // this mutex (it's up to the user to arrange for a mutex to get
-        // dropped, that's not our job)
-        //
-        // IMPORTANT: This code must be kept in sync with `Mutex::into_inner`.
-        unsafe { self.inner.destroy() }
-    }
-}
-
 #[stable(feature = "mutex_from", since = "1.24.0")]
 impl<T> From<T> for Mutex<T> {
     /// Creates a new mutex in an unlocked state ready for use.
@@ -509,7 +487,7 @@ impl<T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'_, T> {
     }
 }
 
-pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
+pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::MovableMutex {
     &guard.lock.inner
 }
 
diff --git a/library/std/src/sys/hermit/args.rs b/library/std/src/sys/hermit/args.rs
index 72c1b8511ca..77272939272 100644
--- a/library/std/src/sys/hermit/args.rs
+++ b/library/std/src/sys/hermit/args.rs
@@ -57,11 +57,11 @@ mod imp {
     use crate::ptr;
     use crate::sys_common::os_str_bytes::*;
 
-    use crate::sys_common::mutex::Mutex;
+    use crate::sys_common::mutex::StaticMutex;
 
     static mut ARGC: isize = 0;
     static mut ARGV: *const *const u8 = ptr::null();
-    static LOCK: Mutex = Mutex::new();
+    static LOCK: StaticMutex = StaticMutex::new();
 
     pub unsafe fn init(argc: isize, argv: *const *const u8) {
         let _guard = LOCK.lock();
diff --git a/library/std/src/sys/sgx/abi/mem.rs b/library/std/src/sys/sgx/abi/mem.rs
index 57fd7efdd49..ffa234fccfe 100644
--- a/library/std/src/sys/sgx/abi/mem.rs
+++ b/library/std/src/sys/sgx/abi/mem.rs
@@ -21,8 +21,15 @@ extern "C" {
 #[inline(always)]
 #[unstable(feature = "sgx_platform", issue = "56975")]
 pub fn image_base() -> u64 {
-    let base;
-    unsafe { llvm_asm!("lea IMAGE_BASE(%rip),$0":"=r"(base)) };
+    let base: u64;
+    unsafe {
+        asm!(
+            "lea IMAGE_BASE(%rip), {}",
+            lateout(reg) base,
+            // NOTE(#76738): ATT syntax is used to support LLVM 8 and 9.
+            options(att_syntax, nostack, preserves_flags, nomem, pure),
+        )
+    };
     base
 }
 
diff --git a/library/std/src/sys/sgx/ext/arch.rs b/library/std/src/sys/sgx/ext/arch.rs
index 0c97a87e2e4..7488e7e5dc9 100644
--- a/library/std/src/sys/sgx/ext/arch.rs
+++ b/library/std/src/sys/sgx/ext/arch.rs
@@ -31,13 +31,13 @@ pub fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32>
         let mut out = MaybeUninit::uninit();
         let error;
 
-        llvm_asm!(
-            "enclu"
-            : "={eax}"(error)
-            : "{eax}"(ENCLU_EGETKEY),
-              "{rbx}"(request),
-              "{rcx}"(out.as_mut_ptr())
-            : "flags"
+        asm!(
+            "enclu",
+            inlateout("eax") ENCLU_EGETKEY => error,
+            in("rbx") request,
+            in("rcx") out.as_mut_ptr(),
+            // NOTE(#76738): ATT syntax is used to support LLVM 8 and 9.
+            options(att_syntax, nostack),
         );
 
         match error {
@@ -60,13 +60,14 @@ pub fn ereport(
     unsafe {
         let mut report = MaybeUninit::uninit();
 
-        llvm_asm!(
-            "enclu"
-            : /* no output registers */
-            : "{eax}"(ENCLU_EREPORT),
-              "{rbx}"(targetinfo),
-              "{rcx}"(reportdata),
-              "{rdx}"(report.as_mut_ptr())
+        asm!(
+            "enclu",
+            in("eax") ENCLU_EREPORT,
+            in("rbx") targetinfo,
+            in("rcx") reportdata,
+            in("rdx") report.as_mut_ptr(),
+            // NOTE(#76738): ATT syntax is used to support LLVM 8 and 9.
+            options(att_syntax, preserves_flags, nostack),
         );
 
         report.assume_init()
diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs
index 9bc44a59482..f7c3f163718 100644
--- a/library/std/src/sys/unix/args.rs
+++ b/library/std/src/sys/unix/args.rs
@@ -80,13 +80,13 @@ mod imp {
     use crate::ptr;
     use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering};
 
-    use crate::sys_common::mutex::Mutex;
+    use crate::sys_common::mutex::StaticMutex;
 
     static ARGC: AtomicIsize = AtomicIsize::new(0);
     static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());
     // We never call `ENV_LOCK.init()`, so it is UB to attempt to
     // acquire this mutex reentrantly!
-    static LOCK: Mutex = Mutex::new();
+    static LOCK: StaticMutex = StaticMutex::new();
 
     unsafe fn really_init(argc: isize, argv: *const *const u8) {
         let _guard = LOCK.lock();
diff --git a/library/std/src/sys/unix/ext/io.rs b/library/std/src/sys/unix/ext/io.rs
index ec7a32b675c..fbea1aa9f2a 100644
--- a/library/std/src/sys/unix/ext/io.rs
+++ b/library/std/src/sys/unix/ext/io.rs
@@ -62,6 +62,25 @@ pub trait IntoRawFd {
     fn into_raw_fd(self) -> RawFd;
 }
 
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl AsRawFd for RawFd {
+    fn as_raw_fd(&self) -> RawFd {
+        *self
+    }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl IntoRawFd for RawFd {
+    fn into_raw_fd(self) -> RawFd {
+        self
+    }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl FromRawFd for RawFd {
+    unsafe fn from_raw_fd(fd: RawFd) -> RawFd {
+        fd
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRawFd for fs::File {
     fn as_raw_fd(&self) -> RawFd {
diff --git a/library/std/src/sys/unix/futex.rs b/library/std/src/sys/unix/futex.rs
new file mode 100644
index 00000000000..e6f0c48c59b
--- /dev/null
+++ b/library/std/src/sys/unix/futex.rs
@@ -0,0 +1,37 @@
+#![cfg(any(target_os = "linux", target_os = "android"))]
+
+use crate::convert::TryInto;
+use crate::ptr::null;
+use crate::sync::atomic::AtomicI32;
+use crate::time::Duration;
+
+pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) {
+    let timespec = timeout.and_then(|d| {
+        Some(libc::timespec {
+            // Sleep forever if the timeout is longer than fits in a timespec.
+            tv_sec: d.as_secs().try_into().ok()?,
+            // This conversion never truncates, as subsec_nanos is always <1e9.
+            tv_nsec: d.subsec_nanos() as _,
+        })
+    });
+    unsafe {
+        libc::syscall(
+            libc::SYS_futex,
+            futex as *const AtomicI32,
+            libc::FUTEX_WAIT | libc::FUTEX_PRIVATE_FLAG,
+            expected,
+            timespec.as_ref().map_or(null(), |d| d as *const libc::timespec),
+        );
+    }
+}
+
+pub fn futex_wake(futex: &AtomicI32) {
+    unsafe {
+        libc::syscall(
+            libc::SYS_futex,
+            futex as *const AtomicI32,
+            libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG,
+            1,
+        );
+    }
+}
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index eddf00d3979..776f4f18ecf 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -49,6 +49,7 @@ pub mod env;
 pub mod ext;
 pub mod fd;
 pub mod fs;
+pub mod futex;
 pub mod io;
 #[cfg(target_os = "l4re")]
 mod l4re;
@@ -75,6 +76,13 @@ pub use crate::sys_common::os_str_bytes as os_str;
 
 #[cfg(not(test))]
 pub fn init() {
+    // The standard streams might be closed on application startup. To prevent
+    // std::io::{stdin, stdout,stderr} objects from using other unrelated file
+    // resources opened later, we reopen standards streams when they are closed.
+    unsafe {
+        sanitize_standard_fds();
+    }
+
     // By default, some platforms will send a *signal* when an EPIPE error
     // would otherwise be delivered. This runtime doesn't install a SIGPIPE
     // handler, causing it to kill the program, which isn't exactly what we
@@ -86,6 +94,62 @@ pub fn init() {
         reset_sigpipe();
     }
 
+    cfg_if::cfg_if! {
+        if #[cfg(miri)] {
+            // The standard fds are always available in Miri.
+            unsafe fn sanitize_standard_fds() {}
+        } else if #[cfg(not(any(
+            target_os = "emscripten",
+            target_os = "fuchsia",
+            // The poll on Darwin doesn't set POLLNVAL for closed fds.
+            target_os = "macos",
+            target_os = "ios",
+            target_os = "redox",
+        )))] {
+            // In the case when all file descriptors are open, the poll has been
+            // observed to perform better than fcntl (on GNU/Linux).
+            unsafe fn sanitize_standard_fds() {
+                use crate::sys::os::errno;
+                let pfds: &mut [_] = &mut [
+                    libc::pollfd { fd: 0, events: 0, revents: 0 },
+                    libc::pollfd { fd: 1, events: 0, revents: 0 },
+                    libc::pollfd { fd: 2, events: 0, revents: 0 },
+                ];
+                while libc::poll(pfds.as_mut_ptr(), 3, 0) == -1 {
+                    if errno() == libc::EINTR {
+                        continue;
+                    }
+                    libc::abort();
+                }
+                for pfd in pfds {
+                    if pfd.revents & libc::POLLNVAL == 0 {
+                        continue;
+                    }
+                    if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
+                        // If the stream is closed but we failed to reopen it, abort the
+                        // process. Otherwise we wouldn't preserve the safety of
+                        // operations on the corresponding Rust object Stdin, Stdout, or
+                        // Stderr.
+                        libc::abort();
+                    }
+                }
+            }
+        } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "redox"))] {
+            unsafe fn sanitize_standard_fds() {
+                use crate::sys::os::errno;
+                for fd in 0..3 {
+                    if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF {
+                        if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
+                            libc::abort();
+                        }
+                    }
+                }
+            }
+        } else {
+            unsafe fn sanitize_standard_fds() {}
+        }
+    }
+
     #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))]
     unsafe fn reset_sigpipe() {
         assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 4aa61fc5bf6..c9f9ed01e12 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -21,7 +21,7 @@ use crate::slice;
 use crate::str;
 use crate::sys::cvt;
 use crate::sys::fd;
-use crate::sys_common::mutex::{Mutex, MutexGuard};
+use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard};
 use crate::vec;
 
 use libc::{c_char, c_int, c_void};
@@ -470,10 +470,9 @@ pub unsafe fn environ() -> *mut *const *const c_char {
     &mut environ
 }
 
-pub unsafe fn env_lock() -> MutexGuard<'static> {
-    // We never call `ENV_LOCK.init()`, so it is UB to attempt to
-    // acquire this mutex reentrantly!
-    static ENV_LOCK: Mutex = Mutex::new();
+pub unsafe fn env_lock() -> StaticMutexGuard<'static> {
+    // It is UB to attempt to acquire this mutex reentrantly!
+    static ENV_LOCK: StaticMutex = StaticMutex::new();
     ENV_LOCK.lock()
 }
 
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 50f5e78cf2a..ea7ea6f067c 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -67,7 +67,7 @@ impl Command {
                     // pipe I/O up to PIPE_BUF bytes should be atomic, and then
                     // we want to be sure we *don't* run at_exit destructors as
                     // we're being torn down regardless
-                    assert!(output.write(&bytes).is_ok());
+                    rtassert!(output.write(&bytes).is_ok());
                     libc::_exit(1)
                 }
                 n => n,
diff --git a/library/std/src/sys/vxworks/args.rs b/library/std/src/sys/vxworks/args.rs
index adff6c489bb..30cf7a707c7 100644
--- a/library/std/src/sys/vxworks/args.rs
+++ b/library/std/src/sys/vxworks/args.rs
@@ -57,11 +57,11 @@ mod imp {
     use crate::marker::PhantomData;
     use crate::ptr;
 
-    use crate::sys_common::mutex::Mutex;
+    use crate::sys_common::mutex::StaticMutex;
 
     static mut ARGC: isize = 0;
     static mut ARGV: *const *const u8 = ptr::null();
-    static LOCK: Mutex = Mutex::new();
+    static LOCK: StaticMutex = StaticMutex::new();
 
     pub unsafe fn init(argc: isize, argv: *const *const u8) {
         let _guard = LOCK.lock();
diff --git a/library/std/src/sys/vxworks/ext/io.rs b/library/std/src/sys/vxworks/ext/io.rs
index 25c6e26d96e..8b5a2d12af7 100644
--- a/library/std/src/sys/vxworks/ext/io.rs
+++ b/library/std/src/sys/vxworks/ext/io.rs
@@ -63,6 +63,25 @@ pub trait IntoRawFd {
     fn into_raw_fd(self) -> RawFd;
 }
 
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl AsRawFd for RawFd {
+    fn as_raw_fd(&self) -> RawFd {
+        *self
+    }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl IntoRawFd for RawFd {
+    fn into_raw_fd(self) -> RawFd {
+        self
+    }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl FromRawFd for RawFd {
+    unsafe fn from_raw_fd(fd: RawFd) -> RawFd {
+        fd
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRawFd for fs::File {
     fn as_raw_fd(&self) -> RawFd {
diff --git a/library/std/src/sys/vxworks/os.rs b/library/std/src/sys/vxworks/os.rs
index 1fadf716135..08394a8d29d 100644
--- a/library/std/src/sys/vxworks/os.rs
+++ b/library/std/src/sys/vxworks/os.rs
@@ -10,7 +10,7 @@ use crate::path::{self, Path, PathBuf};
 use crate::slice;
 use crate::str;
 use crate::sys::cvt;
-use crate::sys_common::mutex::{Mutex, MutexGuard};
+use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard};
 use libc::{self, c_char /*,c_void */, c_int};
 /*use sys::fd; this one is probably important */
 use crate::vec;
@@ -212,10 +212,9 @@ pub unsafe fn environ() -> *mut *const *const c_char {
     &mut environ
 }
 
-pub unsafe fn env_lock() -> MutexGuard<'static> {
-    // We never call `ENV_LOCK.init()`, so it is UB to attempt to
-    // acquire this mutex reentrantly!
-    static ENV_LOCK: Mutex = Mutex::new();
+pub unsafe fn env_lock() -> StaticMutexGuard<'static> {
+    // It is UB to attempt to acquire this mutex reentrantly!
+    static ENV_LOCK: StaticMutex = StaticMutex::new();
     ENV_LOCK.lock()
 }
 
diff --git a/library/std/src/sys/wasi/ext/io.rs b/library/std/src/sys/wasi/ext/io.rs
index 4e8fa65eb20..661214e8f4c 100644
--- a/library/std/src/sys/wasi/ext/io.rs
+++ b/library/std/src/sys/wasi/ext/io.rs
@@ -52,6 +52,25 @@ pub trait IntoRawFd {
     fn into_raw_fd(self) -> RawFd;
 }
 
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl AsRawFd for RawFd {
+    fn as_raw_fd(&self) -> RawFd {
+        *self
+    }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl IntoRawFd for RawFd {
+    fn into_raw_fd(self) -> RawFd {
+        self
+    }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl FromRawFd for RawFd {
+    unsafe fn from_raw_fd(fd: RawFd) -> RawFd {
+        fd
+    }
+}
+
 impl AsRawFd for net::TcpStream {
     fn as_raw_fd(&self) -> RawFd {
         self.as_inner().fd().as_raw()
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index f440442ca30..559c4dc9c7c 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -1032,7 +1032,7 @@ extern "system" {
 // Functions that aren't available on every version of Windows that we support,
 // but we still use them and just provide some form of a fallback implementation.
 compat_fn! {
-    kernel32:
+    "kernel32":
 
     pub fn CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR,
                                _lpTargetFileName: LPCWSTR,
diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs
index d6d433f9d08..3f25f05e1b9 100644
--- a/library/std/src/sys/windows/compat.rs
+++ b/library/std/src/sys/windows/compat.rs
@@ -12,7 +12,6 @@
 //! function is available but afterwards it's just a load and a jump.
 
 use crate::ffi::CString;
-use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sys::c;
 
 pub fn lookup(module: &str, symbol: &str) -> Option<usize> {
@@ -28,45 +27,69 @@ pub fn lookup(module: &str, symbol: &str) -> Option<usize> {
     }
 }
 
-pub fn store_func(ptr: &AtomicUsize, module: &str, symbol: &str, fallback: usize) -> usize {
-    let value = lookup(module, symbol).unwrap_or(fallback);
-    ptr.store(value, Ordering::SeqCst);
-    value
-}
-
 macro_rules! compat_fn {
-    ($module:ident: $(
+    ($module:literal: $(
         $(#[$meta:meta])*
-        pub fn $symbol:ident($($argname:ident: $argtype:ty),*)
-                                  -> $rettype:ty {
-            $($body:expr);*
-        }
+        pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $body:block
     )*) => ($(
-        #[allow(unused_variables)]
         $(#[$meta])*
-        pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype {
+        pub mod $symbol {
+            use super::*;
             use crate::sync::atomic::{AtomicUsize, Ordering};
             use crate::mem;
+
             type F = unsafe extern "system" fn($($argtype),*) -> $rettype;
 
             static PTR: AtomicUsize = AtomicUsize::new(0);
 
+            #[allow(unused_variables)]
+            unsafe extern "system" fn fallback($($argname: $argtype),*) -> $rettype $body
+
+            /// This address is stored in `PTR` to incidate an unavailable API.
+            ///
+            /// This way, call() will end up calling fallback() if it is unavailable.
+            ///
+            /// This is a `static` to avoid rustc duplicating `fn fallback()`
+            /// into both load() and is_available(), which would break
+            /// is_available()'s comparison. By using the same static variable
+            /// in both places, they'll refer to the same (copy of the)
+            /// function.
+            ///
+            /// LLVM merging the address of fallback with other functions
+            /// (because of unnamed_addr) is fine, since it's only compared to
+            /// an address from GetProcAddress from an external dll.
+            static FALLBACK: F = fallback;
+
+            #[cold]
             fn load() -> usize {
-                crate::sys::compat::store_func(&PTR,
-                                          stringify!($module),
-                                          stringify!($symbol),
-                                          fallback as usize)
+                // There is no locking here. It's okay if this is executed by multiple threads in
+                // parallel. `lookup` will result in the same value, and it's okay if they overwrite
+                // eachothers result as long as they do so atomically. We don't need any guarantees
+                // about memory ordering, as this involves just a single atomic variable which is
+                // not used to protect or order anything else.
+                let addr = crate::sys::compat::lookup($module, stringify!($symbol))
+                    .unwrap_or(FALLBACK as usize);
+                PTR.store(addr, Ordering::Relaxed);
+                addr
             }
-            unsafe extern "system" fn fallback($($argname: $argtype),*)
-                                               -> $rettype {
-                $($body);*
+
+            fn addr() -> usize {
+                match PTR.load(Ordering::Relaxed) {
+                    0 => load(),
+                    addr => addr,
+                }
+            }
+
+            #[allow(dead_code)]
+            pub fn is_available() -> bool {
+                addr() != FALLBACK as usize
             }
 
-            let addr = match PTR.load(Ordering::SeqCst) {
-                0 => load(),
-                n => n,
-            };
-            mem::transmute::<usize, F>(addr)($($argname),*)
+            pub unsafe fn call($($argname: $argtype),*) -> $rettype {
+                mem::transmute::<usize, F>(addr())($($argname),*)
+            }
         }
+
+        pub use $symbol::call as $symbol;
     )*)
 }
diff --git a/library/std/src/sys/windows/mutex.rs b/library/std/src/sys/windows/mutex.rs
index 1e09b95c872..e2aaca59fe2 100644
--- a/library/std/src/sys/windows/mutex.rs
+++ b/library/std/src/sys/windows/mutex.rs
@@ -23,7 +23,6 @@ use crate::cell::{Cell, UnsafeCell};
 use crate::mem::{self, MaybeUninit};
 use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sys::c;
-use crate::sys::compat;
 
 pub struct Mutex {
     // This is either directly an SRWLOCK (if supported), or a Box<Inner> otherwise.
@@ -40,8 +39,8 @@ struct Inner {
 
 #[derive(Clone, Copy)]
 enum Kind {
-    SRWLock = 1,
-    CriticalSection = 2,
+    SRWLock,
+    CriticalSection,
 }
 
 #[inline]
@@ -130,21 +129,7 @@ impl Mutex {
 }
 
 fn kind() -> Kind {
-    static KIND: AtomicUsize = AtomicUsize::new(0);
-
-    let val = KIND.load(Ordering::SeqCst);
-    if val == Kind::SRWLock as usize {
-        return Kind::SRWLock;
-    } else if val == Kind::CriticalSection as usize {
-        return Kind::CriticalSection;
-    }
-
-    let ret = match compat::lookup("kernel32", "AcquireSRWLockExclusive") {
-        None => Kind::CriticalSection,
-        Some(..) => Kind::SRWLock,
-    };
-    KIND.store(ret as usize, Ordering::SeqCst);
-    ret
+    if c::AcquireSRWLockExclusive::is_available() { Kind::SRWLock } else { Kind::CriticalSection }
 }
 
 pub struct ReentrantMutex {
diff --git a/library/std/src/sys_common/alloc.rs b/library/std/src/sys_common/alloc.rs
index f22476be325..6c1bc0d839a 100644
--- a/library/std/src/sys_common/alloc.rs
+++ b/library/std/src/sys_common/alloc.rs
@@ -12,6 +12,7 @@ use crate::ptr;
     target_arch = "mips",
     target_arch = "powerpc",
     target_arch = "powerpc64",
+    target_arch = "sparc",
     target_arch = "asmjs",
     target_arch = "wasm32",
     target_arch = "hexagon",
diff --git a/library/std/src/sys_common/at_exit_imp.rs b/library/std/src/sys_common/at_exit_imp.rs
index 6b799db856e..90d5d3a7898 100644
--- a/library/std/src/sys_common/at_exit_imp.rs
+++ b/library/std/src/sys_common/at_exit_imp.rs
@@ -4,7 +4,7 @@
 
 use crate::mem;
 use crate::ptr;
-use crate::sys_common::mutex::Mutex;
+use crate::sys_common::mutex::StaticMutex;
 
 type Queue = Vec<Box<dyn FnOnce()>>;
 
@@ -12,9 +12,8 @@ type Queue = Vec<Box<dyn FnOnce()>>;
 // on poisoning and this module needs to operate at a lower level than requiring
 // the thread infrastructure to be in place (useful on the borders of
 // initialization/destruction).
-// We never call `LOCK.init()`, so it is UB to attempt to
-// acquire this mutex reentrantly!
-static LOCK: Mutex = Mutex::new();
+// It is UB to attempt to acquire this mutex reentrantly!
+static LOCK: StaticMutex = StaticMutex::new();
 static mut QUEUE: *mut Queue = ptr::null_mut();
 
 const DONE: *mut Queue = 1_usize as *mut _;
diff --git a/library/std/src/sys_common/condvar.rs b/library/std/src/sys_common/condvar.rs
index f9611bc6f7b..a48d301f812 100644
--- a/library/std/src/sys_common/condvar.rs
+++ b/library/std/src/sys_common/condvar.rs
@@ -1,5 +1,5 @@
 use crate::sys::condvar as imp;
-use crate::sys_common::mutex::{self, Mutex};
+use crate::sys_common::mutex::MovableMutex;
 use crate::time::Duration;
 
 /// An OS-based condition variable.
@@ -46,8 +46,8 @@ impl Condvar {
     /// Behavior is also undefined if more than one mutex is used concurrently
     /// on this condition variable.
     #[inline]
-    pub unsafe fn wait(&self, mutex: &Mutex) {
-        self.0.wait(mutex::raw(mutex))
+    pub unsafe fn wait(&self, mutex: &MovableMutex) {
+        self.0.wait(mutex.raw())
     }
 
     /// Waits for a signal on the specified mutex with a timeout duration
@@ -57,8 +57,8 @@ impl Condvar {
     /// Behavior is also undefined if more than one mutex is used concurrently
     /// on this condition variable.
     #[inline]
-    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        self.0.wait_timeout(mutex::raw(mutex), dur)
+    pub unsafe fn wait_timeout(&self, mutex: &MovableMutex, dur: Duration) -> bool {
+        self.0.wait_timeout(mutex.raw(), dur)
     }
 
     /// Deallocates all resources associated with this condition variable.
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 28cdfefb12a..234b257aa92 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -66,6 +66,7 @@ pub mod thread;
 pub mod thread_info;
 pub mod thread_local_dtor;
 pub mod thread_local_key;
+pub mod thread_parker;
 pub mod util;
 pub mod wtf8;
 
diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs
index e66d8994147..93ec7d89bc5 100644
--- a/library/std/src/sys_common/mutex.rs
+++ b/library/std/src/sys_common/mutex.rs
@@ -1,101 +1,106 @@
 use crate::sys::mutex as imp;
 
-/// An OS-based mutual exclusion lock.
+/// An OS-based mutual exclusion lock, meant for use in static variables.
+///
+/// This mutex has a const constructor ([`StaticMutex::new`]), does not
+/// implement `Drop` to cleanup resources, and causes UB when moved or used
+/// reentrantly.
+///
+/// This mutex does not implement poisoning.
 ///
-/// This is the thinnest cross-platform wrapper around OS mutexes. All usage of
-/// this mutex is unsafe and it is recommended to instead use the safe wrapper
-/// at the top level of the crate instead of this type.
-pub struct Mutex(imp::Mutex);
+/// This is a wrapper around `imp::Mutex` that does *not* call `init()` and
+/// `destroy()`.
+pub struct StaticMutex(imp::Mutex);
 
-unsafe impl Sync for Mutex {}
+unsafe impl Sync for StaticMutex {}
 
-impl Mutex {
+impl StaticMutex {
     /// Creates a new mutex for use.
     ///
     /// Behavior is undefined if the mutex is moved after it is
     /// first used with any of the functions below.
-    /// Also, until `init` is called, behavior is undefined if this
-    /// mutex is ever used reentrantly, i.e., `raw_lock` or `try_lock`
-    /// are called by the thread currently holding the lock.
+    /// Also, the behavior is undefined if this mutex is ever used reentrantly,
+    /// i.e., `lock` is called by the thread currently holding the lock.
     #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")]
-    pub const fn new() -> Mutex {
-        Mutex(imp::Mutex::new())
+    pub const fn new() -> Self {
+        Self(imp::Mutex::new())
     }
 
-    /// Prepare the mutex for use.
+    /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex
+    /// will be unlocked.
     ///
-    /// This should be called once the mutex is at a stable memory address.
-    /// If called, this must be the very first thing that happens to the mutex.
-    /// Calling it in parallel with or after any operation (including another
-    /// `init()`) is undefined behavior.
+    /// It is undefined behaviour to call this function while locked, or if the
+    /// mutex has been moved since the last time this was called.
     #[inline]
-    pub unsafe fn init(&mut self) {
-        self.0.init()
+    pub unsafe fn lock(&self) -> StaticMutexGuard<'_> {
+        self.0.lock();
+        StaticMutexGuard(&self.0)
     }
+}
 
-    /// Locks the mutex blocking the current thread until it is available.
-    ///
-    /// Behavior is undefined if the mutex has been moved between this and any
-    /// previous function call.
+#[must_use]
+pub struct StaticMutexGuard<'a>(&'a imp::Mutex);
+
+impl Drop for StaticMutexGuard<'_> {
     #[inline]
-    pub unsafe fn raw_lock(&self) {
-        self.0.lock()
+    fn drop(&mut self) {
+        unsafe {
+            self.0.unlock();
+        }
     }
+}
 
-    /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex
-    /// will be unlocked.
+/// An OS-based mutual exclusion lock.
+///
+/// This mutex does *not* have a const constructor, cleans up its resources in
+/// its `Drop` implementation, may safely be moved (when not borrowed), and
+/// does not cause UB when used reentrantly.
+///
+/// This mutex does not implement poisoning.
+///
+/// This is a wrapper around `Box<imp::Mutex>`, to allow the object to be moved
+/// without moving the raw mutex.
+pub struct MovableMutex(Box<imp::Mutex>);
+
+unsafe impl Sync for MovableMutex {}
+
+impl MovableMutex {
+    /// Creates a new mutex.
+    pub fn new() -> Self {
+        let mut mutex = box imp::Mutex::new();
+        unsafe { mutex.init() };
+        Self(mutex)
+    }
+
+    pub(crate) fn raw(&self) -> &imp::Mutex {
+        &self.0
+    }
+
+    /// Locks the mutex blocking the current thread until it is available.
     #[inline]
-    pub unsafe fn lock(&self) -> MutexGuard<'_> {
-        self.raw_lock();
-        MutexGuard(&self.0)
+    pub fn raw_lock(&self) {
+        unsafe { self.0.lock() }
     }
 
     /// Attempts to lock the mutex without blocking, returning whether it was
     /// successfully acquired or not.
-    ///
-    /// Behavior is undefined if the mutex has been moved between this and any
-    /// previous function call.
     #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        self.0.try_lock()
+    pub fn try_lock(&self) -> bool {
+        unsafe { self.0.try_lock() }
     }
 
     /// Unlocks the mutex.
     ///
     /// Behavior is undefined if the current thread does not actually hold the
     /// mutex.
-    ///
-    /// Consider switching from the pair of raw_lock() and raw_unlock() to
-    /// lock() whenever possible.
     #[inline]
     pub unsafe fn raw_unlock(&self) {
         self.0.unlock()
     }
-
-    /// Deallocates all resources associated with this mutex.
-    ///
-    /// Behavior is undefined if there are current or will be future users of
-    /// this mutex.
-    #[inline]
-    pub unsafe fn destroy(&self) {
-        self.0.destroy()
-    }
 }
 
-// not meant to be exported to the outside world, just the containing module
-pub fn raw(mutex: &Mutex) -> &imp::Mutex {
-    &mutex.0
-}
-
-#[must_use]
-/// A simple RAII utility for the above Mutex without the poisoning semantics.
-pub struct MutexGuard<'a>(&'a imp::Mutex);
-
-impl Drop for MutexGuard<'_> {
-    #[inline]
+impl Drop for MovableMutex {
     fn drop(&mut self) {
-        unsafe {
-            self.0.unlock();
-        }
+        unsafe { self.0.destroy() };
     }
 }
diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs
index 676eadd1fac..dbcb7b36265 100644
--- a/library/std/src/sys_common/thread_local_key.rs
+++ b/library/std/src/sys_common/thread_local_key.rs
@@ -53,7 +53,7 @@ mod tests;
 
 use crate::sync::atomic::{self, AtomicUsize, Ordering};
 use crate::sys::thread_local_key as imp;
-use crate::sys_common::mutex::Mutex;
+use crate::sys_common::mutex::StaticMutex;
 
 /// A type for TLS keys that are statically allocated.
 ///
@@ -157,7 +157,7 @@ impl StaticKey {
         if imp::requires_synchronized_create() {
             // We never call `INIT_LOCK.init()`, so it is UB to attempt to
             // acquire this mutex reentrantly!
-            static INIT_LOCK: Mutex = Mutex::new();
+            static INIT_LOCK: StaticMutex = StaticMutex::new();
             let _guard = INIT_LOCK.lock();
             let mut key = self.key.load(Ordering::SeqCst);
             if key == 0 {
diff --git a/library/std/src/sys_common/thread_parker/futex.rs b/library/std/src/sys_common/thread_parker/futex.rs
new file mode 100644
index 00000000000..a5d4927dcc5
--- /dev/null
+++ b/library/std/src/sys_common/thread_parker/futex.rs
@@ -0,0 +1,93 @@
+use crate::sync::atomic::AtomicI32;
+use crate::sync::atomic::Ordering::{Acquire, Release};
+use crate::sys::futex::{futex_wait, futex_wake};
+use crate::time::Duration;
+
+const PARKED: i32 = -1;
+const EMPTY: i32 = 0;
+const NOTIFIED: i32 = 1;
+
+pub struct Parker {
+    state: AtomicI32,
+}
+
+// Notes about memory ordering:
+//
+// Memory ordering is only relevant for the relative ordering of operations
+// between different variables. Even Ordering::Relaxed guarantees a
+// monotonic/consistent order when looking at just a single atomic variable.
+//
+// So, since this parker is just a single atomic variable, we only need to look
+// at the ordering guarantees we need to provide to the 'outside world'.
+//
+// The only memory ordering guarantee that parking and unparking provide, is
+// that things which happened before unpark() are visible on the thread
+// returning from park() afterwards. Otherwise, it was effectively unparked
+// before unpark() was called while still consuming the 'token'.
+//
+// In other words, unpark() needs to synchronize with the part of park() that
+// consumes the token and returns.
+//
+// This is done with a release-acquire synchronization, by using
+// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using
+// Ordering::Acquire when checking for this state in park().
+impl Parker {
+    #[inline]
+    pub const fn new() -> Self {
+        Parker { state: AtomicI32::new(EMPTY) }
+    }
+
+    // Assumes this is only called by the thread that owns the Parker,
+    // which means that `self.state != PARKED`.
+    pub unsafe fn park(&self) {
+        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
+        // first case.
+        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
+            return;
+        }
+        loop {
+            // Wait for something to happen, assuming it's still set to PARKED.
+            futex_wait(&self.state, PARKED, None);
+            // Change NOTIFIED=>EMPTY and return in that case.
+            if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED {
+                return;
+            } else {
+                // Spurious wake up. We loop to try again.
+            }
+        }
+    }
+
+    // Assumes this is only called by the thread that owns the Parker,
+    // which means that `self.state != PARKED`.
+    pub unsafe fn park_timeout(&self, timeout: Duration) {
+        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
+        // first case.
+        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
+            return;
+        }
+        // Wait for something to happen, assuming it's still set to PARKED.
+        futex_wait(&self.state, PARKED, Some(timeout));
+        // This is not just a store, because we need to establish a
+        // release-acquire ordering with unpark().
+        if self.state.swap(EMPTY, Acquire) == NOTIFIED {
+            // Woke up because of unpark().
+        } else {
+            // Timeout or spurious wake up.
+            // We return either way, because we can't easily tell if it was the
+            // timeout or not.
+        }
+    }
+
+    #[inline]
+    pub fn unpark(&self) {
+        // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
+        // wake the thread in the first case.
+        //
+        // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
+        // purpose, to make sure every unpark() has a release-acquire ordering
+        // with park().
+        if self.state.swap(NOTIFIED, Release) == PARKED {
+            futex_wake(&self.state);
+        }
+    }
+}
diff --git a/library/std/src/sys_common/thread_parker/generic.rs b/library/std/src/sys_common/thread_parker/generic.rs
new file mode 100644
index 00000000000..14cfa958e5e
--- /dev/null
+++ b/library/std/src/sys_common/thread_parker/generic.rs
@@ -0,0 +1,119 @@
+//! Parker implementaiton based on a Mutex and Condvar.
+
+use crate::sync::atomic::AtomicUsize;
+use crate::sync::atomic::Ordering::SeqCst;
+use crate::sync::{Condvar, Mutex};
+use crate::time::Duration;
+
+const EMPTY: usize = 0;
+const PARKED: usize = 1;
+const NOTIFIED: usize = 2;
+
+pub struct Parker {
+    state: AtomicUsize,
+    lock: Mutex<()>,
+    cvar: Condvar,
+}
+
+impl Parker {
+    pub fn new() -> Self {
+        Parker { state: AtomicUsize::new(EMPTY), lock: Mutex::new(()), cvar: Condvar::new() }
+    }
+
+    // This implementaiton doesn't require `unsafe`, but other implementations
+    // may assume this is only called by the thread that owns the Parker.
+    pub unsafe fn park(&self) {
+        // If we were previously notified then we consume this notification and
+        // return quickly.
+        if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+            return;
+        }
+
+        // Otherwise we need to coordinate going to sleep
+        let mut m = self.lock.lock().unwrap();
+        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+            Ok(_) => {}
+            Err(NOTIFIED) => {
+                // We must read here, even though we know it will be `NOTIFIED`.
+                // This is because `unpark` may have been called again since we read
+                // `NOTIFIED` in the `compare_exchange` above. We must perform an
+                // acquire operation that synchronizes with that `unpark` to observe
+                // any writes it made before the call to unpark. To do that we must
+                // read from the write it made to `state`.
+                let old = self.state.swap(EMPTY, SeqCst);
+                assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
+                return;
+            } // should consume this notification, so prohibit spurious wakeups in next park.
+            Err(_) => panic!("inconsistent park state"),
+        }
+        loop {
+            m = self.cvar.wait(m).unwrap();
+            match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) {
+                Ok(_) => return, // got a notification
+                Err(_) => {}     // spurious wakeup, go back to sleep
+            }
+        }
+    }
+
+    // This implementaiton doesn't require `unsafe`, but other implementations
+    // may assume this is only called by the thread that owns the Parker.
+    pub unsafe fn park_timeout(&self, dur: Duration) {
+        // Like `park` above we have a fast path for an already-notified thread, and
+        // afterwards we start coordinating for a sleep.
+        // return quickly.
+        if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+            return;
+        }
+        let m = self.lock.lock().unwrap();
+        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+            Ok(_) => {}
+            Err(NOTIFIED) => {
+                // We must read again here, see `park`.
+                let old = self.state.swap(EMPTY, SeqCst);
+                assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
+                return;
+            } // should consume this notification, so prohibit spurious wakeups in next park.
+            Err(_) => panic!("inconsistent park_timeout state"),
+        }
+
+        // Wait with a timeout, and if we spuriously wake up or otherwise wake up
+        // from a notification we just want to unconditionally set the state back to
+        // empty, either consuming a notification or un-flagging ourselves as
+        // parked.
+        let (_m, _result) = self.cvar.wait_timeout(m, dur).unwrap();
+        match self.state.swap(EMPTY, SeqCst) {
+            NOTIFIED => {} // got a notification, hurray!
+            PARKED => {}   // no notification, alas
+            n => panic!("inconsistent park_timeout state: {}", n),
+        }
+    }
+
+    pub fn unpark(&self) {
+        // To ensure the unparked thread will observe any writes we made
+        // before this call, we must perform a release operation that `park`
+        // can synchronize with. To do that we must write `NOTIFIED` even if
+        // `state` is already `NOTIFIED`. That is why this must be a swap
+        // rather than a compare-and-swap that returns if it reads `NOTIFIED`
+        // on failure.
+        match self.state.swap(NOTIFIED, SeqCst) {
+            EMPTY => return,    // no one was waiting
+            NOTIFIED => return, // already unparked
+            PARKED => {}        // gotta go wake someone up
+            _ => panic!("inconsistent state in unpark"),
+        }
+
+        // There is a period between when the parked thread sets `state` to
+        // `PARKED` (or last checked `state` in the case of a spurious wake
+        // up) and when it actually waits on `cvar`. If we were to notify
+        // during this period it would be ignored and then when the parked
+        // thread went to sleep it would never wake up. Fortunately, it has
+        // `lock` locked at this stage so we can acquire `lock` to wait until
+        // it is ready to receive the notification.
+        //
+        // Releasing `lock` before the call to `notify_one` means that when the
+        // parked thread wakes it doesn't get woken only to have to wait for us
+        // to release `lock`.
+        drop(self.lock.lock().unwrap());
+        self.cvar.notify_one()
+    }
+}
diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs
new file mode 100644
index 00000000000..23c17c8e2cf
--- /dev/null
+++ b/library/std/src/sys_common/thread_parker/mod.rs
@@ -0,0 +1,9 @@
+cfg_if::cfg_if! {
+    if #[cfg(any(target_os = "linux", target_os = "android"))] {
+        mod futex;
+        pub use futex::Parker;
+    } else {
+        mod generic;
+        pub use generic::Parker;
+    }
+}
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 8c353e2484e..087175bb92a 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -159,13 +159,12 @@ use crate::num::NonZeroU64;
 use crate::panic;
 use crate::panicking;
 use crate::str;
-use crate::sync::atomic::AtomicUsize;
-use crate::sync::atomic::Ordering::SeqCst;
-use crate::sync::{Arc, Condvar, Mutex};
+use crate::sync::Arc;
 use crate::sys::thread as imp;
 use crate::sys_common::mutex;
 use crate::sys_common::thread;
 use crate::sys_common::thread_info;
+use crate::sys_common::thread_parker::Parker;
 use crate::sys_common::{AsInner, IntoInner};
 use crate::time::Duration;
 
@@ -667,6 +666,8 @@ pub fn current() -> Thread {
 ///
 /// [`channel`]: crate::sync::mpsc
 /// [`join`]: JoinHandle::join
+/// [`Condvar`]: crate::sync::Condvar
+/// [`Mutex`]: crate::sync::Mutex
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn yield_now() {
     imp::Thread::yield_now()
@@ -712,6 +713,8 @@ pub fn yield_now() {
 ///     panic!()
 /// }
 /// ```
+///
+/// [Mutex]: crate::sync::Mutex
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn panicking() -> bool {
@@ -779,11 +782,6 @@ pub fn sleep(dur: Duration) {
     imp::Thread::sleep(dur)
 }
 
-// constants for park/unpark
-const EMPTY: usize = 0;
-const PARKED: usize = 1;
-const NOTIFIED: usize = 2;
-
 /// Blocks unless or until the current thread's token is made available.
 ///
 /// A call to `park` does not guarantee that the thread will remain parked
@@ -870,45 +868,11 @@ const NOTIFIED: usize = 2;
 ///
 /// [`unpark`]: Thread::unpark
 /// [`thread::park_timeout`]: park_timeout
-//
-// The implementation currently uses the trivial strategy of a Mutex+Condvar
-// with wakeup flag, which does not actually allow spurious wakeups. In the
-// future, this will be implemented in a more efficient way, perhaps along the lines of
-//   http://cr.openjdk.java.net/~stefank/6989984.1/raw_files/new/src/os/linux/vm/os_linux.cpp
-// or futuxes, and in either case may allow spurious wakeups.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn park() {
-    let thread = current();
-
-    // If we were previously notified then we consume this notification and
-    // return quickly.
-    if thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
-        return;
-    }
-
-    // Otherwise we need to coordinate going to sleep
-    let mut m = thread.inner.lock.lock().unwrap();
-    match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
-        Ok(_) => {}
-        Err(NOTIFIED) => {
-            // We must read here, even though we know it will be `NOTIFIED`.
-            // This is because `unpark` may have been called again since we read
-            // `NOTIFIED` in the `compare_exchange` above. We must perform an
-            // acquire operation that synchronizes with that `unpark` to observe
-            // any writes it made before the call to unpark. To do that we must
-            // read from the write it made to `state`.
-            let old = thread.inner.state.swap(EMPTY, SeqCst);
-            assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
-            return;
-        } // should consume this notification, so prohibit spurious wakeups in next park.
-        Err(_) => panic!("inconsistent park state"),
-    }
-    loop {
-        m = thread.inner.cvar.wait(m).unwrap();
-        match thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) {
-            Ok(_) => return, // got a notification
-            Err(_) => {}     // spurious wakeup, go back to sleep
-        }
+    // SAFETY: park_timeout is called on the parker owned by this thread.
+    unsafe {
+        current().inner.parker.park();
     }
 }
 
@@ -970,35 +934,9 @@ pub fn park_timeout_ms(ms: u32) {
 /// ```
 #[stable(feature = "park_timeout", since = "1.4.0")]
 pub fn park_timeout(dur: Duration) {
-    let thread = current();
-
-    // Like `park` above we have a fast path for an already-notified thread, and
-    // afterwards we start coordinating for a sleep.
-    // return quickly.
-    if thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
-        return;
-    }
-    let m = thread.inner.lock.lock().unwrap();
-    match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
-        Ok(_) => {}
-        Err(NOTIFIED) => {
-            // We must read again here, see `park`.
-            let old = thread.inner.state.swap(EMPTY, SeqCst);
-            assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
-            return;
-        } // should consume this notification, so prohibit spurious wakeups in next park.
-        Err(_) => panic!("inconsistent park_timeout state"),
-    }
-
-    // Wait with a timeout, and if we spuriously wake up or otherwise wake up
-    // from a notification we just want to unconditionally set the state back to
-    // empty, either consuming a notification or un-flagging ourselves as
-    // parked.
-    let (_m, _result) = thread.inner.cvar.wait_timeout(m, dur).unwrap();
-    match thread.inner.state.swap(EMPTY, SeqCst) {
-        NOTIFIED => {} // got a notification, hurray!
-        PARKED => {}   // no notification, alas
-        n => panic!("inconsistent park_timeout state: {}", n),
+    // SAFETY: park_timeout is called on the parker owned by this thread.
+    unsafe {
+        current().inner.parker.park_timeout(dur);
     }
 }
 
@@ -1034,9 +972,8 @@ pub struct ThreadId(NonZeroU64);
 impl ThreadId {
     // Generate a new unique thread ID.
     fn new() -> ThreadId {
-        // We never call `GUARD.init()`, so it is UB to attempt to
-        // acquire this mutex reentrantly!
-        static GUARD: mutex::Mutex = mutex::Mutex::new();
+        // It is UB to attempt to acquire this mutex reentrantly!
+        static GUARD: mutex::StaticMutex = mutex::StaticMutex::new();
         static mut COUNTER: u64 = 1;
 
         unsafe {
@@ -1077,11 +1014,7 @@ impl ThreadId {
 struct Inner {
     name: Option<CString>, // Guaranteed to be UTF-8
     id: ThreadId,
-
-    // state for thread park/unpark
-    state: AtomicUsize,
-    lock: Mutex<()>,
-    cvar: Condvar,
+    parker: Parker,
 }
 
 #[derive(Clone)]
@@ -1115,13 +1048,7 @@ impl Thread {
         let cname =
             name.map(|n| CString::new(n).expect("thread name may not contain interior null bytes"));
         Thread {
-            inner: Arc::new(Inner {
-                name: cname,
-                id: ThreadId::new(),
-                state: AtomicUsize::new(EMPTY),
-                lock: Mutex::new(()),
-                cvar: Condvar::new(),
-            }),
+            inner: Arc::new(Inner { name: cname, id: ThreadId::new(), parker: Parker::new() }),
         }
     }
 
@@ -1156,33 +1083,9 @@ impl Thread {
     /// parked_thread.join().unwrap();
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[inline]
     pub fn unpark(&self) {
-        // To ensure the unparked thread will observe any writes we made
-        // before this call, we must perform a release operation that `park`
-        // can synchronize with. To do that we must write `NOTIFIED` even if
-        // `state` is already `NOTIFIED`. That is why this must be a swap
-        // rather than a compare-and-swap that returns if it reads `NOTIFIED`
-        // on failure.
-        match self.inner.state.swap(NOTIFIED, SeqCst) {
-            EMPTY => return,    // no one was waiting
-            NOTIFIED => return, // already unparked
-            PARKED => {}        // gotta go wake someone up
-            _ => panic!("inconsistent state in unpark"),
-        }
-
-        // There is a period between when the parked thread sets `state` to
-        // `PARKED` (or last checked `state` in the case of a spurious wake
-        // up) and when it actually waits on `cvar`. If we were to notify
-        // during this period it would be ignored and then when the parked
-        // thread went to sleep it would never wake up. Fortunately, it has
-        // `lock` locked at this stage so we can acquire `lock` to wait until
-        // it is ready to receive the notification.
-        //
-        // Releasing `lock` before the call to `notify_one` means that when the
-        // parked thread wakes it doesn't get woken only to have to wait for us
-        // to release `lock`.
-        drop(self.inner.lock.lock().unwrap());
-        self.inner.cvar.notify_one()
+        self.inner.parker.unpark();
     }
 
     /// Gets the thread's unique identifier.
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index 18e38c6299b..e7df3841147 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -20,7 +20,7 @@ use crate::error::Error;
 use crate::fmt;
 use crate::ops::{Add, AddAssign, Sub, SubAssign};
 use crate::sys::time;
-use crate::sys_common::mutex::Mutex;
+use crate::sys_common::mutex::StaticMutex;
 use crate::sys_common::FromInner;
 
 #[stable(feature = "time", since = "1.3.0")]
@@ -243,7 +243,7 @@ impl Instant {
             return Instant(os_now);
         }
 
-        static LOCK: Mutex = Mutex::new();
+        static LOCK: StaticMutex = StaticMutex::new();
         static mut LAST_NOW: time::Instant = time::Instant::zero();
         unsafe {
             let _lock = LOCK.lock();