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/ascii.rs2
-rw-r--r--library/std/src/backtrace.rs2
-rw-r--r--library/std/src/collections/hash/map.rs201
-rw-r--r--library/std/src/collections/hash/map/tests.rs7
-rw-r--r--library/std/src/collections/hash/set.rs48
-rw-r--r--library/std/src/collections/hash/set/tests.rs6
-rw-r--r--library/std/src/collections/mod.rs8
-rw-r--r--library/std/src/env/tests.rs2
-rw-r--r--library/std/src/error.rs2
-rw-r--r--library/std/src/f32.rs4
-rw-r--r--library/std/src/f64.rs4
-rw-r--r--library/std/src/ffi/mod.rs10
-rw-r--r--library/std/src/ffi/os_str.rs3
-rw-r--r--library/std/src/fs.rs111
-rw-r--r--library/std/src/fs/tests.rs6
-rw-r--r--library/std/src/hash/random.rs5
-rw-r--r--library/std/src/io/buffered/bufreader.rs14
-rw-r--r--library/std/src/io/buffered/bufreader/buffer.rs16
-rw-r--r--library/std/src/io/buffered/bufwriter.rs12
-rw-r--r--library/std/src/io/buffered/tests.rs3
-rw-r--r--library/std/src/io/copy.rs2
-rw-r--r--library/std/src/io/copy/tests.rs2
-rw-r--r--library/std/src/io/error.rs6
-rw-r--r--library/std/src/io/error/repr_bitpacked.rs2
-rw-r--r--library/std/src/io/error/tests.rs2
-rw-r--r--library/std/src/io/mod.rs62
-rw-r--r--library/std/src/io/stdio.rs8
-rw-r--r--library/std/src/io/stdio/tests.rs15
-rw-r--r--library/std/src/io/tests.rs67
-rw-r--r--library/std/src/io/util/tests.rs2
-rw-r--r--library/std/src/keyword_docs.rs4
-rw-r--r--library/std/src/lib.rs47
-rw-r--r--library/std/src/net/ip_addr.rs2
-rw-r--r--library/std/src/net/ip_addr/tests.rs2
-rw-r--r--library/std/src/net/socket_addr.rs2
-rw-r--r--library/std/src/net/tcp.rs13
-rw-r--r--library/std/src/net/tcp/tests.rs29
-rw-r--r--library/std/src/net/udp.rs18
-rw-r--r--library/std/src/net/udp/tests.rs9
-rw-r--r--library/std/src/num.rs4
-rw-r--r--library/std/src/os/fortanix_sgx/mod.rs12
-rw-r--r--library/std/src/os/mod.rs2
-rw-r--r--library/std/src/os/nuttx/fs.rs92
-rw-r--r--library/std/src/os/nuttx/mod.rs4
-rw-r--r--library/std/src/os/nuttx/raw.rs33
-rw-r--r--library/std/src/os/unix/mod.rs2
-rw-r--r--library/std/src/os/unix/net/addr.rs23
-rw-r--r--library/std/src/os/unix/net/ancillary.rs6
-rw-r--r--library/std/src/os/unix/net/datagram.rs16
-rw-r--r--library/std/src/os/unix/net/listener.rs12
-rw-r--r--library/std/src/os/unix/net/stream.rs12
-rw-r--r--library/std/src/os/unix/net/ucred.rs8
-rw-r--r--library/std/src/os/wasi/mod.rs2
-rw-r--r--library/std/src/os/xous/ffi/definitions.rs66
-rw-r--r--library/std/src/os/xous/services.rs2
-rw-r--r--library/std/src/os/xous/services/systime.rs2
-rw-r--r--library/std/src/panic.rs62
-rw-r--r--library/std/src/panicking.rs20
-rw-r--r--library/std/src/path.rs6
-rw-r--r--library/std/src/path/tests.rs16
-rw-r--r--library/std/src/pipe.rs2
-rw-r--r--library/std/src/process.rs12
-rw-r--r--library/std/src/process/tests.rs2
-rw-r--r--library/std/src/random.rs105
-rw-r--r--library/std/src/rt.rs55
-rw-r--r--library/std/src/sync/barrier/tests.rs4
-rw-r--r--library/std/src/sync/condvar.rs2
-rw-r--r--library/std/src/sync/condvar/tests.rs16
-rw-r--r--library/std/src/sync/lazy_lock/tests.rs6
-rw-r--r--library/std/src/sync/mod.rs18
-rw-r--r--library/std/src/sync/mpmc/context.rs2
-rw-r--r--library/std/src/sync/mpmc/error.rs5
-rw-r--r--library/std/src/sync/mpmc/mod.rs1037
-rw-r--r--library/std/src/sync/mpmc/tests.rs728
-rw-r--r--library/std/src/sync/mpmc/waker.rs2
-rw-r--r--library/std/src/sync/mpmc/zero.rs14
-rw-r--r--library/std/src/sync/mpsc/mod.rs4
-rw-r--r--library/std/src/sync/mutex.rs4
-rw-r--r--library/std/src/sync/once.rs2
-rw-r--r--library/std/src/sync/once_lock/tests.rs9
-rw-r--r--library/std/src/sync/reentrant_lock.rs4
-rw-r--r--library/std/src/sync/rwlock.rs4
-rw-r--r--library/std/src/sys/alloc/solid.rs2
-rw-r--r--library/std/src/sys/alloc/unix.rs3
-rw-r--r--library/std/src/sys/alloc/wasm.rs3
-rw-r--r--library/std/src/sys/alloc/windows.rs2
-rw-r--r--library/std/src/sys/dbg.rs229
-rw-r--r--library/std/src/sys/mod.rs2
-rw-r--r--library/std/src/sys/os_str/bytes.rs3
-rw-r--r--library/std/src/sys/os_str/wtf8.rs5
-rw-r--r--library/std/src/sys/pal/hermit/args.rs2
-rw-r--r--library/std/src/sys/pal/hermit/fs.rs4
-rw-r--r--library/std/src/sys/pal/hermit/mod.rs20
-rw-r--r--library/std/src/sys/pal/hermit/net.rs4
-rw-r--r--library/std/src/sys/pal/hermit/thread.rs1
-rw-r--r--library/std/src/sys/pal/hermit/time.rs8
-rw-r--r--library/std/src/sys/pal/itron/task.rs2
-rw-r--r--library/std/src/sys/pal/itron/thread.rs2
-rw-r--r--library/std/src/sys/pal/itron/time/tests.rs30
-rw-r--r--library/std/src/sys/pal/sgx/abi/usercalls/mod.rs4
-rw-r--r--library/std/src/sys/pal/sgx/abi/usercalls/tests.rs2
-rw-r--r--library/std/src/sys/pal/sgx/mod.rs18
-rw-r--r--library/std/src/sys/pal/sgx/net.rs16
-rw-r--r--library/std/src/sys/pal/sgx/waitqueue/mod.rs4
-rw-r--r--library/std/src/sys/pal/solid/abi/fs.rs4
-rw-r--r--library/std/src/sys/pal/solid/abi/mod.rs2
-rw-r--r--library/std/src/sys/pal/solid/error.rs2
-rw-r--r--library/std/src/sys/pal/solid/mod.rs10
-rw-r--r--library/std/src/sys/pal/solid/net.rs2
-rw-r--r--library/std/src/sys/pal/teeos/mod.rs3
-rw-r--r--library/std/src/sys/pal/teeos/rand.rs21
-rw-r--r--library/std/src/sys/pal/uefi/helpers.rs2
-rw-r--r--library/std/src/sys/pal/uefi/mod.rs33
-rw-r--r--library/std/src/sys/pal/uefi/os.rs4
-rw-r--r--library/std/src/sys/pal/unix/args.rs1
-rw-r--r--library/std/src/sys/pal/unix/env.rs11
-rw-r--r--library/std/src/sys/pal/unix/fd.rs58
-rw-r--r--library/std/src/sys/pal/unix/fs.rs41
-rw-r--r--library/std/src/sys/pal/unix/mod.rs6
-rw-r--r--library/std/src/sys/pal/unix/net.rs10
-rw-r--r--library/std/src/sys/pal/unix/os.rs6
-rw-r--r--library/std/src/sys/pal/unix/process/mod.rs6
-rw-r--r--library/std/src/sys/pal/unix/process/process_common.rs6
-rw-r--r--library/std/src/sys/pal/unix/process/process_fuchsia.rs6
-rw-r--r--library/std/src/sys/pal/unix/process/process_unix.rs16
-rw-r--r--library/std/src/sys/pal/unix/process/process_vxworks.rs4
-rw-r--r--library/std/src/sys/pal/unix/rand.rs302
-rw-r--r--library/std/src/sys/pal/unix/stack_overflow.rs15
-rw-r--r--library/std/src/sys/pal/unix/thread.rs30
-rw-r--r--library/std/src/sys/pal/unix/thread_parking.rs2
-rw-r--r--library/std/src/sys/pal/unsupported/common.rs4
-rw-r--r--library/std/src/sys/pal/wasi/fs.rs2
-rw-r--r--library/std/src/sys/pal/wasi/helpers.rs12
-rw-r--r--library/std/src/sys/pal/wasi/mod.rs2
-rw-r--r--library/std/src/sys/pal/wasip2/mod.rs3
-rw-r--r--library/std/src/sys/pal/wasip2/net.rs417
-rw-r--r--library/std/src/sys/pal/windows/api.rs3
-rw-r--r--library/std/src/sys/pal/windows/args.rs2
-rw-r--r--library/std/src/sys/pal/windows/args/tests.rs8
-rw-r--r--library/std/src/sys/pal/windows/c.rs4
-rw-r--r--library/std/src/sys/pal/windows/compat.rs10
-rw-r--r--library/std/src/sys/pal/windows/fs.rs42
-rw-r--r--library/std/src/sys/pal/windows/futex.rs6
-rw-r--r--library/std/src/sys/pal/windows/handle/tests.rs2
-rw-r--r--library/std/src/sys/pal/windows/io.rs2
-rw-r--r--library/std/src/sys/pal/windows/mod.rs3
-rw-r--r--library/std/src/sys/pal/windows/net.rs16
-rw-r--r--library/std/src/sys/pal/windows/pipe.rs9
-rw-r--r--library/std/src/sys/pal/windows/process.rs16
-rw-r--r--library/std/src/sys/pal/windows/process/tests.rs2
-rw-r--r--library/std/src/sys/pal/windows/rand.rs27
-rw-r--r--library/std/src/sys/pal/xous/net/dns.rs2
-rw-r--r--library/std/src/sys/pal/xous/stdio.rs4
-rw-r--r--library/std/src/sys/pal/xous/thread.rs6
-rw-r--r--library/std/src/sys/pal/zkvm/args.rs2
-rw-r--r--library/std/src/sys/pal/zkvm/mod.rs8
-rw-r--r--library/std/src/sys/pal/zkvm/os.rs2
-rw-r--r--library/std/src/sys/path/windows.rs2
-rw-r--r--library/std/src/sys/personality/mod.rs2
-rw-r--r--library/std/src/sys/random/apple.rs15
-rw-r--r--library/std/src/sys/random/arc4random.rs34
-rw-r--r--library/std/src/sys/random/espidf.rs9
-rw-r--r--library/std/src/sys/random/fuchsia.rs13
-rw-r--r--library/std/src/sys/random/getentropy.rs17
-rw-r--r--library/std/src/sys/random/hermit.rs7
-rw-r--r--library/std/src/sys/random/horizon.rs7
-rw-r--r--library/std/src/sys/random/linux.rs170
-rw-r--r--library/std/src/sys/random/mod.rs96
-rw-r--r--library/std/src/sys/random/redox.rs12
-rw-r--r--library/std/src/sys/random/sgx.rs67
-rw-r--r--library/std/src/sys/random/solid.rs8
-rw-r--r--library/std/src/sys/random/teeos.rs7
-rw-r--r--library/std/src/sys/random/uefi.rs27
-rw-r--r--library/std/src/sys/random/unix_legacy.rs20
-rw-r--r--library/std/src/sys/random/unsupported.rs15
-rw-r--r--library/std/src/sys/random/vxworks.rs25
-rw-r--r--library/std/src/sys/random/wasi.rs5
-rw-r--r--library/std/src/sys/random/windows.rs20
-rw-r--r--library/std/src/sys/random/zkvm.rs21
-rw-r--r--library/std/src/sys/sync/condvar/mod.rs8
-rw-r--r--library/std/src/sys/sync/condvar/pthread.rs38
-rw-r--r--library/std/src/sys/sync/condvar/sgx.rs29
-rw-r--r--library/std/src/sys/sync/condvar/teeos.rs101
-rw-r--r--library/std/src/sys/sync/condvar/windows7.rs2
-rw-r--r--library/std/src/sys/sync/condvar/xous.rs2
-rw-r--r--library/std/src/sys/sync/mod.rs3
-rw-r--r--library/std/src/sys/sync/mutex/fuchsia.rs6
-rw-r--r--library/std/src/sys/sync/mutex/itron.rs2
-rw-r--r--library/std/src/sys/sync/mutex/mod.rs2
-rw-r--r--library/std/src/sys/sync/mutex/pthread.rs83
-rw-r--r--library/std/src/sys/sync/mutex/sgx.rs30
-rw-r--r--library/std/src/sys/sync/mutex/xous.rs2
-rw-r--r--library/std/src/sys/sync/once_box.rs82
-rw-r--r--library/std/src/sys/sync/rwlock/queue.rs8
-rw-r--r--library/std/src/sys/sync/rwlock/solid.rs2
-rw-r--r--library/std/src/sys/sync/rwlock/teeos.rs8
-rw-r--r--library/std/src/sys/sync/thread_parking/id.rs4
-rw-r--r--library/std/src/sys/sync/thread_parking/mod.rs1
-rw-r--r--library/std/src/sys/sync/thread_parking/pthread.rs11
-rw-r--r--library/std/src/sys/sync/thread_parking/windows7.rs4
-rw-r--r--library/std/src/sys/sync/thread_parking/xous.rs2
-rw-r--r--library/std/src/sys/thread_local/destructors/linux_like.rs2
-rw-r--r--library/std/src/sys/thread_local/guard/apple.rs1
-rw-r--r--library/std/src/sys/thread_local/guard/key.rs41
-rw-r--r--library/std/src/sys/thread_local/guard/solid.rs5
-rw-r--r--library/std/src/sys/thread_local/guard/windows.rs8
-rw-r--r--library/std/src/sys/thread_local/key/tests.rs2
-rw-r--r--library/std/src/sys/thread_local/key/xous.rs4
-rw-r--r--library/std/src/sys/thread_local/mod.rs48
-rw-r--r--library/std/src/sys/thread_local/native/mod.rs31
-rw-r--r--library/std/src/sys/thread_local/os.rs34
-rw-r--r--library/std/src/sys/thread_local/statik.rs33
-rw-r--r--library/std/src/sys_common/io.rs2
-rw-r--r--library/std/src/sys_common/lazy_box.rs88
-rw-r--r--library/std/src/sys_common/mod.rs4
-rw-r--r--library/std/src/sys_common/net.rs11
-rw-r--r--library/std/src/sys_common/wtf8.rs5
-rw-r--r--library/std/src/sys_common/wtf8/tests.rs111
-rw-r--r--library/std/src/thread/current.rs254
-rw-r--r--library/std/src/thread/local.rs2
-rw-r--r--library/std/src/thread/local/tests.rs36
-rw-r--r--library/std/src/thread/mod.rs170
-rw-r--r--library/std/src/thread/scoped.rs6
-rw-r--r--library/std/src/thread/tests.rs2
-rw-r--r--library/std/src/time/tests.rs4
225 files changed, 4834 insertions, 1883 deletions
diff --git a/library/std/src/ascii.rs b/library/std/src/ascii.rs
index 3a2880fd509..3813f3237fb 100644
--- a/library/std/src/ascii.rs
+++ b/library/std/src/ascii.rs
@@ -16,7 +16,7 @@
 #[unstable(feature = "ascii_char", issue = "110998")]
 pub use core::ascii::Char;
 #[stable(feature = "rust1", since = "1.0.0")]
-pub use core::ascii::{escape_default, EscapeDefault};
+pub use core::ascii::{EscapeDefault, escape_default};
 
 /// Extension methods for ASCII-subset only operations.
 ///
diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs
index 7df9a8a14b0..fc333d7ff3f 100644
--- a/library/std/src/backtrace.rs
+++ b/library/std/src/backtrace.rs
@@ -91,9 +91,9 @@ mod tests;
 use crate::backtrace_rs::{self, BytesOrWideString};
 use crate::ffi::c_void;
 use crate::panic::UnwindSafe;
+use crate::sync::LazyLock;
 use crate::sync::atomic::AtomicU8;
 use crate::sync::atomic::Ordering::Relaxed;
-use crate::sync::LazyLock;
 use crate::sys::backtrace::{lock, output_filename, set_image_base};
 use crate::{env, fmt};
 
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index 1a18721b15e..f2e523dca77 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -909,8 +909,11 @@ where
     /// Attempts to get mutable references to `N` values in the map at once.
     ///
     /// Returns an array of length `N` with the results of each query. For soundness, at most one
-    /// mutable reference will be returned to any value. `None` will be returned if any of the
-    /// keys are duplicates or missing.
+    /// mutable reference will be returned to any value. `None` will be used if the key is missing.
+    ///
+    /// # Panics
+    ///
+    /// Panics if any keys are overlapping.
     ///
     /// # Examples
     ///
@@ -924,16 +927,23 @@ where
     /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691);
     /// libraries.insert("Library of Congress".to_string(), 1800);
     ///
+    /// // Get Athenæum and Bodleian Library
+    /// let [Some(a), Some(b)] = libraries.get_many_mut([
+    ///     "Athenæum",
+    ///     "Bodleian Library",
+    /// ]) else { panic!() };
+    ///
+    /// // Assert values of Athenæum and Library of Congress
     /// let got = libraries.get_many_mut([
     ///     "Athenæum",
     ///     "Library of Congress",
     /// ]);
     /// assert_eq!(
     ///     got,
-    ///     Some([
-    ///         &mut 1807,
-    ///         &mut 1800,
-    ///     ]),
+    ///     [
+    ///         Some(&mut 1807),
+    ///         Some(&mut 1800),
+    ///     ],
     /// );
     ///
     /// // Missing keys result in None
@@ -941,18 +951,31 @@ where
     ///     "Athenæum",
     ///     "New York Public Library",
     /// ]);
-    /// assert_eq!(got, None);
+    /// assert_eq!(
+    ///     got,
+    ///     [
+    ///         Some(&mut 1807),
+    ///         None
+    ///     ]
+    /// );
+    /// ```
     ///
-    /// // Duplicate keys result in None
+    /// ```should_panic
+    /// #![feature(map_many_mut)]
+    /// use std::collections::HashMap;
+    ///
+    /// let mut libraries = HashMap::new();
+    /// libraries.insert("Athenæum".to_string(), 1807);
+    ///
+    /// // Duplicate keys panic!
     /// let got = libraries.get_many_mut([
     ///     "Athenæum",
     ///     "Athenæum",
     /// ]);
-    /// assert_eq!(got, None);
     /// ```
     #[inline]
     #[unstable(feature = "map_many_mut", issue = "97601")]
-    pub fn get_many_mut<Q: ?Sized, const N: usize>(&mut self, ks: [&Q; N]) -> Option<[&'_ mut V; N]>
+    pub fn get_many_mut<Q: ?Sized, const N: usize>(&mut self, ks: [&Q; N]) -> [Option<&'_ mut V>; N]
     where
         K: Borrow<Q>,
         Q: Hash + Eq,
@@ -963,10 +986,10 @@ where
     /// Attempts to get mutable references to `N` values in the map at once, without validating that
     /// the values are unique.
     ///
-    /// Returns an array of length `N` with the results of each query. `None` will be returned if
-    /// any of the keys are missing.
+    /// Returns an array of length `N` with the results of each query. `None` will be used if
+    /// the key is missing.
     ///
-    /// For a safe alternative see [`get_many_mut`](Self::get_many_mut).
+    /// For a safe alternative see [`get_many_mut`](`HashMap::get_many_mut`).
     ///
     /// # Safety
     ///
@@ -987,31 +1010,39 @@ where
     /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691);
     /// libraries.insert("Library of Congress".to_string(), 1800);
     ///
-    /// let got = libraries.get_many_mut([
+    /// // SAFETY: The keys do not overlap.
+    /// let [Some(a), Some(b)] = (unsafe { libraries.get_many_unchecked_mut([
+    ///     "Athenæum",
+    ///     "Bodleian Library",
+    /// ]) }) else { panic!() };
+    ///
+    /// // SAFETY: The keys do not overlap.
+    /// let got = unsafe { libraries.get_many_unchecked_mut([
     ///     "Athenæum",
     ///     "Library of Congress",
-    /// ]);
+    /// ]) };
     /// assert_eq!(
     ///     got,
-    ///     Some([
-    ///         &mut 1807,
-    ///         &mut 1800,
-    ///     ]),
+    ///     [
+    ///         Some(&mut 1807),
+    ///         Some(&mut 1800),
+    ///     ],
     /// );
     ///
-    /// // Missing keys result in None
-    /// let got = libraries.get_many_mut([
+    /// // SAFETY: The keys do not overlap.
+    /// let got = unsafe { libraries.get_many_unchecked_mut([
     ///     "Athenæum",
     ///     "New York Public Library",
-    /// ]);
-    /// assert_eq!(got, None);
+    /// ]) };
+    /// // Missing keys result in None
+    /// assert_eq!(got, [Some(&mut 1807), None]);
     /// ```
     #[inline]
     #[unstable(feature = "map_many_mut", issue = "97601")]
     pub unsafe fn get_many_unchecked_mut<Q: ?Sized, const N: usize>(
         &mut self,
         ks: [&Q; N],
-    ) -> Option<[&'_ mut V; N]>
+    ) -> [Option<&'_ mut V>; N]
     where
         K: Borrow<Q>,
         Q: Hash + Eq,
@@ -1407,6 +1438,14 @@ impl<K, V> Clone for Iter<'_, K, V> {
     }
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for Iter<'_, K, V> {
+    #[inline]
+    fn default() -> Self {
+        Iter { base: Default::default() }
+    }
+}
+
 #[stable(feature = "std_debug", since = "1.16.0")]
 impl<K: Debug, V: Debug> fmt::Debug for Iter<'_, K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -1445,6 +1484,14 @@ impl<'a, K, V> IterMut<'a, K, V> {
     }
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for IterMut<'_, K, V> {
+    #[inline]
+    fn default() -> Self {
+        IterMut { base: Default::default() }
+    }
+}
+
 /// An owning iterator over the entries of a `HashMap`.
 ///
 /// This `struct` is created by the [`into_iter`] method on [`HashMap`]
@@ -1475,6 +1522,14 @@ impl<K, V> IntoIter<K, V> {
     }
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for IntoIter<K, V> {
+    #[inline]
+    fn default() -> Self {
+        IntoIter { base: Default::default() }
+    }
+}
+
 /// An iterator over the keys of a `HashMap`.
 ///
 /// This `struct` is created by the [`keys`] method on [`HashMap`]. See its
@@ -1507,6 +1562,14 @@ impl<K, V> Clone for Keys<'_, K, V> {
     }
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for Keys<'_, K, V> {
+    #[inline]
+    fn default() -> Self {
+        Keys { inner: Default::default() }
+    }
+}
+
 #[stable(feature = "std_debug", since = "1.16.0")]
 impl<K: Debug, V> fmt::Debug for Keys<'_, K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -1546,6 +1609,14 @@ impl<K, V> Clone for Values<'_, K, V> {
     }
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for Values<'_, K, V> {
+    #[inline]
+    fn default() -> Self {
+        Values { inner: Default::default() }
+    }
+}
+
 #[stable(feature = "std_debug", since = "1.16.0")]
 impl<K, V: Debug> fmt::Debug for Values<'_, K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -1634,6 +1705,14 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> {
     inner: IterMut<'a, K, V>,
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for ValuesMut<'_, K, V> {
+    #[inline]
+    fn default() -> Self {
+        ValuesMut { inner: Default::default() }
+    }
+}
+
 /// An owning iterator over the keys of a `HashMap`.
 ///
 /// This `struct` is created by the [`into_keys`] method on [`HashMap`].
@@ -1656,6 +1735,14 @@ pub struct IntoKeys<K, V> {
     inner: IntoIter<K, V>,
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for IntoKeys<K, V> {
+    #[inline]
+    fn default() -> Self {
+        IntoKeys { inner: Default::default() }
+    }
+}
+
 /// An owning iterator over the values of a `HashMap`.
 ///
 /// This `struct` is created by the [`into_values`] method on [`HashMap`].
@@ -1678,6 +1765,14 @@ pub struct IntoValues<K, V> {
     inner: IntoIter<K, V>,
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for IntoValues<K, V> {
+    #[inline]
+    fn default() -> Self {
+        IntoValues { inner: Default::default() }
+    }
+}
+
 /// A builder for computing where in a HashMap a key-value pair would be stored.
 ///
 /// See the [`HashMap::raw_entry_mut`] docs for usage examples.
@@ -2978,64 +3073,6 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
     pub fn remove(self) -> V {
         self.base.remove()
     }
-
-    /// Replaces the entry, returning the old key and value. The new key in the hash map will be
-    /// the key used to create this entry.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(map_entry_replace)]
-    /// use std::collections::hash_map::{Entry, HashMap};
-    /// use std::rc::Rc;
-    ///
-    /// let mut map: HashMap<Rc<String>, u32> = HashMap::new();
-    /// map.insert(Rc::new("Stringthing".to_string()), 15);
-    ///
-    /// let my_key = Rc::new("Stringthing".to_string());
-    ///
-    /// if let Entry::Occupied(entry) = map.entry(my_key) {
-    ///     // Also replace the key with a handle to our other key.
-    ///     let (old_key, old_value): (Rc<String>, u32) = entry.replace_entry(16);
-    /// }
-    ///
-    /// ```
-    #[inline]
-    #[unstable(feature = "map_entry_replace", issue = "44286")]
-    pub fn replace_entry(self, value: V) -> (K, V) {
-        self.base.replace_entry(value)
-    }
-
-    /// Replaces the key in the hash map with the key used to create this entry.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(map_entry_replace)]
-    /// use std::collections::hash_map::{Entry, HashMap};
-    /// use std::rc::Rc;
-    ///
-    /// let mut map: HashMap<Rc<String>, u32> = HashMap::new();
-    /// let known_strings: Vec<Rc<String>> = Vec::new();
-    ///
-    /// // Initialise known strings, run program, etc.
-    ///
-    /// reclaim_memory(&mut map, &known_strings);
-    ///
-    /// fn reclaim_memory(map: &mut HashMap<Rc<String>, u32>, known_strings: &[Rc<String>] ) {
-    ///     for s in known_strings {
-    ///         if let Entry::Occupied(entry) = map.entry(Rc::clone(s)) {
-    ///             // Replaces the entry's key with our version of it in `known_strings`.
-    ///             entry.replace_key();
-    ///         }
-    ///     }
-    /// }
-    /// ```
-    #[inline]
-    #[unstable(feature = "map_entry_replace", issue = "44286")]
-    pub fn replace_key(self) -> K {
-        self.base.replace_key()
-    }
 }
 
 impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs
index 6641197c372..fa8ea95b891 100644
--- a/library/std/src/collections/hash/map/tests.rs
+++ b/library/std/src/collections/hash/map/tests.rs
@@ -274,7 +274,7 @@ fn test_lots_of_insertions() {
     for _ in 0..loops {
         assert!(m.is_empty());
 
-        let count = if cfg!(miri) { 101 } else { 1001 };
+        let count = if cfg!(miri) { 66 } else { 1001 };
 
         for i in 1..count {
             assert!(m.insert(i, i).is_none());
@@ -947,7 +947,7 @@ fn test_raw_entry() {
 
 mod test_extract_if {
     use super::*;
-    use crate::panic::{catch_unwind, AssertUnwindSafe};
+    use crate::panic::{AssertUnwindSafe, catch_unwind};
     use crate::sync::atomic::{AtomicUsize, Ordering};
 
     trait EqSorted: Iterator {
@@ -1018,6 +1018,7 @@ mod test_extract_if {
     }
 
     #[test]
+    #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
     fn drop_panic_leak() {
         static PREDS: AtomicUsize = AtomicUsize::new(0);
         static DROPS: AtomicUsize = AtomicUsize::new(0);
@@ -1047,6 +1048,7 @@ mod test_extract_if {
     }
 
     #[test]
+    #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
     fn pred_panic_leak() {
         static PREDS: AtomicUsize = AtomicUsize::new(0);
         static DROPS: AtomicUsize = AtomicUsize::new(0);
@@ -1076,6 +1078,7 @@ mod test_extract_if {
 
     // Same as above, but attempt to use the iterator again after the panic in the predicate
     #[test]
+    #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
     fn pred_panic_reuse() {
         static PREDS: AtomicUsize = AtomicUsize::new(0);
         static DROPS: AtomicUsize = AtomicUsize::new(0);
diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs
index 4a113ddea3a..210f5715225 100644
--- a/library/std/src/collections/hash/set.rs
+++ b/library/std/src/collections/hash/set.rs
@@ -724,38 +724,6 @@ where
         self.base.get_or_insert(value)
     }
 
-    /// Inserts an owned copy of the given `value` into the set if it is not
-    /// present, then returns a reference to the value in the set.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(hash_set_entry)]
-    ///
-    /// use std::collections::HashSet;
-    ///
-    /// let mut set: HashSet<String> = ["cat", "dog", "horse"]
-    ///     .iter().map(|&pet| pet.to_owned()).collect();
-    ///
-    /// assert_eq!(set.len(), 3);
-    /// for &pet in &["cat", "dog", "fish"] {
-    ///     let value = set.get_or_insert_owned(pet);
-    ///     assert_eq!(value, pet);
-    /// }
-    /// assert_eq!(set.len(), 4); // a new "fish" was inserted
-    /// ```
-    #[inline]
-    #[unstable(feature = "hash_set_entry", issue = "60896")]
-    pub fn get_or_insert_owned<Q: ?Sized>(&mut self, value: &Q) -> &T
-    where
-        T: Borrow<Q>,
-        Q: Hash + Eq + ToOwned<Owned = T>,
-    {
-        // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with
-        // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`.
-        self.base.get_or_insert_owned(value)
-    }
-
     /// Inserts a value computed from `f` into the set if the given `value` is
     /// not present, then returns a reference to the value in the set.
     ///
@@ -1276,6 +1244,14 @@ pub struct Iter<'a, K: 'a> {
     base: base::Iter<'a, K>,
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K> Default for Iter<'_, K> {
+    #[inline]
+    fn default() -> Self {
+        Iter { base: Default::default() }
+    }
+}
+
 /// An owning iterator over the items of a `HashSet`.
 ///
 /// This `struct` is created by the [`into_iter`] method on [`HashSet`]
@@ -1297,6 +1273,14 @@ pub struct IntoIter<K> {
     base: base::IntoIter<K>,
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K> Default for IntoIter<K> {
+    #[inline]
+    fn default() -> Self {
+        IntoIter { base: Default::default() }
+    }
+}
+
 /// A draining iterator over the items of a `HashSet`.
 ///
 /// This `struct` is created by the [`drain`] method on [`HashSet`].
diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs
index 4e635165272..8ee8a3e8bf6 100644
--- a/library/std/src/collections/hash/set/tests.rs
+++ b/library/std/src/collections/hash/set/tests.rs
@@ -1,8 +1,8 @@
 use super::HashSet;
 use crate::hash::RandomState;
-use crate::panic::{catch_unwind, AssertUnwindSafe};
-use crate::sync::atomic::{AtomicU32, Ordering};
+use crate::panic::{AssertUnwindSafe, catch_unwind};
 use crate::sync::Arc;
+use crate::sync::atomic::{AtomicU32, Ordering};
 
 #[test]
 fn test_zero_capacities() {
@@ -429,6 +429,7 @@ fn test_extract_if() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_extract_if_drop_panic_leak() {
     static PREDS: AtomicU32 = AtomicU32::new(0);
     static DROPS: AtomicU32 = AtomicU32::new(0);
@@ -459,6 +460,7 @@ fn test_extract_if_drop_panic_leak() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_extract_if_pred_panic_leak() {
     static PREDS: AtomicU32 = AtomicU32::new(0);
     static DROPS: AtomicU32 = AtomicU32::new(0);
diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs
index 21bebff96b9..889ed3c5380 100644
--- a/library/std/src/collections/mod.rs
+++ b/library/std/src/collections/mod.rs
@@ -418,13 +418,13 @@ pub use alloc_crate::collections::TryReserveError;
 )]
 pub use alloc_crate::collections::TryReserveErrorKind;
 #[stable(feature = "rust1", since = "1.0.0")]
-pub use alloc_crate::collections::{binary_heap, btree_map, btree_set};
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use alloc_crate::collections::{linked_list, vec_deque};
-#[stable(feature = "rust1", since = "1.0.0")]
 pub use alloc_crate::collections::{BTreeMap, BTreeSet, BinaryHeap};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use alloc_crate::collections::{LinkedList, VecDeque};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc_crate::collections::{binary_heap, btree_map, btree_set};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc_crate::collections::{linked_list, vec_deque};
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(inline)]
diff --git a/library/std/src/env/tests.rs b/library/std/src/env/tests.rs
index fc7aee29733..d0217261068 100644
--- a/library/std/src/env/tests.rs
+++ b/library/std/src/env/tests.rs
@@ -1,7 +1,7 @@
 use super::*;
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi", target_env = "sgx"), ignore)]
 fn test_self_exe_path() {
     let path = current_exe();
     assert!(path.is_ok());
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index 3e17431af45..b3e63aaf1c5 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -7,7 +7,7 @@ mod tests;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::error::Error;
 #[unstable(feature = "error_generic_member_access", issue = "99301")]
-pub use core::error::{request_ref, request_value, Request};
+pub use core::error::{Request, request_ref, request_value};
 
 use crate::backtrace::Backtrace;
 use crate::fmt::{self, Write};
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index cafbe9761da..fa0b3ef6484 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -18,8 +18,8 @@ mod tests;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated, deprecated_in_future)]
 pub use core::f32::{
-    consts, DIGITS, EPSILON, INFINITY, MANTISSA_DIGITS, MAX, MAX_10_EXP, MAX_EXP, MIN, MIN_10_EXP,
-    MIN_EXP, MIN_POSITIVE, NAN, NEG_INFINITY, RADIX,
+    DIGITS, EPSILON, INFINITY, MANTISSA_DIGITS, MAX, MAX_10_EXP, MAX_EXP, MIN, MIN_10_EXP, MIN_EXP,
+    MIN_POSITIVE, NAN, NEG_INFINITY, RADIX, consts,
 };
 
 #[cfg(not(test))]
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index fba283e3a44..9fa43a6742e 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -18,8 +18,8 @@ mod tests;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated, deprecated_in_future)]
 pub use core::f64::{
-    consts, DIGITS, EPSILON, INFINITY, MANTISSA_DIGITS, MAX, MAX_10_EXP, MAX_EXP, MIN, MIN_10_EXP,
-    MIN_EXP, MIN_POSITIVE, NAN, NEG_INFINITY, RADIX,
+    DIGITS, EPSILON, INFINITY, MANTISSA_DIGITS, MAX, MAX_10_EXP, MAX_EXP, MIN, MIN_10_EXP, MIN_EXP,
+    MIN_POSITIVE, NAN, NEG_INFINITY, RADIX, consts,
 };
 
 #[cfg(not(test))]
diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs
index 2b67750c2f0..469136be883 100644
--- a/library/std/src/ffi/mod.rs
+++ b/library/std/src/ffi/mod.rs
@@ -166,11 +166,6 @@ pub mod c_str;
 
 #[stable(feature = "core_c_void", since = "1.30.0")]
 pub use core::ffi::c_void;
-#[stable(feature = "core_ffi_c", since = "1.64.0")]
-pub use core::ffi::{
-    c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint,
-    c_ulong, c_ulonglong, c_ushort,
-};
 #[unstable(
     feature = "c_variadic",
     reason = "the `c_variadic` feature has not been properly tested on \
@@ -178,6 +173,11 @@ pub use core::ffi::{
     issue = "44930"
 )]
 pub use core::ffi::{VaList, VaListImpl};
+#[stable(feature = "core_ffi_c", since = "1.64.0")]
+pub use core::ffi::{
+    c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint,
+    c_ulong, c_ulonglong, c_ushort,
+};
 
 #[doc(no_inline)]
 #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 0f905803bb8..2243f100643 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -9,7 +9,6 @@ use crate::borrow::{Borrow, Cow};
 use crate::collections::TryReserveError;
 use crate::hash::{Hash, Hasher};
 use crate::ops::{self, Range};
-use crate::ptr::addr_of_mut;
 use crate::rc::Rc;
 use crate::str::FromStr;
 use crate::sync::Arc;
@@ -1272,7 +1271,7 @@ unsafe impl CloneToUninit for OsStr {
     #[cfg_attr(debug_assertions, track_caller)]
     unsafe fn clone_to_uninit(&self, dst: *mut Self) {
         // SAFETY: we're just a wrapper around a platform-specific Slice
-        unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) }
+        unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) }
     }
 }
 
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 92d3838d9f2..675140ff18f 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -8,7 +8,15 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 #![deny(unsafe_op_in_unsafe_fn)]
 
-#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx", target_os = "xous"))))]
+#[cfg(all(
+    test,
+    not(any(
+        target_os = "emscripten",
+        target_os = "wasi",
+        target_env = "sgx",
+        target_os = "xous"
+    ))
+))]
 mod tests;
 
 use crate::ffi::OsString;
@@ -375,6 +383,45 @@ impl File {
         OpenOptions::new().read(true).open(path.as_ref())
     }
 
+    /// Attempts to open a file in read-only mode with buffering.
+    ///
+    /// See the [`OpenOptions::open`] method, the [`BufReader`][io::BufReader] type,
+    /// and the [`BufRead`][io::BufRead] trait for more details.
+    ///
+    /// If you only need to read the entire file contents,
+    /// consider [`std::fs::read()`][self::read] or
+    /// [`std::fs::read_to_string()`][self::read_to_string] instead.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error if `path` does not already exist,
+    /// or if memory allocation fails for the new buffer.
+    /// Other errors may also be returned according to [`OpenOptions::open`].
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(file_buffered)]
+    /// use std::fs::File;
+    /// use std::io::BufRead;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let mut f = File::open_buffered("foo.txt")?;
+    ///     assert!(f.capacity() > 0);
+    ///     for (line, i) in f.lines().zip(1..) {
+    ///         println!("{i:6}: {}", line?);
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "file_buffered", issue = "130804")]
+    pub fn open_buffered<P: AsRef<Path>>(path: P) -> io::Result<io::BufReader<File>> {
+        // Allocate the buffer *first* so we don't affect the filesystem otherwise.
+        let buffer = io::BufReader::<Self>::try_new_buffer()?;
+        let file = File::open(path)?;
+        Ok(io::BufReader::with_buffer(file, buffer))
+    }
+
     /// Opens a file in write-only mode.
     ///
     /// This function will create a file if it does not exist,
@@ -404,6 +451,45 @@ impl File {
         OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref())
     }
 
+    /// Opens a file in write-only mode with buffering.
+    ///
+    /// This function will create a file if it does not exist,
+    /// and will truncate it if it does.
+    ///
+    /// Depending on the platform, this function may fail if the
+    /// full directory path does not exist.
+    ///
+    /// See the [`OpenOptions::open`] method and the
+    /// [`BufWriter`][io::BufWriter] type for more details.
+    ///
+    /// See also [`std::fs::write()`][self::write] for a simple function to
+    /// create a file with some given data.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(file_buffered)]
+    /// use std::fs::File;
+    /// use std::io::Write;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let mut f = File::create_buffered("foo.txt")?;
+    ///     assert!(f.capacity() > 0);
+    ///     for i in 0..100 {
+    ///         writeln!(&mut f, "{i}")?;
+    ///     }
+    ///     f.flush()?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "file_buffered", issue = "130804")]
+    pub fn create_buffered<P: AsRef<Path>>(path: P) -> io::Result<io::BufWriter<File>> {
+        // Allocate the buffer *first* so we don't affect the filesystem otherwise.
+        let buffer = io::BufWriter::<Self>::try_new_buffer()?;
+        let file = File::create(path)?;
+        Ok(io::BufWriter::with_buffer(file, buffer))
+    }
+
     /// Creates a new file in read-write mode; error if the file exists.
     ///
     /// This function will create a file if it does not exist, or return an error if it does. This
@@ -1991,6 +2077,11 @@ impl AsInner<fs_imp::DirEntry> for DirEntry {
 /// * The file doesn't exist.
 /// * The user lacks permissions to remove the file.
 ///
+/// This function will only ever return an error of kind `NotFound` if the given
+/// path does not exist. Note that the inverse is not true,
+/// ie. if a path does not exist, its removal may fail for a number of reasons,
+/// such as insufficient permissions.
+///
 /// # Examples
 ///
 /// ```no_run
@@ -2448,6 +2539,11 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
 /// * The user lacks permissions to remove the directory at the provided `path`.
 /// * The directory isn't empty.
 ///
+/// This function will only ever return an error of kind `NotFound` if the given
+/// path does not exist. Note that the inverse is not true,
+/// ie. if a path does not exist, its removal may fail for a number of reasons,
+/// such as insufficient permissions.
+///
 /// # Examples
 ///
 /// ```no_run
@@ -2473,16 +2569,15 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
 /// # Platform-specific behavior
 ///
 /// This function currently corresponds to `openat`, `fdopendir`, `unlinkat` and `lstat` functions
-/// on Unix (except for macOS before version 10.10 and REDOX) and the `CreateFileW`,
-/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtCreateFile` functions on
-/// Windows. Note that, this [may change in the future][changes].
+/// on Unix (except for REDOX) and the `CreateFileW`, `GetFileInformationByHandleEx`,
+/// `SetFileInformationByHandle`, and `NtCreateFile` functions on Windows. Note that, this
+/// [may change in the future][changes].
 ///
 /// [changes]: io#platform-specific-behavior
 ///
-/// On macOS before version 10.10 and REDOX, as well as when running in Miri for any target, this
-/// function is not protected against time-of-check to time-of-use (TOCTOU) race conditions, and
-/// should not be used in security-sensitive code on those platforms. All other platforms are
-/// protected.
+/// On REDOX, as well as when running in Miri for any target, this function is not protected against
+/// time-of-check to time-of-use (TOCTOU) race conditions, and should not be used in
+/// security-sensitive code on those platforms. All other platforms are protected.
 ///
 /// # Errors
 ///
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index fb8dd2b0ca1..0672fe6f771 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -11,10 +11,10 @@ use crate::os::unix::fs::symlink as symlink_file;
 #[cfg(unix)]
 use crate::os::unix::fs::symlink as junction_point;
 #[cfg(windows)]
-use crate::os::windows::fs::{junction_point, symlink_dir, symlink_file, OpenOptionsExt};
+use crate::os::windows::fs::{OpenOptionsExt, junction_point, symlink_dir, symlink_file};
 use crate::path::Path;
 use crate::sync::Arc;
-use crate::sys_common::io::test::{tmpdir, TempDir};
+use crate::sys_common::io::test::{TempDir, tmpdir};
 use crate::time::{Duration, Instant, SystemTime};
 use crate::{env, str, thread};
 
@@ -1732,7 +1732,7 @@ fn windows_unix_socket_exists() {
         let bytes = core::slice::from_raw_parts(bytes.as_ptr().cast::<i8>(), bytes.len());
         addr.sun_path[..bytes.len()].copy_from_slice(bytes);
         let len = mem::size_of_val(&addr) as i32;
-        let result = c::bind(socket, ptr::addr_of!(addr).cast::<c::SOCKADDR>(), len);
+        let result = c::bind(socket, (&raw const addr).cast::<c::SOCKADDR>(), len);
         c::closesocket(socket);
         assert_eq!(result, 0);
     }
diff --git a/library/std/src/hash/random.rs b/library/std/src/hash/random.rs
index 8ef45172eac..40f3a90f60c 100644
--- a/library/std/src/hash/random.rs
+++ b/library/std/src/hash/random.rs
@@ -10,7 +10,8 @@
 #[allow(deprecated)]
 use super::{BuildHasher, Hasher, SipHasher13};
 use crate::cell::Cell;
-use crate::{fmt, sys};
+use crate::fmt;
+use crate::sys::random::hashmap_random_keys;
 
 /// `RandomState` is the default state for [`HashMap`] types.
 ///
@@ -65,7 +66,7 @@ impl RandomState {
         // increment one of the seeds on every RandomState creation, giving
         // every corresponding HashMap a different iteration order.
         thread_local!(static KEYS: Cell<(u64, u64)> = {
-            Cell::new(sys::hashmap_random_keys())
+            Cell::new(hashmap_random_keys())
         });
 
         KEYS.with(|keys| {
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 7dcca2707ba..8b46738ab8a 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -4,8 +4,8 @@ use buffer::Buffer;
 
 use crate::fmt;
 use crate::io::{
-    self, uninlined_slow_read_byte, BorrowedCursor, BufRead, IoSliceMut, Read, Seek, SeekFrom,
-    SizeHint, SpecReadByte, DEFAULT_BUF_SIZE,
+    self, BorrowedCursor, BufRead, DEFAULT_BUF_SIZE, IoSliceMut, Read, Seek, SeekFrom, SizeHint,
+    SpecReadByte, uninlined_slow_read_byte,
 };
 
 /// The `BufReader<R>` struct adds buffering to any reader.
@@ -74,6 +74,14 @@ impl<R: Read> BufReader<R> {
         BufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
     }
 
+    pub(crate) fn try_new_buffer() -> io::Result<Buffer> {
+        Buffer::try_with_capacity(DEFAULT_BUF_SIZE)
+    }
+
+    pub(crate) fn with_buffer(inner: R, buf: Buffer) -> Self {
+        Self { inner, buf }
+    }
+
     /// Creates a new `BufReader<R>` with the specified buffer capacity.
     ///
     /// # Examples
@@ -349,7 +357,7 @@ impl<R: ?Sized + Read> Read for BufReader<R> {
         let prev = cursor.written();
 
         let mut rem = self.fill_buf()?;
-        rem.read_buf(cursor.reborrow())?;
+        rem.read_buf(cursor.reborrow())?; // actually never fails
 
         self.consume(cursor.written() - prev); //slice impl of read_buf known to never unfill buf
 
diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs
index 1bf84d8bef3..52fe49985c6 100644
--- a/library/std/src/io/buffered/bufreader/buffer.rs
+++ b/library/std/src/io/buffered/bufreader/buffer.rs
@@ -10,7 +10,7 @@
 //! without encountering any runtime bounds checks.
 
 use crate::cmp;
-use crate::io::{self, BorrowedBuf, Read};
+use crate::io::{self, BorrowedBuf, ErrorKind, Read};
 use crate::mem::MaybeUninit;
 
 pub struct Buffer {
@@ -37,6 +37,16 @@ impl Buffer {
     }
 
     #[inline]
+    pub fn try_with_capacity(capacity: usize) -> io::Result<Self> {
+        match Box::try_new_uninit_slice(capacity) {
+            Ok(buf) => Ok(Self { buf, pos: 0, filled: 0, initialized: 0 }),
+            Err(_) => {
+                Err(io::const_io_error!(ErrorKind::OutOfMemory, "failed to allocate read buffer"))
+            }
+        }
+    }
+
+    #[inline]
     pub fn buffer(&self) -> &[u8] {
         // SAFETY: self.pos and self.cap are valid, and self.cap => self.pos, and
         // that region is initialized because those are all invariants of this type.
@@ -133,11 +143,13 @@ impl Buffer {
                 buf.set_init(self.initialized);
             }
 
-            reader.read_buf(buf.unfilled())?;
+            let result = reader.read_buf(buf.unfilled());
 
             self.pos = 0;
             self.filled = buf.len();
             self.initialized = buf.init_len();
+
+            result?;
         }
         Ok(self.buffer())
     }
diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs
index 21650d46744..c41bae2aa4e 100644
--- a/library/std/src/io/buffered/bufwriter.rs
+++ b/library/std/src/io/buffered/bufwriter.rs
@@ -1,5 +1,5 @@
 use crate::io::{
-    self, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
+    self, DEFAULT_BUF_SIZE, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write,
 };
 use crate::mem::{self, ManuallyDrop};
 use crate::{error, fmt, ptr};
@@ -94,6 +94,16 @@ impl<W: Write> BufWriter<W> {
         BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
     }
 
+    pub(crate) fn try_new_buffer() -> io::Result<Vec<u8>> {
+        Vec::try_with_capacity(DEFAULT_BUF_SIZE).map_err(|_| {
+            io::const_io_error!(ErrorKind::OutOfMemory, "failed to allocate write buffer")
+        })
+    }
+
+    pub(crate) fn with_buffer(inner: W, buf: Vec<u8>) -> Self {
+        Self { inner, buf, panicked: false }
+    }
+
     /// Creates a new `BufWriter<W>` with at least the specified buffer capacity.
     ///
     /// # Examples
diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs
index d89ecd317d6..bff0f823c4b 100644
--- a/library/std/src/io/buffered/tests.rs
+++ b/library/std/src/io/buffered/tests.rs
@@ -164,6 +164,7 @@ fn test_buffered_reader_stream_position() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_buffered_reader_stream_position_panic() {
     let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
     let mut reader = BufReader::with_capacity(4, io::Cursor::new(inner));
@@ -487,7 +488,7 @@ fn dont_panic_in_drop_on_panicked_flush() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn panic_in_write_doesnt_flush_in_drop() {
     static WRITES: AtomicUsize = AtomicUsize::new(0);
 
diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs
index d49866345cb..8d733325b3b 100644
--- a/library/std/src/io/copy.rs
+++ b/library/std/src/io/copy.rs
@@ -1,4 +1,4 @@
-use super::{BorrowedBuf, BufReader, BufWriter, Read, Result, Write, DEFAULT_BUF_SIZE};
+use super::{BorrowedBuf, BufReader, BufWriter, DEFAULT_BUF_SIZE, Read, Result, Write};
 use crate::alloc::Allocator;
 use crate::cmp;
 use crate::collections::VecDeque;
diff --git a/library/std/src/io/copy/tests.rs b/library/std/src/io/copy/tests.rs
index 7e08826a7e1..2e0eb6cdce6 100644
--- a/library/std/src/io/copy/tests.rs
+++ b/library/std/src/io/copy/tests.rs
@@ -122,8 +122,8 @@ mod io_benches {
     use test::Bencher;
 
     use crate::fs::{File, OpenOptions};
-    use crate::io::prelude::*;
     use crate::io::BufReader;
+    use crate::io::prelude::*;
 
     #[bench]
     fn bench_copy_buf_reader(b: &mut Bencher) {
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index 6ecd9469c17..f20814dd95c 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -400,6 +400,11 @@ pub enum ErrorKind {
     #[stable(feature = "out_of_memory_error", since = "1.54.0")]
     OutOfMemory,
 
+    /// The operation was partially successful and needs to be checked
+    /// later on due to not blocking.
+    #[unstable(feature = "io_error_inprogress", issue = "130840")]
+    InProgress,
+
     // "Unusual" error kinds which do not correspond simply to (sets
     // of) OS error codes, should be added just above this comment.
     // `Other` and `Uncategorized` should remain at the end:
@@ -449,6 +454,7 @@ impl ErrorKind {
             FilesystemQuotaExceeded => "filesystem quota exceeded",
             HostUnreachable => "host unreachable",
             Interrupted => "operation interrupted",
+            InProgress => "in progress",
             InvalidData => "invalid data",
             InvalidFilename => "invalid filename",
             InvalidInput => "invalid input parameter",
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
index 9d3ade46bd9..a839a2fbac1 100644
--- a/library/std/src/io/error/repr_bitpacked.rs
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -124,6 +124,7 @@ const TAG_SIMPLE: usize = 0b11;
 /// is_unwind_safe::<std::io::Error>();
 /// ```
 #[repr(transparent)]
+#[rustc_insignificant_dtor]
 pub(super) struct Repr(NonNull<()>, PhantomData<ErrorData<Box<Custom>>>);
 
 // All the types `Repr` stores internally are Send + Sync, and so is it.
@@ -348,6 +349,7 @@ fn kind_from_prim(ek: u32) -> Option<ErrorKind> {
         UnexpectedEof,
         Unsupported,
         OutOfMemory,
+        InProgress,
         Uncategorized,
     })
 }
diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs
index 064e2e36b7a..00d04984a38 100644
--- a/library/std/src/io/error/tests.rs
+++ b/library/std/src/io/error/tests.rs
@@ -1,4 +1,4 @@
-use super::{const_io_error, Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage};
+use super::{Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage, const_io_error};
 use crate::assert_matches::assert_matches;
 use crate::mem::size_of;
 use crate::sys::decode_error_kind;
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 644b294db8d..8fedcb241d0 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -307,9 +307,9 @@ pub(crate) use error::const_io_error;
 pub use self::buffered::WriterPanicked;
 #[unstable(feature = "raw_os_error_ty", issue = "107792")]
 pub use self::error::RawOsError;
-pub(crate) use self::stdio::attempt_print_to_stderr;
 #[stable(feature = "is_terminal", since = "1.70.0")]
 pub use self::stdio::IsTerminal;
+pub(crate) use self::stdio::attempt_print_to_stderr;
 #[unstable(feature = "print_internals", issue = "none")]
 #[doc(hidden)]
 pub use self::stdio::{_eprint, _print};
@@ -322,8 +322,8 @@ pub use self::{
     copy::copy,
     cursor::Cursor,
     error::{Error, ErrorKind, Result},
-    stdio::{stderr, stdin, stdout, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock},
-    util::{empty, repeat, sink, Empty, Repeat, Sink},
+    stdio::{Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, stderr, stdin, stdout},
+    util::{Empty, Repeat, Sink, empty, repeat, sink},
 };
 use crate::mem::take;
 use crate::ops::{Deref, DerefMut};
@@ -398,8 +398,7 @@ where
 // - avoid passing large buffers to readers that always initialize the free capacity if they perform short reads (#23815, #23820)
 // - pass large buffers to readers that do not initialize the spare capacity. this can amortize per-call overheads
 // - and finally pass not-too-small and not-too-large buffers to Windows read APIs because they manage to suffer from both problems
-//   at the same time, i.e. small reads suffer from syscall overhead, all reads incur initialization cost
-//   proportional to buffer size (#110650)
+//   at the same time, i.e. small reads suffer from syscall overhead, all reads incur costs proportional to buffer size (#110650)
 //
 pub(crate) fn default_read_to_end<R: Read + ?Sized>(
     r: &mut R,
@@ -444,6 +443,8 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(
         }
     }
 
+    let mut consecutive_short_reads = 0;
+
     loop {
         if buf.len() == buf.capacity() && buf.capacity() == start_cap {
             // The buffer might be an exact fit. Let's read into a probe buffer
@@ -473,37 +474,50 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(
         }
 
         let mut cursor = read_buf.unfilled();
-        loop {
+        let result = loop {
             match r.read_buf(cursor.reborrow()) {
-                Ok(()) => break,
                 Err(e) if e.is_interrupted() => continue,
-                Err(e) => return Err(e),
+                // Do not stop now in case of error: we might have received both data
+                // and an error
+                res => break res,
             }
-        }
+        };
 
         let unfilled_but_initialized = cursor.init_ref().len();
         let bytes_read = cursor.written();
         let was_fully_initialized = read_buf.init_len() == buf_len;
 
+        // SAFETY: BorrowedBuf's invariants mean this much memory is initialized.
+        unsafe {
+            let new_len = bytes_read + buf.len();
+            buf.set_len(new_len);
+        }
+
+        // Now that all data is pushed to the vector, we can fail without data loss
+        result?;
+
         if bytes_read == 0 {
             return Ok(buf.len() - start_len);
         }
 
+        if bytes_read < buf_len {
+            consecutive_short_reads += 1;
+        } else {
+            consecutive_short_reads = 0;
+        }
+
         // store how much was initialized but not filled
         initialized = unfilled_but_initialized;
 
-        // SAFETY: BorrowedBuf's invariants mean this much memory is initialized.
-        unsafe {
-            let new_len = bytes_read + buf.len();
-            buf.set_len(new_len);
-        }
-
         // Use heuristics to determine the max read size if no initial size hint was provided
         if size_hint.is_none() {
             // The reader is returning short reads but it doesn't call ensure_init().
             // In that case we no longer need to restrict read sizes to avoid
             // initialization costs.
-            if !was_fully_initialized {
+            // When reading from disk we usually don't get any short reads except at EOF.
+            // So we wait for at least 2 short reads before uncapping the read buffer;
+            // this helps with the Windows issue.
+            if !was_fully_initialized && consecutive_short_reads > 1 {
                 max_read_size = usize::MAX;
             }
 
@@ -964,6 +978,8 @@ pub trait Read {
     /// with uninitialized buffers. The new data will be appended to any existing contents of `buf`.
     ///
     /// The default implementation delegates to `read`.
+    ///
+    /// This method makes it possible to return both data and an error but it is advised against.
     #[unstable(feature = "read_buf", issue = "78485")]
     fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> {
         default_read_buf(|b| self.read(b), buf)
@@ -2058,6 +2074,7 @@ pub trait Seek {
 /// It is used by the [`Seek`] trait.
 #[derive(Copy, PartialEq, Eq, Clone, Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "SeekFrom")]
 pub enum SeekFrom {
     /// Sets the offset to the provided number of bytes.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -2365,8 +2382,6 @@ pub trait BufRead: Read {
     /// about Ferris from a binary string, skipping the fun fact:
     ///
     /// ```
-    /// #![feature(bufread_skip_until)]
-    ///
     /// use std::io::{self, BufRead};
     ///
     /// let mut cursor = io::Cursor::new(b"Ferris\0Likes long walks on the beach\0Crustacean\0");
@@ -2390,7 +2405,7 @@ pub trait BufRead: Read {
     /// assert_eq!(num_bytes, 11);
     /// assert_eq!(animal, b"Crustacean\0");
     /// ```
-    #[unstable(feature = "bufread_skip_until", issue = "111735")]
+    #[stable(feature = "bufread_skip_until", since = "CURRENT_RUSTC_VERSION")]
     fn skip_until(&mut self, byte: u8) -> Result<usize> {
         skip_until(self, byte)
     }
@@ -2930,7 +2945,7 @@ impl<T: Read> Read for Take<T> {
             }
 
             let mut cursor = sliced_buf.unfilled();
-            self.inner.read_buf(cursor.reborrow())?;
+            let result = self.inner.read_buf(cursor.reborrow());
 
             let new_init = cursor.init_ref().len();
             let filled = sliced_buf.len();
@@ -2945,13 +2960,14 @@ impl<T: Read> Read for Take<T> {
             }
 
             self.limit -= filled as u64;
+
+            result
         } else {
             let written = buf.written();
-            self.inner.read_buf(buf.reborrow())?;
+            let result = self.inner.read_buf(buf.reborrow());
             self.limit -= (buf.written() - written) as u64;
+            result
         }
-
-        Ok(())
     }
 }
 
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 6de069a518e..35b38ed783f 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -370,7 +370,12 @@ impl Stdin {
     /// Locks this handle and reads a line of input, appending it to the specified buffer.
     ///
     /// For detailed semantics of this method, see the documentation on
-    /// [`BufRead::read_line`].
+    /// [`BufRead::read_line`]. In particular:
+    /// * Previous content of the buffer will be preserved. To avoid appending
+    ///   to the buffer, you need to [`clear`] it first.
+    /// * The trailing newline character, if any, is included in the buffer.
+    ///
+    /// [`clear`]: String::clear
     ///
     /// # Examples
     ///
@@ -394,6 +399,7 @@ impl Stdin {
     ///   in which case it will wait for the Enter key to be pressed before
     ///   continuing
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("get_line")]
     pub fn read_line(&self, buf: &mut String) -> io::Result<usize> {
         self.lock().read_line(buf)
     }
diff --git a/library/std/src/io/stdio/tests.rs b/library/std/src/io/stdio/tests.rs
index f89fd27ce6c..bf8f3a5adfb 100644
--- a/library/std/src/io/stdio/tests.rs
+++ b/library/std/src/io/stdio/tests.rs
@@ -25,7 +25,7 @@ fn stderrlock_unwind_safe() {
 fn assert_unwind_safe<T: UnwindSafe + RefUnwindSafe>() {}
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn panic_doesnt_poison() {
     thread::spawn(|| {
         let _a = stdin();
@@ -48,17 +48,17 @@ fn panic_doesnt_poison() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn test_lock_stderr() {
     test_lock(stderr, || stderr().lock());
 }
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn test_lock_stdin() {
     test_lock(stdin, || stdin().lock());
 }
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn test_lock_stdout() {
     test_lock(stdout, || stdout().lock());
 }
@@ -159,8 +159,7 @@ where
     assert_eq!(rx2.recv().unwrap(), Release2); // release th2
     th2.join().unwrap();
     th1.join().unwrap();
-    assert_eq!(
-        *log.lock().unwrap(),
-        [Start1, Acquire1, Start2, Release1, Acquire2, Release2, Acquire1, Release1]
-    );
+    assert_eq!(*log.lock().unwrap(), [
+        Start1, Acquire1, Start2, Release1, Acquire2, Release2, Acquire1, Release1
+    ]);
 }
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index 24e5a1dfd5c..56b71c47dc7 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -1,7 +1,7 @@
-use super::{repeat, BorrowedBuf, Cursor, SeekFrom};
+use super::{BorrowedBuf, Cursor, SeekFrom, repeat};
 use crate::cmp::{self, min};
 use crate::io::{
-    self, BufRead, BufReader, IoSlice, IoSliceMut, Read, Seek, Write, DEFAULT_BUF_SIZE,
+    self, BufRead, BufReader, DEFAULT_BUF_SIZE, IoSlice, IoSliceMut, Read, Seek, Write,
 };
 use crate::mem::MaybeUninit;
 use crate::ops::Deref;
@@ -735,6 +735,69 @@ fn read_buf_full_read() {
     assert_eq!(BufReader::new(FullRead).fill_buf().unwrap().len(), DEFAULT_BUF_SIZE);
 }
 
+struct DataAndErrorReader(&'static [u8]);
+
+impl Read for DataAndErrorReader {
+    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
+        panic!("We want tests to use `read_buf`")
+    }
+
+    fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> {
+        self.0.read_buf(buf).unwrap();
+        Err(io::Error::other("error"))
+    }
+}
+
+#[test]
+fn read_buf_data_and_error_take() {
+    let mut buf = [0; 64];
+    let mut buf = io::BorrowedBuf::from(buf.as_mut_slice());
+
+    let mut r = DataAndErrorReader(&[4, 5, 6]).take(1);
+    assert!(r.read_buf(buf.unfilled()).is_err());
+    assert_eq!(buf.filled(), &[4]);
+
+    assert!(r.read_buf(buf.unfilled()).is_ok());
+    assert_eq!(buf.filled(), &[4]);
+    assert_eq!(r.get_ref().0, &[5, 6]);
+}
+
+#[test]
+fn read_buf_data_and_error_buf() {
+    let mut r = BufReader::new(DataAndErrorReader(&[4, 5, 6]));
+
+    assert!(r.fill_buf().is_err());
+    assert_eq!(r.fill_buf().unwrap(), &[4, 5, 6]);
+}
+
+#[test]
+fn read_buf_data_and_error_read_to_end() {
+    let mut r = DataAndErrorReader(&[4, 5, 6]);
+
+    let mut v = Vec::with_capacity(200);
+    assert!(r.read_to_end(&mut v).is_err());
+
+    assert_eq!(v, &[4, 5, 6]);
+}
+
+#[test]
+fn read_to_end_error() {
+    struct ErrorReader;
+
+    impl Read for ErrorReader {
+        fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
+            Err(io::Error::other("error"))
+        }
+    }
+
+    let mut r = [4, 5, 6].chain(ErrorReader);
+
+    let mut v = Vec::with_capacity(200);
+    assert!(r.read_to_end(&mut v).is_err());
+
+    assert_eq!(v, &[4, 5, 6]);
+}
+
 #[test]
 // Miri does not support signalling OOM
 #[cfg_attr(miri, ignore)]
diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs
index 1dff3f3832b..0599a881af1 100644
--- a/library/std/src/io/util/tests.rs
+++ b/library/std/src/io/util/tests.rs
@@ -1,5 +1,5 @@
 use crate::io::prelude::*;
-use crate::io::{empty, repeat, sink, BorrowedBuf, Empty, Repeat, SeekFrom, Sink};
+use crate::io::{BorrowedBuf, Empty, Repeat, SeekFrom, Sink, empty, repeat, sink};
 use crate::mem::MaybeUninit;
 
 #[test]
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index 9f4d244b547..453b2708daa 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -2349,12 +2349,13 @@ mod async_keyword {}
 /// [`async`]: ../std/keyword.async.html
 mod await_keyword {}
 
+// FIXME(dyn_compat_renaming): Update URL and link text.
 #[doc(keyword = "dyn")]
 //
 /// `dyn` is a prefix of a [trait object]'s type.
 ///
 /// The `dyn` keyword is used to highlight that calls to methods on the associated `Trait`
-/// are [dynamically dispatched]. To use the trait this way, it must be 'object safe'.
+/// are [dynamically dispatched]. To use the trait this way, it must be 'dyn-compatible'[^1].
 ///
 /// Unlike generic parameters or `impl Trait`, the compiler does not know the concrete type that
 /// is being passed. That is, the type has been [erased].
@@ -2382,6 +2383,7 @@ mod await_keyword {}
 /// [ref-trait-obj]: ../reference/types/trait-object.html
 /// [ref-obj-safety]: ../reference/items/traits.html#object-safety
 /// [erased]: https://en.wikipedia.org/wiki/Type_erasure
+/// [^1]: Formerly known as 'object safe'.
 mod dyn_keyword {}
 
 #[doc(keyword = "union")]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index e4ba5e47613..65a9aa66c7c 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -32,13 +32,17 @@
 //!
 //! Once you are familiar with the contents of the standard library you may
 //! begin to find the verbosity of the prose distracting. At this stage in your
-//! development you may want to press the `[-]` button near the top of the
-//! page to collapse it into a more skimmable view.
-//!
-//! While you are looking at that `[-]` button also notice the `source`
-//! link. Rust's API documentation comes with the source code and you are
-//! encouraged to read it. The standard library source is generally high
-//! quality and a peek behind the curtains is often enlightening.
+//! development you may want to press the <code>
+//! <svg style="width:0.75rem;height:0.75rem" viewBox="0 0 12 12"
+//! stroke="currentColor" fill="none">
+//! <path d="M2,2l4,4l4,-4M2,6l4,4l4,-4"/></svg> Summary</code> button near the
+//! top of the page to collapse it into a more skimmable view.
+//!
+//! While you are looking at the top of the page, also notice the
+//! <code>source</code> link. Rust's API documentation comes with the source
+//! code and you are encouraged to read it. The standard library source is
+//! generally high quality and a peek behind the curtains is
+//! often enlightening.
 //!
 //! # What is in the standard library documentation?
 //!
@@ -149,7 +153,7 @@
 //! the [`io`], [`fs`], and [`net`] modules.
 //!
 //! The [`thread`] module contains Rust's threading abstractions. [`sync`]
-//! contains further primitive shared memory types, including [`atomic`] and
+//! contains further primitive shared memory types, including [`atomic`], [`mpmc`] and
 //! [`mpsc`], which contains the channel types for message passing.
 //!
 //! # Use before and after `main()`
@@ -173,6 +177,7 @@
 //! - after-main use of thread-locals, which also affects additional features:
 //!   - [`thread::current()`]
 //!   - [`thread::scope()`]
+//!   - [`sync::mpmc`]
 //!   - [`sync::mpsc`]
 //! - before-main stdio file descriptors are not guaranteed to be open on unix platforms
 //!
@@ -198,6 +203,7 @@
 //! [`atomic`]: sync::atomic
 //! [`for`]: ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for
 //! [`str`]: prim@str
+//! [`mpmc`]: sync::mpmc
 //! [`mpsc`]: sync::mpsc
 //! [`std::cmp`]: cmp
 //! [`std::slice`]: mod@slice
@@ -318,6 +324,7 @@
 //
 // Library features (core):
 // tidy-alphabetical-start
+#![feature(array_chunks)]
 #![feature(c_str_module)]
 #![feature(char_internals)]
 #![feature(clone_to_uninit)]
@@ -348,6 +355,7 @@
 #![feature(prelude_2024)]
 #![feature(ptr_as_uninit)]
 #![feature(ptr_mask)]
+#![feature(random)]
 #![feature(slice_internals)]
 #![feature(slice_ptr_get)]
 #![feature(slice_range)]
@@ -368,6 +376,7 @@
 #![feature(slice_concat_trait)]
 #![feature(thin_box)]
 #![feature(try_reserve_kind)]
+#![feature(try_with_capacity)]
 #![feature(vec_into_raw_parts)]
 // tidy-alphabetical-end
 //
@@ -493,9 +502,9 @@ pub use core::default;
 pub use core::future;
 #[stable(feature = "core_hint", since = "1.27.0")]
 pub use core::hint;
-#[stable(feature = "i128", since = "1.26.0")]
+#[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated, deprecated_in_future)]
-pub use core::i128;
+pub use core::i8;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated, deprecated_in_future)]
 pub use core::i16;
@@ -505,9 +514,9 @@ pub use core::i32;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated, deprecated_in_future)]
 pub use core::i64;
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "i128", since = "1.26.0")]
 #[allow(deprecated, deprecated_in_future)]
-pub use core::i8;
+pub use core::i128;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::intrinsics;
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -529,9 +538,9 @@ pub use core::pin;
 pub use core::ptr;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::result;
-#[stable(feature = "i128", since = "1.26.0")]
+#[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated, deprecated_in_future)]
-pub use core::u128;
+pub use core::u8;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated, deprecated_in_future)]
 pub use core::u16;
@@ -541,9 +550,9 @@ pub use core::u32;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated, deprecated_in_future)]
 pub use core::u64;
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "i128", since = "1.26.0")]
 #[allow(deprecated, deprecated_in_future)]
-pub use core::u8;
+pub use core::u128;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated, deprecated_in_future)]
 pub use core::usize;
@@ -595,6 +604,8 @@ pub mod path;
 #[unstable(feature = "anonymous_pipe", issue = "127154")]
 pub mod pipe;
 pub mod process;
+#[unstable(feature = "random", issue = "130703")]
+pub mod random;
 pub mod sync;
 pub mod time;
 
@@ -649,9 +660,9 @@ pub mod arch {
     #[stable(feature = "simd_x86", since = "1.27.0")]
     pub use std_detect::is_x86_feature_detected;
     #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")]
-    pub use std_detect::{is_mips64_feature_detected, is_mips_feature_detected};
+    pub use std_detect::{is_mips_feature_detected, is_mips64_feature_detected};
     #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")]
-    pub use std_detect::{is_powerpc64_feature_detected, is_powerpc_feature_detected};
+    pub use std_detect::{is_powerpc_feature_detected, is_powerpc64_feature_detected};
 }
 
 // This was stabilized in the crate root so we have to keep it there.
diff --git a/library/std/src/net/ip_addr.rs b/library/std/src/net/ip_addr.rs
index 8a9426b61f9..4d673a1d66d 100644
--- a/library/std/src/net/ip_addr.rs
+++ b/library/std/src/net/ip_addr.rs
@@ -1,5 +1,5 @@
 // Tests for this module
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", all(target_os = "wasi", target_env = "p1")))))]
 mod tests;
 
 #[stable(feature = "ip_addr", since = "1.7.0")]
diff --git a/library/std/src/net/ip_addr/tests.rs b/library/std/src/net/ip_addr/tests.rs
index ab99c0c2fcc..7bed6f8a0f5 100644
--- a/library/std/src/net/ip_addr/tests.rs
+++ b/library/std/src/net/ip_addr/tests.rs
@@ -1,5 +1,5 @@
-use crate::net::test::{sa4, tsa};
 use crate::net::Ipv4Addr;
+use crate::net::test::{sa4, tsa};
 
 #[test]
 fn to_socket_addr_socketaddr() {
diff --git a/library/std/src/net/socket_addr.rs b/library/std/src/net/socket_addr.rs
index 84922aabdb5..ba9c948a2e9 100644
--- a/library/std/src/net/socket_addr.rs
+++ b/library/std/src/net/socket_addr.rs
@@ -1,5 +1,5 @@
 // Tests for this module
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", all(target_os = "wasi", target_env = "p1")))))]
 mod tests;
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs
index 22d2dfe65a2..67a0f7e439d 100644
--- a/library/std/src/net/tcp.rs
+++ b/library/std/src/net/tcp.rs
@@ -1,6 +1,13 @@
 #![deny(unsafe_op_in_unsafe_fn)]
 
-#[cfg(all(test, not(any(target_os = "emscripten", target_os = "xous"))))]
+#[cfg(all(
+    test,
+    not(any(
+        target_os = "emscripten",
+        all(target_os = "wasi", target_env = "p1"),
+        target_os = "xous"
+    ))
+))]
 mod tests;
 
 use crate::fmt;
@@ -8,7 +15,7 @@ use crate::io::prelude::*;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::iter::FusedIterator;
 use crate::net::{Shutdown, SocketAddr, ToSocketAddrs};
-use crate::sys_common::{net as net_imp, AsInner, FromInner, IntoInner};
+use crate::sys_common::{AsInner, FromInner, IntoInner, net as net_imp};
 use crate::time::Duration;
 
 /// A TCP stream between a local and a remote socket.
@@ -561,7 +568,7 @@ impl TcpStream {
 
     /// Moves this TCP stream into or out of nonblocking mode.
     ///
-    /// This will result in `read`, `write`, `recv` and `send` operations
+    /// This will result in `read`, `write`, `recv` and `send` system operations
     /// becoming nonblocking, i.e., immediately returning from their calls.
     /// If the IO operation is successful, `Ok` is returned and no further
     /// action is required. If the IO operation could not be completed and needs
diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs
index d26517d74e4..a7b5cdf4ec0 100644
--- a/library/std/src/net/tcp/tests.rs
+++ b/library/std/src/net/tcp/tests.rs
@@ -57,6 +57,7 @@ fn connect_timeout_error() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn listen_localhost() {
     let socket_addr = next_test_ip4();
     let listener = t!(TcpListener::bind(&socket_addr));
@@ -73,6 +74,7 @@ fn listen_localhost() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn connect_loopback() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -94,6 +96,7 @@ fn connect_loopback() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn smoke_test() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -114,6 +117,7 @@ fn smoke_test() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn read_eof() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -133,6 +137,7 @@ fn read_eof() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn write_close() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -161,6 +166,7 @@ fn write_close() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn multiple_connect_serial() {
     each_ip(&mut |addr| {
         let max = 10;
@@ -183,6 +189,7 @@ fn multiple_connect_serial() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn multiple_connect_interleaved_greedy_schedule() {
     const MAX: usize = 10;
     each_ip(&mut |addr| {
@@ -220,6 +227,7 @@ fn multiple_connect_interleaved_greedy_schedule() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn multiple_connect_interleaved_lazy_schedule() {
     const MAX: usize = 10;
     each_ip(&mut |addr| {
@@ -255,6 +263,7 @@ fn multiple_connect_interleaved_lazy_schedule() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn socket_and_peer_name() {
     each_ip(&mut |addr| {
         let listener = t!(TcpListener::bind(&addr));
@@ -270,6 +279,7 @@ fn socket_and_peer_name() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn partial_read() {
     each_ip(&mut |addr| {
         let (tx, rx) = channel();
@@ -291,6 +301,7 @@ fn partial_read() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn read_buf() {
     each_ip(&mut |addr| {
         let srv = t!(TcpListener::bind(&addr));
@@ -389,6 +400,7 @@ fn double_bind() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn tcp_clone_smoke() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -420,6 +432,7 @@ fn tcp_clone_smoke() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn tcp_clone_two_read() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -454,6 +467,7 @@ fn tcp_clone_two_read() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn tcp_clone_two_write() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -483,6 +497,7 @@ fn tcp_clone_two_write() {
 #[test]
 // FIXME: https://github.com/fortanix/rust-sgx/issues/110
 #[cfg_attr(target_env = "sgx", ignore)]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn shutdown_smoke() {
     each_ip(&mut |addr| {
         let a = t!(TcpListener::bind(&addr));
@@ -505,6 +520,7 @@ fn shutdown_smoke() {
 #[test]
 // FIXME: https://github.com/fortanix/rust-sgx/issues/110
 #[cfg_attr(target_env = "sgx", ignore)]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn close_readwrite_smoke() {
     each_ip(&mut |addr| {
         let a = t!(TcpListener::bind(&addr));
@@ -547,6 +563,7 @@ fn close_readwrite_smoke() {
 #[cfg_attr(target_env = "sgx", ignore)]
 // On windows, shutdown will not wake up blocking I/O operations.
 #[cfg_attr(windows, ignore)]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn close_read_wakes_up() {
     each_ip(&mut |addr| {
         let listener = t!(TcpListener::bind(&addr));
@@ -574,6 +591,7 @@ fn close_read_wakes_up() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn clone_while_reading() {
     each_ip(&mut |addr| {
         let accept = t!(TcpListener::bind(&addr));
@@ -614,6 +632,7 @@ fn clone_while_reading() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn clone_accept_smoke() {
     each_ip(&mut |addr| {
         let a = t!(TcpListener::bind(&addr));
@@ -632,6 +651,7 @@ fn clone_accept_smoke() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn clone_accept_concurrent() {
     each_ip(&mut |addr| {
         let a = t!(TcpListener::bind(&addr));
@@ -670,10 +690,10 @@ fn debug() {
         addr.to_string()
     }
 
+    #[cfg(any(unix, target_os = "wasi"))]
+    use crate::os::fd::AsRawFd;
     #[cfg(target_env = "sgx")]
     use crate::os::fortanix_sgx::io::AsRawFd;
-    #[cfg(unix)]
-    use crate::os::unix::io::AsRawFd;
     #[cfg(not(windows))]
     fn render_inner(addr: &dyn AsRawFd) -> impl fmt::Debug {
         addr.as_raw_fd()
@@ -714,6 +734,7 @@ fn debug() {
     ignore
 )]
 #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 #[test]
 fn timeouts() {
     let addr = next_test_ip4();
@@ -742,6 +763,7 @@ fn timeouts() {
 
 #[test]
 #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 fn test_read_timeout() {
     let addr = next_test_ip4();
     let listener = t!(TcpListener::bind(&addr));
@@ -763,6 +785,7 @@ fn test_read_timeout() {
 
 #[test]
 #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 fn test_read_with_timeout() {
     let addr = next_test_ip4();
     let listener = t!(TcpListener::bind(&addr));
@@ -810,6 +833,7 @@ fn test_timeout_zero_duration() {
 
 #[test]
 #[cfg_attr(target_env = "sgx", ignore)]
+#[cfg_attr(target_os = "wasi", ignore)] // linger not supported
 fn linger() {
     let addr = next_test_ip4();
     let _listener = t!(TcpListener::bind(&addr));
@@ -879,6 +903,7 @@ fn set_nonblocking() {
 
 #[test]
 #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn peek() {
     each_ip(&mut |addr| {
         let (txdone, rxdone) = channel();
diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs
index 32e9086003d..6df47d7b0e0 100644
--- a/library/std/src/net/udp.rs
+++ b/library/std/src/net/udp.rs
@@ -1,10 +1,18 @@
-#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx", target_os = "xous"))))]
+#[cfg(all(
+    test,
+    not(any(
+        target_os = "emscripten",
+        all(target_os = "wasi", target_env = "p1"),
+        target_env = "sgx",
+        target_os = "xous"
+    ))
+))]
 mod tests;
 
 use crate::fmt;
 use crate::io::{self, ErrorKind};
 use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
-use crate::sys_common::{net as net_imp, AsInner, FromInner, IntoInner};
+use crate::sys_common::{AsInner, FromInner, IntoInner, net as net_imp};
 use crate::time::Duration;
 
 /// A UDP socket.
@@ -579,8 +587,8 @@ impl UdpSocket {
     /// This function specifies a new multicast group for this socket to join.
     /// The address must be a valid multicast address, and `interface` is the
     /// address of the local interface with which the system should join the
-    /// multicast group. If it's equal to `INADDR_ANY` then an appropriate
-    /// interface is chosen by the system.
+    /// multicast group. If it's equal to [`UNSPECIFIED`](Ipv4Addr::UNSPECIFIED)
+    /// then an appropriate interface is chosen by the system.
     #[stable(feature = "net2_mutators", since = "1.9.0")]
     pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
         self.0.join_multicast_v4(multiaddr, interface)
@@ -764,7 +772,7 @@ impl UdpSocket {
 
     /// Moves this UDP socket into or out of nonblocking mode.
     ///
-    /// This will result in `recv`, `recv_from`, `send`, and `send_to`
+    /// This will result in `recv`, `recv_from`, `send`, and `send_to` system
     /// operations becoming nonblocking, i.e., immediately returning from their
     /// calls. If the IO operation is successful, `Ok` is returned and no
     /// further action is required. If the IO operation could not be completed
diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs
index 0cf99366452..1c8c58d1879 100644
--- a/library/std/src/net/udp/tests.rs
+++ b/library/std/src/net/udp/tests.rs
@@ -27,6 +27,7 @@ fn bind_error() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn socket_smoke_test_ip4() {
     each_ip(&mut |server_ip, client_ip| {
         let (tx1, rx1) = channel();
@@ -69,6 +70,7 @@ fn socket_peer() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn udp_clone_smoke() {
     each_ip(&mut |addr1, addr2| {
         let sock1 = t!(UdpSocket::bind(&addr1));
@@ -98,6 +100,7 @@ fn udp_clone_smoke() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn udp_clone_two_read() {
     each_ip(&mut |addr1, addr2| {
         let sock1 = t!(UdpSocket::bind(&addr1));
@@ -130,6 +133,7 @@ fn udp_clone_two_read() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn udp_clone_two_write() {
     each_ip(&mut |addr1, addr2| {
         let sock1 = t!(UdpSocket::bind(&addr1));
@@ -183,6 +187,7 @@ fn debug() {
     any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks", target_os = "nto"),
     ignore
 )]
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 #[test]
 fn timeouts() {
     let addr = next_test_ip4();
@@ -208,6 +213,7 @@ fn timeouts() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 fn test_read_timeout() {
     let addr = next_test_ip4();
 
@@ -232,6 +238,7 @@ fn test_read_timeout() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 fn test_read_with_timeout() {
     let addr = next_test_ip4();
 
@@ -291,6 +298,7 @@ fn connect_send_recv() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // peek not supported
 fn connect_send_peek_recv() {
     each_ip(&mut |addr, _| {
         let socket = t!(UdpSocket::bind(&addr));
@@ -313,6 +321,7 @@ fn connect_send_peek_recv() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // peek_from not supported
 fn peek_from() {
     each_ip(&mut |addr, _| {
         let socket = t!(UdpSocket::bind(&addr));
diff --git a/library/std/src/num.rs b/library/std/src/num.rs
index c1e6e7e628c..d2f679e7dde 100644
--- a/library/std/src/num.rs
+++ b/library/std/src/num.rs
@@ -26,9 +26,9 @@ pub use core::num::ZeroablePrimitive;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::num::{FpCategory, ParseFloatError, ParseIntError, TryFromIntError};
 #[stable(feature = "signed_nonzero", since = "1.34.0")]
-pub use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
+pub use core::num::{NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize};
 #[stable(feature = "nonzero", since = "1.28.0")]
-pub use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
+pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize};
 
 #[cfg(test)]
 use crate::fmt;
diff --git a/library/std/src/os/fortanix_sgx/mod.rs b/library/std/src/os/fortanix_sgx/mod.rs
index 64f4d97ca95..2b5ccbe98f1 100644
--- a/library/std/src/os/fortanix_sgx/mod.rs
+++ b/library/std/src/os/fortanix_sgx/mod.rs
@@ -22,12 +22,12 @@ pub mod usercalls {
     /// Lowest-level interfaces to usercalls and usercall ABI type definitions.
     pub mod raw {
         pub use crate::sys::abi::usercalls::raw::{
-            accept_stream, alloc, async_queues, bind_stream, close, connect_stream, do_usercall,
-            exit, flush, free, insecure_time, launch_thread, read, read_alloc, send, wait, write,
-            ByteBuffer, Cancel, Error, Fd, FifoDescriptor, Register, RegisterArgument, Result,
-            Return, ReturnValue, Tcs, Usercall, Usercalls as UsercallNrs, EV_RETURNQ_NOT_EMPTY,
-            EV_UNPARK, EV_USERCALLQ_NOT_FULL, FD_STDERR, FD_STDIN, FD_STDOUT, RESULT_SUCCESS,
-            USERCALL_USER_DEFINED, WAIT_INDEFINITE, WAIT_NO,
+            ByteBuffer, Cancel, EV_RETURNQ_NOT_EMPTY, EV_UNPARK, EV_USERCALLQ_NOT_FULL, Error,
+            FD_STDERR, FD_STDIN, FD_STDOUT, Fd, FifoDescriptor, RESULT_SUCCESS, Register,
+            RegisterArgument, Result, Return, ReturnValue, Tcs, USERCALL_USER_DEFINED, Usercall,
+            Usercalls as UsercallNrs, WAIT_INDEFINITE, WAIT_NO, accept_stream, alloc, async_queues,
+            bind_stream, close, connect_stream, do_usercall, exit, flush, free, insecure_time,
+            launch_thread, read, read_alloc, send, wait, write,
         };
     }
 }
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index a2496baa63f..6701173d1e0 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -139,6 +139,8 @@ pub mod macos;
 pub mod netbsd;
 #[cfg(target_os = "nto")]
 pub mod nto;
+#[cfg(target_os = "nuttx")]
+pub mod nuttx;
 #[cfg(target_os = "openbsd")]
 pub mod openbsd;
 #[cfg(target_os = "redox")]
diff --git a/library/std/src/os/nuttx/fs.rs b/library/std/src/os/nuttx/fs.rs
new file mode 100644
index 00000000000..7d6d8d16eca
--- /dev/null
+++ b/library/std/src/os/nuttx/fs.rs
@@ -0,0 +1,92 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_dev(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ino(&self) -> u64;
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn st_mode(&self) -> u32;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_nlink(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_uid(&self) -> u32;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_gid(&self) -> u32;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_rdev(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_size(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_atime(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_atime_nsec(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mtime(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mtime_nsec(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ctime(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ctime_nsec(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_blksize(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+    fn st_dev(&self) -> u64 {
+        self.as_inner().as_inner().st_dev as u64
+    }
+    fn st_ino(&self) -> u64 {
+        self.as_inner().as_inner().st_ino as u64
+    }
+    fn st_mode(&self) -> u32 {
+        self.as_inner().as_inner().st_mode as u32
+    }
+    fn st_nlink(&self) -> u64 {
+        self.as_inner().as_inner().st_nlink as u64
+    }
+    fn st_uid(&self) -> u32 {
+        self.as_inner().as_inner().st_uid as u32
+    }
+    fn st_gid(&self) -> u32 {
+        self.as_inner().as_inner().st_gid as u32
+    }
+    fn st_rdev(&self) -> u64 {
+        self.as_inner().as_inner().st_rdev as u64
+    }
+    fn st_size(&self) -> u64 {
+        self.as_inner().as_inner().st_size as u64
+    }
+    fn st_atime(&self) -> i64 {
+        self.as_inner().as_inner().st_atim.tv_sec as i64
+    }
+    fn st_atime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_atim.tv_nsec as i64
+    }
+    fn st_mtime(&self) -> i64 {
+        self.as_inner().as_inner().st_mtim.tv_sec as i64
+    }
+    fn st_mtime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_mtim.tv_nsec as i64
+    }
+    fn st_ctime(&self) -> i64 {
+        self.as_inner().as_inner().st_ctim.tv_sec as i64
+    }
+    fn st_ctime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_ctim.tv_nsec as i64
+    }
+    fn st_blksize(&self) -> u64 {
+        self.as_inner().as_inner().st_blksize as u64
+    }
+    fn st_blocks(&self) -> u64 {
+        self.as_inner().as_inner().st_blocks as u64
+    }
+}
diff --git a/library/std/src/os/nuttx/mod.rs b/library/std/src/os/nuttx/mod.rs
new file mode 100644
index 00000000000..7275bfd1765
--- /dev/null
+++ b/library/std/src/os/nuttx/mod.rs
@@ -0,0 +1,4 @@
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![forbid(unsafe_op_in_unsafe_fn)]
+pub mod fs;
+pub(crate) mod raw;
diff --git a/library/std/src/os/nuttx/raw.rs b/library/std/src/os/nuttx/raw.rs
new file mode 100644
index 00000000000..113079cf4ab
--- /dev/null
+++ b/library/std/src/os/nuttx/raw.rs
@@ -0,0 +1,33 @@
+//! rtems raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+    since = "1.8.0",
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
+)]
+#![allow(deprecated)]
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = libc::pthread_t;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = libc::blkcnt_t;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = libc::blksize_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = libc::dev_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = libc::ino_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = libc::mode_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = libc::nlink_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = libc::off_t;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = libc::time_t;
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
index 7d2f0bd4efe..5c2ec8ef994 100644
--- a/library/std/src/os/unix/mod.rs
+++ b/library/std/src/os/unix/mod.rs
@@ -69,6 +69,8 @@ mod platform {
     pub use crate::os::netbsd::*;
     #[cfg(target_os = "nto")]
     pub use crate::os::nto::*;
+    #[cfg(target_os = "nuttx")]
+    pub use crate::os::nuttx::*;
     #[cfg(target_os = "openbsd")]
     pub use crate::os::openbsd::*;
     #[cfg(target_os = "redox")]
diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs
index 79f2c365025..253e1503cf7 100644
--- a/library/std/src/os/unix/net/addr.rs
+++ b/library/std/src/os/unix/net/addr.rs
@@ -15,15 +15,12 @@ mod libc {
     pub type socklen_t = u32;
     pub struct sockaddr;
     #[derive(Clone)]
-    pub struct sockaddr_un;
+    pub struct sockaddr_un {
+        pub sun_path: [u8; 1],
+    }
 }
 
-fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
-    // Work with an actual instance of the type since using a null pointer is UB
-    let base = (addr as *const libc::sockaddr_un).addr();
-    let path = core::ptr::addr_of!(addr.sun_path).addr();
-    path - base
-}
+const SUN_PATH_OFFSET: usize = mem::offset_of!(libc::sockaddr_un, sun_path);
 
 pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
     // SAFETY: All zeros is a valid representation for `sockaddr_un`.
@@ -53,7 +50,7 @@ pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::s
         ptr::copy_nonoverlapping(bytes.as_ptr(), addr.sun_path.as_mut_ptr().cast(), bytes.len())
     };
 
-    let mut len = sun_path_offset(&addr) + bytes.len();
+    let mut len = SUN_PATH_OFFSET + bytes.len();
     match bytes.get(0) {
         Some(&0) | None => {}
         Some(_) => len += 1,
@@ -98,7 +95,7 @@ impl SocketAddr {
         unsafe {
             let mut addr: libc::sockaddr_un = mem::zeroed();
             let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t;
-            cvt(f(core::ptr::addr_of_mut!(addr) as *mut _, &mut len))?;
+            cvt(f((&raw mut addr) as *mut _, &mut len))?;
             SocketAddr::from_parts(addr, len)
         }
     }
@@ -114,13 +111,13 @@ impl SocketAddr {
             let sun_path: &[u8] =
                 unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&addr.sun_path) };
             len = core::slice::memchr::memchr(0, sun_path)
-                .map_or(len, |new_len| (new_len + sun_path_offset(&addr)) as libc::socklen_t);
+                .map_or(len, |new_len| (new_len + SUN_PATH_OFFSET) as libc::socklen_t);
         }
 
         if len == 0 {
             // When there is a datagram from unnamed unix socket
             // linux returns zero bytes of address
-            len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address
+            len = SUN_PATH_OFFSET as libc::socklen_t; // i.e., zero-length address
         } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
             return Err(io::const_io_error!(
                 io::ErrorKind::InvalidInput,
@@ -238,7 +235,7 @@ impl SocketAddr {
     }
 
     fn address(&self) -> AddressKind<'_> {
-        let len = self.len as usize - sun_path_offset(&self.addr);
+        let len = self.len as usize - SUN_PATH_OFFSET;
         let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
 
         // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
@@ -287,7 +284,7 @@ impl linux_ext::addr::SocketAddrExt for SocketAddr {
                 addr.sun_path.as_mut_ptr().add(1) as *mut u8,
                 name.len(),
             );
-            let len = (sun_path_offset(&addr) + 1 + name.len()) as libc::socklen_t;
+            let len = (SUN_PATH_OFFSET + 1 + name.len()) as libc::socklen_t;
             SocketAddr::from_parts(addr, len)
         }
     }
diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs
index 9b487a62982..36967fc3f98 100644
--- a/library/std/src/os/unix/net/ancillary.rs
+++ b/library/std/src/os/unix/net/ancillary.rs
@@ -1,6 +1,6 @@
 // FIXME: This is currently disabled on *BSD.
 
-use super::{sockaddr_un, SocketAddr};
+use super::{SocketAddr, sockaddr_un};
 use crate::io::{self, IoSlice, IoSliceMut};
 use crate::marker::PhantomData;
 use crate::mem::zeroed;
@@ -37,7 +37,7 @@ pub(super) fn recv_vectored_with_ancillary_from(
     unsafe {
         let mut msg_name: libc::sockaddr_un = zeroed();
         let mut msg: libc::msghdr = zeroed();
-        msg.msg_name = core::ptr::addr_of_mut!(msg_name) as *mut _;
+        msg.msg_name = (&raw mut msg_name) as *mut _;
         msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::socklen_t;
         msg.msg_iov = bufs.as_mut_ptr().cast();
         msg.msg_iovlen = bufs.len() as _;
@@ -70,7 +70,7 @@ pub(super) fn send_vectored_with_ancillary_to(
             if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) };
 
         let mut msg: libc::msghdr = zeroed();
-        msg.msg_name = core::ptr::addr_of_mut!(msg_name) as *mut _;
+        msg.msg_name = (&raw mut msg_name) as *mut _;
         msg.msg_namelen = msg_namelen;
         msg.msg_iov = bufs.as_ptr() as *mut _;
         msg.msg_iovlen = bufs.len() as _;
diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs
index a605c3d4a26..82446ea107f 100644
--- a/library/std/src/os/unix/net/datagram.rs
+++ b/library/std/src/os/unix/net/datagram.rs
@@ -12,9 +12,9 @@
 ))]
 use libc::MSG_NOSIGNAL;
 
+use super::{SocketAddr, sockaddr_un};
 #[cfg(any(doc, target_os = "android", target_os = "linux"))]
-use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary};
-use super::{sockaddr_un, SocketAddr};
+use super::{SocketAncillary, recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to};
 #[cfg(any(doc, target_os = "android", target_os = "linux"))]
 use crate::io::{IoSlice, IoSliceMut};
 use crate::net::Shutdown;
@@ -100,7 +100,7 @@ impl UnixDatagram {
             let socket = UnixDatagram::unbound()?;
             let (addr, len) = sockaddr_un(path.as_ref())?;
 
-            cvt(libc::bind(socket.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len as _))?;
+            cvt(libc::bind(socket.as_raw_fd(), (&raw const addr) as *const _, len as _))?;
 
             Ok(socket)
         }
@@ -133,7 +133,7 @@ impl UnixDatagram {
             let socket = UnixDatagram::unbound()?;
             cvt(libc::bind(
                 socket.as_raw_fd(),
-                core::ptr::addr_of!(socket_addr.addr) as *const _,
+                (&raw const socket_addr.addr) as *const _,
                 socket_addr.len as _,
             ))?;
             Ok(socket)
@@ -215,7 +215,7 @@ impl UnixDatagram {
         unsafe {
             let (addr, len) = sockaddr_un(path.as_ref())?;
 
-            cvt(libc::connect(self.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len))?;
+            cvt(libc::connect(self.as_raw_fd(), (&raw const addr) as *const _, len))?;
         }
         Ok(())
     }
@@ -247,7 +247,7 @@ impl UnixDatagram {
         unsafe {
             cvt(libc::connect(
                 self.as_raw_fd(),
-                core::ptr::addr_of!(socket_addr.addr) as *const _,
+                (&raw const socket_addr.addr) as *const _,
                 socket_addr.len,
             ))?;
         }
@@ -514,7 +514,7 @@ impl UnixDatagram {
                 buf.as_ptr() as *const _,
                 buf.len(),
                 MSG_NOSIGNAL,
-                core::ptr::addr_of!(addr) as *const _,
+                (&raw const addr) as *const _,
                 len,
             ))?;
             Ok(count as usize)
@@ -549,7 +549,7 @@ impl UnixDatagram {
                 buf.as_ptr() as *const _,
                 buf.len(),
                 MSG_NOSIGNAL,
-                core::ptr::addr_of!(socket_addr.addr) as *const _,
+                (&raw const socket_addr.addr) as *const _,
                 socket_addr.len,
             ))?;
             Ok(count as usize)
diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs
index a55199c82fc..be236317d04 100644
--- a/library/std/src/os/unix/net/listener.rs
+++ b/library/std/src/os/unix/net/listener.rs
@@ -1,4 +1,4 @@
-use super::{sockaddr_un, SocketAddr, UnixStream};
+use super::{SocketAddr, UnixStream, sockaddr_un};
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::path::Path;
 use crate::sys::cvt;
@@ -103,11 +103,7 @@ impl UnixListener {
             )))]
             const backlog: libc::c_int = libc::SOMAXCONN;
 
-            cvt(libc::bind(
-                inner.as_inner().as_raw_fd(),
-                core::ptr::addr_of!(addr) as *const _,
-                len as _,
-            ))?;
+            cvt(libc::bind(inner.as_inner().as_raw_fd(), (&raw const addr) as *const _, len as _))?;
             cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?;
 
             Ok(UnixListener(inner))
@@ -147,7 +143,7 @@ impl UnixListener {
             const backlog: core::ffi::c_int = 128;
             cvt(libc::bind(
                 inner.as_raw_fd(),
-                core::ptr::addr_of!(socket_addr.addr) as *const _,
+                (&raw const socket_addr.addr) as *const _,
                 socket_addr.len as _,
             ))?;
             cvt(libc::listen(inner.as_raw_fd(), backlog))?;
@@ -182,7 +178,7 @@ impl UnixListener {
     pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
         let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() };
         let mut len = mem::size_of_val(&storage) as libc::socklen_t;
-        let sock = self.0.accept(core::ptr::addr_of_mut!(storage) as *mut _, &mut len)?;
+        let sock = self.0.accept((&raw mut storage) as *mut _, &mut len)?;
         let addr = SocketAddr::from_parts(storage, len)?;
         Ok((UnixStream(sock), addr))
     }
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
index 19fc7b3d853..cb210b41eae 100644
--- a/library/std/src/os/unix/net/stream.rs
+++ b/library/std/src/os/unix/net/stream.rs
@@ -1,3 +1,6 @@
+use super::{SocketAddr, sockaddr_un};
+#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+use super::{SocketAncillary, recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to};
 #[cfg(any(
     target_os = "android",
     target_os = "linux",
@@ -8,10 +11,7 @@
     target_os = "nto",
     target_vendor = "apple",
 ))]
-use super::{peer_cred, UCred};
-#[cfg(any(doc, target_os = "android", target_os = "linux"))]
-use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary};
-use super::{sockaddr_un, SocketAddr};
+use super::{UCred, peer_cred};
 use crate::fmt;
 use crate::io::{self, IoSlice, IoSliceMut};
 use crate::net::Shutdown;
@@ -84,7 +84,7 @@ impl UnixStream {
             let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
             let (addr, len) = sockaddr_un(path.as_ref())?;
 
-            cvt(libc::connect(inner.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len))?;
+            cvt(libc::connect(inner.as_raw_fd(), (&raw const addr) as *const _, len))?;
             Ok(UnixStream(inner))
         }
     }
@@ -118,7 +118,7 @@ impl UnixStream {
             let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
             cvt(libc::connect(
                 inner.as_raw_fd(),
-                core::ptr::addr_of!(socket_addr.addr) as *const _,
+                (&raw const socket_addr.addr) as *const _,
                 socket_addr.len,
             ))?;
             Ok(UnixStream(inner))
diff --git a/library/std/src/os/unix/net/ucred.rs b/library/std/src/os/unix/net/ucred.rs
index b96e373ad0a..e1014a4f296 100644
--- a/library/std/src/os/unix/net/ucred.rs
+++ b/library/std/src/os/unix/net/ucred.rs
@@ -38,7 +38,7 @@ pub(super) use self::impl_linux::peer_cred;
 
 #[cfg(any(target_os = "linux", target_os = "android"))]
 mod impl_linux {
-    use libc::{c_void, getsockopt, socklen_t, ucred, SOL_SOCKET, SO_PEERCRED};
+    use libc::{SO_PEERCRED, SOL_SOCKET, c_void, getsockopt, socklen_t, ucred};
 
     use super::UCred;
     use crate::os::unix::io::AsRawFd;
@@ -60,7 +60,7 @@ mod impl_linux {
                 socket.as_raw_fd(),
                 SOL_SOCKET,
                 SO_PEERCRED,
-                core::ptr::addr_of_mut!(ucred) as *mut c_void,
+                (&raw mut ucred) as *mut c_void,
                 &mut ucred_size,
             );
 
@@ -98,7 +98,7 @@ mod impl_bsd {
 
 #[cfg(target_vendor = "apple")]
 mod impl_apple {
-    use libc::{c_void, getpeereid, getsockopt, pid_t, socklen_t, LOCAL_PEERPID, SOL_LOCAL};
+    use libc::{LOCAL_PEERPID, SOL_LOCAL, c_void, getpeereid, getsockopt, pid_t, socklen_t};
 
     use super::UCred;
     use crate::os::unix::io::AsRawFd;
@@ -121,7 +121,7 @@ mod impl_apple {
                 socket.as_raw_fd(),
                 SOL_LOCAL,
                 LOCAL_PEERPID,
-                core::ptr::addr_of_mut!(pid) as *mut c_void,
+                (&raw mut pid) as *mut c_void,
                 &mut pid_size,
             );
 
diff --git a/library/std/src/os/wasi/mod.rs b/library/std/src/os/wasi/mod.rs
index 33b50c9e53b..2ee6aa46600 100644
--- a/library/std/src/os/wasi/mod.rs
+++ b/library/std/src/os/wasi/mod.rs
@@ -36,6 +36,8 @@
 pub mod ffi;
 pub mod fs;
 pub mod io;
+
+#[cfg(all(target_os = "wasi", target_env = "p1"))]
 pub mod net;
 
 /// A prelude for conveniently writing platform-specific code.
diff --git a/library/std/src/os/xous/ffi/definitions.rs b/library/std/src/os/xous/ffi/definitions.rs
index 345005bcc78..1b16849af03 100644
--- a/library/std/src/os/xous/ffi/definitions.rs
+++ b/library/std/src/os/xous/ffi/definitions.rs
@@ -126,42 +126,36 @@ impl From<i32> for Error {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl core::fmt::Display for Error {
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
-        write!(
-            f,
-            "{}",
-            match self {
-                Error::NoError => "no error occurred",
-                Error::BadAlignment => "memory was not properly aligned",
-                Error::BadAddress => "an invalid address was supplied",
-                Error::OutOfMemory => "the process or service has run out of memory",
-                Error::MemoryInUse => "the requested address is in use",
-                Error::InterruptNotFound =>
-                    "the requested interrupt does not exist on this platform",
-                Error::InterruptInUse => "the requested interrupt is currently in use",
-                Error::InvalidString => "the specified string was not formatted correctly",
-                Error::ServerExists => "a server with that address already exists",
-                Error::ServerNotFound => "the requetsed server could not be found",
-                Error::ProcessNotFound => "the target process does not exist",
-                Error::ProcessNotChild =>
-                    "the requested operation can only be done on child processes",
-                Error::ProcessTerminated => "the target process has crashed",
-                Error::Timeout => "the requested operation timed out",
-                Error::InternalError => "an internal error occurred",
-                Error::ServerQueueFull => "the server has too many pending messages",
-                Error::ThreadNotAvailable => "the specified thread does not exist",
-                Error::UnhandledSyscall => "the kernel did not recognize that syscall",
-                Error::InvalidSyscall => "the syscall had incorrect parameters",
-                Error::ShareViolation => "an attempt was made to share memory twice",
-                Error::InvalidThread => "tried to resume a thread that was not ready",
-                Error::InvalidPid => "kernel attempted to use a pid that was not valid",
-                Error::AccessDenied => "no permission to perform the requested operation",
-                Error::UseBeforeInit => "attempt to use a service before initialization finished",
-                Error::DoubleFree => "the requested resource was freed twice",
-                Error::DebugInProgress => "kernel attempted to activate a thread being debugged",
-                Error::InvalidLimit => "process attempted to adjust an invalid limit",
-                Error::UnknownError => "an unknown error occurred",
-            }
-        )
+        write!(f, "{}", match self {
+            Error::NoError => "no error occurred",
+            Error::BadAlignment => "memory was not properly aligned",
+            Error::BadAddress => "an invalid address was supplied",
+            Error::OutOfMemory => "the process or service has run out of memory",
+            Error::MemoryInUse => "the requested address is in use",
+            Error::InterruptNotFound => "the requested interrupt does not exist on this platform",
+            Error::InterruptInUse => "the requested interrupt is currently in use",
+            Error::InvalidString => "the specified string was not formatted correctly",
+            Error::ServerExists => "a server with that address already exists",
+            Error::ServerNotFound => "the requetsed server could not be found",
+            Error::ProcessNotFound => "the target process does not exist",
+            Error::ProcessNotChild => "the requested operation can only be done on child processes",
+            Error::ProcessTerminated => "the target process has crashed",
+            Error::Timeout => "the requested operation timed out",
+            Error::InternalError => "an internal error occurred",
+            Error::ServerQueueFull => "the server has too many pending messages",
+            Error::ThreadNotAvailable => "the specified thread does not exist",
+            Error::UnhandledSyscall => "the kernel did not recognize that syscall",
+            Error::InvalidSyscall => "the syscall had incorrect parameters",
+            Error::ShareViolation => "an attempt was made to share memory twice",
+            Error::InvalidThread => "tried to resume a thread that was not ready",
+            Error::InvalidPid => "kernel attempted to use a pid that was not valid",
+            Error::AccessDenied => "no permission to perform the requested operation",
+            Error::UseBeforeInit => "attempt to use a service before initialization finished",
+            Error::DoubleFree => "the requested resource was freed twice",
+            Error::DebugInProgress => "kernel attempted to activate a thread being debugged",
+            Error::InvalidLimit => "process attempted to adjust an invalid limit",
+            Error::UnknownError => "an unknown error occurred",
+        })
     }
 }
 
diff --git a/library/std/src/os/xous/services.rs b/library/std/src/os/xous/services.rs
index ddf0236f5ad..93916750c05 100644
--- a/library/std/src/os/xous/services.rs
+++ b/library/std/src/os/xous/services.rs
@@ -19,7 +19,7 @@ pub(crate) use ticktimer::*;
 
 mod ns {
     const NAME_MAX_LENGTH: usize = 64;
-    use crate::os::xous::ffi::{lend_mut, Connection};
+    use crate::os::xous::ffi::{Connection, lend_mut};
     // By making this repr(C), the layout of this struct becomes well-defined
     // and no longer shifts around.
     // By marking it as `align(4096)` we define that it will be page-aligned,
diff --git a/library/std/src/os/xous/services/systime.rs b/library/std/src/os/xous/services/systime.rs
index 079ede7aa86..de87694b4cd 100644
--- a/library/std/src/os/xous/services/systime.rs
+++ b/library/std/src/os/xous/services/systime.rs
@@ -1,6 +1,6 @@
 use core::sync::atomic::{AtomicU32, Ordering};
 
-use crate::os::xous::ffi::{connect, Connection};
+use crate::os::xous::ffi::{Connection, connect};
 
 pub(crate) enum SystimeScalar {
     GetUtcTimeMs,
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index 541cf42ab47..d649357a56d 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -231,11 +231,11 @@ pub macro panic_2015 {
     }),
 }
 
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+pub use core::panic::Location;
 #[doc(hidden)]
 #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
 pub use core::panic::panic_2021;
-#[stable(feature = "panic_hooks", since = "1.10.0")]
-pub use core::panic::Location;
 #[stable(feature = "catch_unwind", since = "1.9.0")]
 pub use core::panic::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe};
 
@@ -288,45 +288,55 @@ pub use core::panic::abort_unwind;
 
 /// Invokes a closure, capturing the cause of an unwinding panic if one occurs.
 ///
-/// This function will return `Ok` with the closure's result if the closure
-/// does not panic, and will return `Err(cause)` if the closure panics. The
-/// `cause` returned is the object with which panic was originally invoked.
+/// This function will return `Ok` with the closure's result if the closure does
+/// not panic, and will return `Err(cause)` if the closure panics. The `cause`
+/// returned is the object with which panic was originally invoked.
 ///
-/// It is currently undefined behavior to unwind from Rust code into foreign
-/// code, so this function is particularly useful when Rust is called from
-/// another language (normally C). This can run arbitrary Rust code, capturing a
-/// panic and allowing a graceful handling of the error.
+/// Rust functions that are expected to be called from foreign code that does
+/// not support unwinding (such as C compiled with `-fno-exceptions`) should be
+/// defined using `extern "C"`, which ensures that if the Rust code panics, it
+/// is automatically caught and the process is aborted. If this is the desired
+/// behavior, it is not necessary to use `catch_unwind` explicitly. This
+/// function should instead be used when more graceful error-handling is needed.
 ///
 /// It is **not** recommended to use this function for a general try/catch
 /// mechanism. The [`Result`] type is more appropriate to use for functions that
 /// can fail on a regular basis. Additionally, this function is not guaranteed
 /// to catch all panics, see the "Notes" section below.
 ///
-/// The closure provided is required to adhere to the [`UnwindSafe`] trait to ensure
-/// that all captured variables are safe to cross this boundary. The purpose of
-/// this bound is to encode the concept of [exception safety][rfc] in the type
-/// system. Most usage of this function should not need to worry about this
-/// bound as programs are naturally unwind safe without `unsafe` code. If it
-/// becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to quickly
-/// assert that the usage here is indeed unwind safe.
+/// The closure provided is required to adhere to the [`UnwindSafe`] trait to
+/// ensure that all captured variables are safe to cross this boundary. The
+/// purpose of this bound is to encode the concept of [exception safety][rfc] in
+/// the type system. Most usage of this function should not need to worry about
+/// this bound as programs are naturally unwind safe without `unsafe` code. If
+/// it becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to
+/// quickly assert that the usage here is indeed unwind safe.
 ///
 /// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
 ///
 /// # Notes
 ///
-/// Note that this function **might not catch all panics** in Rust. A panic in
-/// Rust is not always implemented via unwinding, but can be implemented by
-/// aborting the process as well. This function *only* catches unwinding panics,
-/// not those that abort the process.
+/// This function **might not catch all Rust panics**. A Rust panic is not
+/// always implemented via unwinding, but can be implemented by aborting the
+/// process as well. This function *only* catches unwinding panics, not those
+/// that abort the process.
+///
+/// If a custom panic hook has been set, it will be invoked before the panic is
+/// caught, before unwinding.
 ///
-/// Note that if a custom panic hook has been set, it will be invoked before
-/// the panic is caught, before unwinding.
+/// Although unwinding into Rust code with a foreign exception (e.g. an
+/// exception thrown from C++ code, or a `panic!` in Rust code compiled or
+/// linked with a different runtime) via an appropriate ABI (e.g. `"C-unwind"`)
+/// is permitted, catching such an exception using this function will have one
+/// of two behaviors, and it is unspecified which will occur:
 ///
-/// Also note that unwinding into Rust code with a foreign exception (e.g.
-/// an exception thrown from C++ code) is undefined behavior.
+/// * The process aborts, after executing all destructors of `f` and the
+///   functions it called.
+/// * The function returns a `Result::Err` containing an opaque type.
 ///
-/// Finally, be **careful in how you drop the result of this function**.
-/// If it is `Err`, it contains the panic payload, and dropping that may in turn panic!
+/// Finally, be **careful in how you drop the result of this function**. If it
+/// is `Err`, it contains the panic payload, and dropping that may in turn
+/// panic!
 ///
 /// # Examples
 ///
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 336e34d7b95..ac1f547c914 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -23,8 +23,8 @@ use crate::mem::{self, ManuallyDrop};
 use crate::panic::{BacktraceStyle, PanicHookInfo};
 use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sync::{PoisonError, RwLock};
+use crate::sys::backtrace;
 use crate::sys::stdio::panic_output;
-use crate::sys::{backtrace, dbg};
 use crate::{fmt, intrinsics, process, thread};
 
 // Binary interface to the panic runtime that the standard library depends on.
@@ -506,7 +506,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
     // method of calling a catch panic whilst juggling ownership.
     let mut data = Data { f: ManuallyDrop::new(f) };
 
-    let data_ptr = core::ptr::addr_of_mut!(data) as *mut u8;
+    let data_ptr = (&raw mut data) as *mut u8;
     // SAFETY:
     //
     // Access to the union's fields: this is `std` and we know that the `r#try`
@@ -859,14 +859,6 @@ pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! {
 #[cfg_attr(not(test), rustc_std_internal_symbol)]
 #[cfg(not(feature = "panic_immediate_abort"))]
 fn rust_panic(msg: &mut dyn PanicPayload) -> ! {
-    // Break into the debugger if it is attached.
-    // The return value is not currently used.
-    //
-    // This function isn't used anywhere else, and
-    // using inside `#[panic_handler]` doesn't seem
-    // to count, so a warning is issued.
-    let _ = dbg::breakpoint_if_debugging();
-
     let code = unsafe { __rust_start_panic(msg) };
     rtabort!("failed to initiate panic, error {code}")
 }
@@ -874,14 +866,6 @@ fn rust_panic(msg: &mut dyn PanicPayload) -> ! {
 #[cfg_attr(not(test), rustc_std_internal_symbol)]
 #[cfg(feature = "panic_immediate_abort")]
 fn rust_panic(_: &mut dyn PanicPayload) -> ! {
-    // Break into the debugger if it is attached.
-    // The return value is not currently used.
-    //
-    // This function isn't used anywhere else, and
-    // using inside `#[panic_handler]` doesn't seem
-    // to count, so a warning is issued.
-    let _ = dbg::breakpoint_if_debugging();
-
     unsafe {
         crate::intrinsics::abort();
     }
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index aa9f63d915a..63edfdb82f3 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -75,14 +75,14 @@ use core::clone::CloneToUninit;
 use crate::borrow::{Borrow, Cow};
 use crate::collections::TryReserveError;
 use crate::error::Error;
-use crate::ffi::{os_str, OsStr, OsString};
+use crate::ffi::{OsStr, OsString, os_str};
 use crate::hash::{Hash, Hasher};
 use crate::iter::FusedIterator;
 use crate::ops::{self, Deref};
 use crate::rc::Rc;
 use crate::str::FromStr;
 use crate::sync::Arc;
-use crate::sys::path::{is_sep_byte, is_verbatim_sep, parse_prefix, MAIN_SEP_STR};
+use crate::sys::path::{MAIN_SEP_STR, is_sep_byte, is_verbatim_sep, parse_prefix};
 use crate::{cmp, fmt, fs, io, sys};
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -3144,7 +3144,7 @@ unsafe impl CloneToUninit for Path {
     #[cfg_attr(debug_assertions, track_caller)]
     unsafe fn clone_to_uninit(&self, dst: *mut Self) {
         // SAFETY: Path is just a wrapper around OsStr
-        unsafe { self.inner.clone_to_uninit(core::ptr::addr_of_mut!((*dst).inner)) }
+        unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) }
     }
 }
 
diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs
index 6436872087d..b75793d2bc9 100644
--- a/library/std/src/path/tests.rs
+++ b/library/std/src/path/tests.rs
@@ -139,7 +139,7 @@ fn test_pathbuf_leak() {
 }
 
 #[test]
-#[cfg(unix)]
+#[cfg(any(unix, target_os = "wasi"))]
 pub fn test_decompositions_unix() {
     t!("",
     iter: [],
@@ -1201,7 +1201,10 @@ pub fn test_push() {
         });
     );
 
-    if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) {
+    if cfg!(unix)
+        || cfg!(target_os = "wasi")
+        || cfg!(all(target_env = "sgx", target_vendor = "fortanix"))
+    {
         tp!("", "foo", "foo");
         tp!("foo", "bar", "foo/bar");
         tp!("foo/", "bar", "foo/bar");
@@ -1358,7 +1361,10 @@ pub fn test_set_file_name() {
     tfn!("foo", "bar", "bar");
     tfn!("foo", "", "");
     tfn!("", "foo", "foo");
-    if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) {
+    if cfg!(unix)
+        || cfg!(target_os = "wasi")
+        || cfg!(all(target_env = "sgx", target_vendor = "fortanix"))
+    {
         tfn!(".", "foo", "./foo");
         tfn!("foo/", "bar", "bar");
         tfn!("foo/.", "bar", "bar");
@@ -1758,7 +1764,7 @@ fn test_components_debug() {
     assert_eq!(expected, actual);
 }
 
-#[cfg(unix)]
+#[cfg(any(unix, target_os = "wasi"))]
 #[test]
 fn test_iter_debug() {
     let path = Path::new("/tmp");
@@ -1859,7 +1865,7 @@ fn test_ord() {
 }
 
 #[test]
-#[cfg(unix)]
+#[cfg(any(unix, target_os = "wasi"))]
 fn test_unix_absolute() {
     use crate::path::absolute;
 
diff --git a/library/std/src/pipe.rs b/library/std/src/pipe.rs
index aa4c7014fe9..891032e94a6 100644
--- a/library/std/src/pipe.rs
+++ b/library/std/src/pipe.rs
@@ -12,7 +12,7 @@
 //! ```
 
 use crate::io;
-use crate::sys::anonymous_pipe::{pipe as pipe_inner, AnonPipe};
+use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner};
 
 /// Create anonymous pipe that is close-on-exec and blocking.
 #[unstable(feature = "anonymous_pipe", issue = "127154")]
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 60d452465da..f24fe353e55 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -148,7 +148,15 @@
 #![stable(feature = "process", since = "1.0.0")]
 #![deny(unsafe_op_in_unsafe_fn)]
 
-#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx", target_os = "xous"))))]
+#[cfg(all(
+    test,
+    not(any(
+        target_os = "emscripten",
+        target_os = "wasi",
+        target_env = "sgx",
+        target_os = "xous"
+    ))
+))]
 mod tests;
 
 use crate::convert::Infallible;
@@ -157,7 +165,7 @@ use crate::io::prelude::*;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::num::NonZero;
 use crate::path::Path;
-use crate::sys::pipe::{read2, AnonPipe};
+use crate::sys::pipe::{AnonPipe, read2};
 use crate::sys::process as imp;
 #[stable(feature = "command_access", since = "1.57.0")]
 pub use crate::sys_common::process::CommandEnvs;
diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs
index f8e8e0dea55..88cc95caf40 100644
--- a/library/std/src/process/tests.rs
+++ b/library/std/src/process/tests.rs
@@ -437,7 +437,7 @@ fn test_proc_thread_attributes() {
     use crate::mem;
     use crate::os::windows::io::AsRawHandle;
     use crate::os::windows::process::CommandExt;
-    use crate::sys::c::{CloseHandle, BOOL, HANDLE};
+    use crate::sys::c::{BOOL, CloseHandle, HANDLE};
     use crate::sys::cvt;
 
     #[repr(C)]
diff --git a/library/std/src/random.rs b/library/std/src/random.rs
new file mode 100644
index 00000000000..604fa4df110
--- /dev/null
+++ b/library/std/src/random.rs
@@ -0,0 +1,105 @@
+//! Random value generation.
+//!
+//! The [`Random`] trait allows generating a random value for a type using a
+//! given [`RandomSource`].
+
+#[unstable(feature = "random", issue = "130703")]
+pub use core::random::*;
+
+use crate::sys::random as sys;
+
+/// The default random source.
+///
+/// This asks the system for random data suitable for cryptographic purposes
+/// such as key generation. If security is a concern, consult the platform
+/// documentation below for the specific guarantees your target provides.
+///
+/// The high quality of randomness provided by this source means it can be quite
+/// slow on some targets. If you need a large quantity of random numbers and
+/// security is not a concern,  consider using an alternative random number
+/// generator (potentially seeded from this one).
+///
+/// # Underlying sources
+///
+/// Platform               | Source
+/// -----------------------|---------------------------------------------------------------
+/// Linux                  | [`getrandom`] or [`/dev/urandom`] after polling `/dev/random`
+/// Windows                | [`ProcessPrng`](https://learn.microsoft.com/en-us/windows/win32/seccng/processprng)
+/// Apple                  | `CCRandomGenerateBytes`
+/// DragonFly              | [`arc4random_buf`](https://man.dragonflybsd.org/?command=arc4random)
+/// ESP-IDF                | [`esp_fill_random`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/random.html#_CPPv415esp_fill_randomPv6size_t)
+/// FreeBSD                | [`arc4random_buf`](https://man.freebsd.org/cgi/man.cgi?query=arc4random)
+/// Fuchsia                | [`cprng_draw`](https://fuchsia.dev/reference/syscalls/cprng_draw)
+/// Haiku                  | `arc4random_buf`
+/// Illumos                | [`arc4random_buf`](https://www.illumos.org/man/3C/arc4random)
+/// NetBSD                 | [`arc4random_buf`](https://man.netbsd.org/arc4random.3)
+/// OpenBSD                | [`arc4random_buf`](https://man.openbsd.org/arc4random.3)
+/// Solaris                | [`arc4random_buf`](https://docs.oracle.com/cd/E88353_01/html/E37843/arc4random-3c.html)
+/// Vita                   | `arc4random_buf`
+/// Hermit                 | `read_entropy`
+/// Horizon                | `getrandom` shim
+/// Hurd, L4Re, QNX        | `/dev/urandom`
+/// Redox                  | `/scheme/rand`
+/// SGX                    | [`rdrand`](https://en.wikipedia.org/wiki/RDRAND)
+/// SOLID                  | `SOLID_RNG_SampleRandomBytes`
+/// TEEOS                  | `TEE_GenerateRandom`
+/// UEFI                   | [`EFI_RNG_PROTOCOL`](https://uefi.org/specs/UEFI/2.10/37_Secure_Technologies.html#random-number-generator-protocol)
+/// VxWorks                | `randABytes` after waiting for `randSecure` to become ready
+/// WASI                   | [`random_get`](https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#-random_getbuf-pointeru8-buf_len-size---result-errno)
+/// ZKVM                   | `sys_rand`
+///
+/// Note that the sources used might change over time.
+///
+/// Consult the documentation for the underlying operations on your supported
+/// targets to determine whether they provide any particular desired properties,
+/// such as support for reseeding on VM fork operations.
+///
+/// [`getrandom`]: https://www.man7.org/linux/man-pages/man2/getrandom.2.html
+/// [`/dev/urandom`]: https://www.man7.org/linux/man-pages/man4/random.4.html
+#[derive(Default, Debug, Clone, Copy)]
+#[unstable(feature = "random", issue = "130703")]
+pub struct DefaultRandomSource;
+
+#[unstable(feature = "random", issue = "130703")]
+impl RandomSource for DefaultRandomSource {
+    fn fill_bytes(&mut self, bytes: &mut [u8]) {
+        sys::fill_bytes(bytes)
+    }
+}
+
+/// Generates a random value with the default random source.
+///
+/// This is a convenience function for `T::random(&mut DefaultRandomSource)` and
+/// will sample according to the same distribution as the underlying [`Random`]
+/// trait implementation. See [`DefaultRandomSource`] for more information about
+/// how randomness is sourced.
+///
+/// **Warning:** Be careful when manipulating random values! The
+/// [`random`](Random::random) method on integers samples them with a uniform
+/// distribution, so a value of 1 is just as likely as [`i32::MAX`]. By using
+/// modulo operations, some of the resulting values can become more likely than
+/// others. Use audited crates when in doubt.
+///
+/// # Examples
+///
+/// Generating a [version 4/variant 1 UUID] represented as text:
+/// ```
+/// #![feature(random)]
+///
+/// use std::random::random;
+///
+/// let bits: u128 = random();
+/// let g1 = (bits >> 96) as u32;
+/// let g2 = (bits >> 80) as u16;
+/// let g3 = (0x4000 | (bits >> 64) & 0x0fff) as u16;
+/// let g4 = (0x8000 | (bits >> 48) & 0x3fff) as u16;
+/// let g5 = (bits & 0xffffffffffff) as u64;
+/// let uuid = format!("{g1:08x}-{g2:04x}-{g3:04x}-{g4:04x}-{g5:012x}");
+/// println!("{uuid}");
+/// ```
+///
+/// [version 4/variant 1 UUID]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
+#[unstable(feature = "random", issue = "130703")]
+pub fn random<T: Random>() -> T {
+    T::random(&mut DefaultRandomSource)
+}
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index b6f36931ec2..80e7c3c026b 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -21,9 +21,10 @@ pub use crate::panicking::{begin_panic, panic_count};
 pub use core::panicking::{panic_display, panic_fmt};
 
 #[rustfmt::skip]
+use crate::any::Any;
 use crate::sync::Once;
-use crate::sys;
 use crate::thread::{self, Thread};
+use crate::{mem, panic, sys};
 
 // Prints to the "panic output", depending on the platform this may be:
 // - the standard error output
@@ -66,6 +67,11 @@ macro_rules! rtunwrap {
     };
 }
 
+fn handle_rt_panic(e: Box<dyn Any + Send>) {
+    mem::forget(e);
+    rtabort!("initialization or cleanup bug");
+}
+
 // One-time runtime initialization.
 // Runs before `main`.
 // SAFETY: must be called only once during runtime initialization.
@@ -96,9 +102,38 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
         sys::init(argc, argv, sigpipe)
     };
 
-    // Set up the current thread to give it the right name.
-    let thread = Thread::new_main();
-    thread::set_current(thread);
+    // Set up the current thread handle to give it the right name.
+    //
+    // When code running before main uses `ReentrantLock` (for example by
+    // using `println!`), the thread ID can become initialized before we
+    // create this handle. Since `set_current` fails when the ID of the
+    // handle does not match the current ID, we should attempt to use the
+    // current thread ID here instead of unconditionally creating a new
+    // one. Also see #130210.
+    let thread = Thread::new_main(thread::current_id());
+    if let Err(_thread) = thread::set_current(thread) {
+        // `thread::current` will create a new handle if none has been set yet.
+        // Thus, if someone uses it before main, this call will fail. That's a
+        // bad idea though, as we then cannot set the main thread name here.
+        //
+        // FIXME: detect the main thread in `thread::current` and use the
+        //        correct name there.
+        rtabort!("code running before main must not use thread::current");
+    }
+}
+
+/// Clean up the thread-local runtime state. This *should* be run after all other
+/// code managed by the Rust runtime, but will not cause UB if that condition is
+/// not fulfilled. Also note that this function is not guaranteed to be run, but
+/// skipping it will cause leaks and therefore is to be avoided.
+pub(crate) fn thread_cleanup() {
+    // This function is run in situations where unwinding leads to an abort
+    // (think `extern "C"` functions). Abort here instead so that we can
+    // print a nice message.
+    panic::catch_unwind(|| {
+        crate::thread::drop_current();
+    })
+    .unwrap_or_else(handle_rt_panic);
 }
 
 // One-time runtime cleanup.
@@ -123,11 +158,6 @@ fn lang_start_internal(
     argv: *const *const u8,
     sigpipe: u8,
 ) -> Result<isize, !> {
-    use crate::{mem, panic};
-    let rt_abort = move |e| {
-        mem::forget(e);
-        rtabort!("initialization or cleanup bug");
-    };
     // Guard against the code called by this function from unwinding outside of the Rust-controlled
     // code, which is UB. This is a requirement imposed by a combination of how the
     // `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking
@@ -139,16 +169,17 @@ fn lang_start_internal(
     // prevent std from accidentally introducing a panic to these functions. Another is from
     // user code from `main` or, more nefariously, as described in e.g. issue #86030.
     // SAFETY: Only called once during runtime initialization.
-    panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?;
+    panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) })
+        .unwrap_or_else(handle_rt_panic);
     let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)
         .map_err(move |e| {
             mem::forget(e);
             rtabort!("drop of the panic payload panicked");
         });
-    panic::catch_unwind(cleanup).map_err(rt_abort)?;
+    panic::catch_unwind(cleanup).unwrap_or_else(handle_rt_panic);
     // Guard against multiple threads calling `libc::exit` concurrently.
     // See the documentation for `unique_thread_exit` for more information.
-    panic::catch_unwind(|| crate::sys::exit_guard::unique_thread_exit()).map_err(rt_abort)?;
+    panic::catch_unwind(crate::sys::exit_guard::unique_thread_exit).unwrap_or_else(handle_rt_panic);
     ret_code
 }
 
diff --git a/library/std/src/sync/barrier/tests.rs b/library/std/src/sync/barrier/tests.rs
index 834a3e75158..0fbcd998812 100644
--- a/library/std/src/sync/barrier/tests.rs
+++ b/library/std/src/sync/barrier/tests.rs
@@ -1,9 +1,9 @@
-use crate::sync::mpsc::{channel, TryRecvError};
+use crate::sync::mpsc::{TryRecvError, channel};
 use crate::sync::{Arc, Barrier};
 use crate::thread;
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn test_barrier() {
     const N: usize = 10;
 
diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs
index e41cbc1a65c..44ffcb528d9 100644
--- a/library/std/src/sync/condvar.rs
+++ b/library/std/src/sync/condvar.rs
@@ -2,7 +2,7 @@
 mod tests;
 
 use crate::fmt;
-use crate::sync::{mutex, poison, LockResult, MutexGuard, PoisonError};
+use crate::sync::{LockResult, MutexGuard, PoisonError, mutex, poison};
 use crate::sys::sync as sys;
 use crate::time::{Duration, Instant};
 
diff --git a/library/std/src/sync/condvar/tests.rs b/library/std/src/sync/condvar/tests.rs
index 12d13a6b20b..f9e9066bc92 100644
--- a/library/std/src/sync/condvar/tests.rs
+++ b/library/std/src/sync/condvar/tests.rs
@@ -12,7 +12,7 @@ fn smoke() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn notify_one() {
     let m = Arc::new(Mutex::new(()));
     let m2 = m.clone();
@@ -29,7 +29,7 @@ fn notify_one() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn notify_all() {
     const N: usize = 10;
 
@@ -66,7 +66,7 @@ fn notify_all() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn wait_while() {
     let pair = Arc::new((Mutex::new(false), Condvar::new()));
     let pair2 = pair.clone();
@@ -87,7 +87,7 @@ fn wait_while() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported
 fn wait_timeout_wait() {
     let m = Arc::new(Mutex::new(()));
     let c = Arc::new(Condvar::new());
@@ -106,7 +106,7 @@ fn wait_timeout_wait() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported
 fn wait_timeout_while_wait() {
     let m = Arc::new(Mutex::new(()));
     let c = Arc::new(Condvar::new());
@@ -118,7 +118,7 @@ fn wait_timeout_while_wait() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported
 fn wait_timeout_while_instant_satisfy() {
     let m = Arc::new(Mutex::new(()));
     let c = Arc::new(Condvar::new());
@@ -130,7 +130,7 @@ fn wait_timeout_while_instant_satisfy() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn wait_timeout_while_wake() {
     let pair = Arc::new((Mutex::new(false), Condvar::new()));
     let pair_copy = pair.clone();
@@ -153,7 +153,7 @@ fn wait_timeout_while_wake() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn wait_timeout_wake() {
     let m = Arc::new(Mutex::new(()));
     let c = Arc::new(Condvar::new());
diff --git a/library/std/src/sync/lazy_lock/tests.rs b/library/std/src/sync/lazy_lock/tests.rs
index 94044368305..7d7dde54349 100644
--- a/library/std/src/sync/lazy_lock/tests.rs
+++ b/library/std/src/sync/lazy_lock/tests.rs
@@ -34,6 +34,7 @@ fn lazy_default() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn lazy_poisoning() {
     let x: LazyCell<String> = LazyCell::new(|| panic!("kaboom"));
     for _ in 0..2 {
@@ -43,7 +44,7 @@ fn lazy_poisoning() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn sync_lazy_new() {
     static CALLED: AtomicUsize = AtomicUsize::new(0);
     static SYNC_LAZY: LazyLock<i32> = LazyLock::new(|| {
@@ -90,7 +91,7 @@ fn sync_lazy_default() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn static_sync_lazy() {
     static XS: LazyLock<Vec<i32>> = LazyLock::new(|| {
         let mut xs = Vec::new();
@@ -123,6 +124,7 @@ fn static_sync_lazy_via_fn() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn sync_lazy_poisoning() {
     let x: LazyLock<String> = LazyLock::new(|| panic!("kaboom"));
     for _ in 0..2 {
diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs
index d0ba8cc3b47..0fb77331293 100644
--- a/library/std/src/sync/mod.rs
+++ b/library/std/src/sync/mod.rs
@@ -9,6 +9,9 @@
 //! Consider the following code, operating on some global static variables:
 //!
 //! ```rust
+//! // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
+//! #![allow(static_mut_refs)]
+//!
 //! static mut A: u32 = 0;
 //! static mut B: u32 = 0;
 //! static mut C: u32 = 0;
@@ -130,6 +133,11 @@
 //!   inter-thread synchronisation mechanism, at the cost of some
 //!   extra memory.
 //!
+//! - [`mpmc`]: Multi-producer, multi-consumer queues, used for
+//!   message-based communication. Can provide a lightweight
+//!   inter-thread synchronisation mechanism, at the cost of some
+//!   extra memory.
+//!
 //! - [`Mutex`]: Mutual Exclusion mechanism, which ensures that at
 //!   most one thread at a time is able to access some data.
 //!
@@ -150,6 +158,7 @@
 //! [`Arc`]: crate::sync::Arc
 //! [`Barrier`]: crate::sync::Barrier
 //! [`Condvar`]: crate::sync::Condvar
+//! [`mpmc`]: crate::sync::mpmc
 //! [`mpsc`]: crate::sync::mpsc
 //! [`Mutex`]: crate::sync::Mutex
 //! [`Once`]: crate::sync::Once
@@ -158,10 +167,10 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use core::sync::atomic;
 #[unstable(feature = "exclusive_wrapper", issue = "98407")]
 pub use core::sync::Exclusive;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::sync::atomic;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use alloc_crate::sync::{Arc, Weak};
@@ -178,7 +187,7 @@ pub use self::mutex::MappedMutexGuard;
 pub use self::mutex::{Mutex, MutexGuard};
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated)]
-pub use self::once::{Once, OnceState, ONCE_INIT};
+pub use self::once::{ONCE_INIT, Once, OnceState};
 #[stable(feature = "once_cell", since = "1.70.0")]
 pub use self::once_lock::OnceLock;
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -190,12 +199,13 @@ pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+pub mod mpmc;
 pub mod mpsc;
 
 mod barrier;
 mod condvar;
 mod lazy_lock;
-mod mpmc;
 mod mutex;
 pub(crate) mod once;
 mod once_lock;
diff --git a/library/std/src/sync/mpmc/context.rs b/library/std/src/sync/mpmc/context.rs
index 8db3c9896eb..2371d32d4ea 100644
--- a/library/std/src/sync/mpmc/context.rs
+++ b/library/std/src/sync/mpmc/context.rs
@@ -4,8 +4,8 @@ use super::select::Selected;
 use super::waker::current_thread_id;
 use crate::cell::Cell;
 use crate::ptr;
-use crate::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
 use crate::sync::Arc;
+use crate::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
 use crate::thread::{self, Thread};
 use crate::time::Instant;
 
diff --git a/library/std/src/sync/mpmc/error.rs b/library/std/src/sync/mpmc/error.rs
index e3aec7e7623..e34b56d0831 100644
--- a/library/std/src/sync/mpmc/error.rs
+++ b/library/std/src/sync/mpmc/error.rs
@@ -7,6 +7,7 @@ use crate::{error, fmt};
 ///
 /// [`send_timeout`]: super::Sender::send_timeout
 #[derive(PartialEq, Eq, Clone, Copy)]
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 pub enum SendTimeoutError<T> {
     /// The message could not be sent because the channel is full and the operation timed out.
     ///
@@ -18,12 +19,14 @@ pub enum SendTimeoutError<T> {
     Disconnected(T),
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> fmt::Debug for SendTimeoutError<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         "SendTimeoutError(..)".fmt(f)
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> fmt::Display for SendTimeoutError<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
@@ -33,8 +36,10 @@ impl<T> fmt::Display for SendTimeoutError<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> error::Error for SendTimeoutError<T> {}
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> From<SendError<T>> for SendTimeoutError<T> {
     fn from(err: SendError<T>) -> SendTimeoutError<T> {
         match err {
diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs
index c640e07348e..44e146a89ba 100644
--- a/library/std/src/sync/mpmc/mod.rs
+++ b/library/std/src/sync/mpmc/mod.rs
@@ -1,8 +1,114 @@
-//! Multi-producer multi-consumer channels.
+//! Multi-producer, multi-consumer FIFO queue communication primitives.
+//!
+//! This module provides message-based communication over channels, concretely
+//! defined by two types:
+//!
+//! * [`Sender`]
+//! * [`Receiver`]
+//!
+//! [`Sender`]s are used to send data to a set of [`Receiver`]s. Both
+//! sender and receiver are cloneable (multi-producer) such that many threads can send
+//! simultaneously to receivers (multi-consumer).
+//!
+//! These channels come in two flavors:
+//!
+//! 1. An asynchronous, infinitely buffered channel. The [`channel`] function
+//!    will return a `(Sender, Receiver)` tuple where all sends will be
+//!    **asynchronous** (they never block). The channel conceptually has an
+//!    infinite buffer.
+//!
+//! 2. A synchronous, bounded channel. The [`sync_channel`] function will
+//!    return a `(SyncSender, Receiver)` tuple where the storage for pending
+//!    messages is a pre-allocated buffer of a fixed size. All sends will be
+//!    **synchronous** by blocking until there is buffer space available. Note
+//!    that a bound of 0 is allowed, causing the channel to become a "rendezvous"
+//!    channel where each sender atomically hands off a message to a receiver.
+//!
+//! [`send`]: Sender::send
+//!
+//! ## Disconnection
+//!
+//! The send and receive operations on channels will all return a [`Result`]
+//! indicating whether the operation succeeded or not. An unsuccessful operation
+//! is normally indicative of the other half of a channel having "hung up" by
+//! being dropped in its corresponding thread.
+//!
+//! Once half of a channel has been deallocated, most operations can no longer
+//! continue to make progress, so [`Err`] will be returned. Many applications
+//! will continue to [`unwrap`] the results returned from this module,
+//! instigating a propagation of failure among threads if one unexpectedly dies.
+//!
+//! [`unwrap`]: Result::unwrap
+//!
+//! # Examples
+//!
+//! Simple usage:
+//!
+//! ```
+//! #![feature(mpmc_channel)]
+//!
+//! use std::thread;
+//! use std::sync::mpmc::channel;
+//!
+//! // Create a simple streaming channel
+//! let (tx, rx) = channel();
+//! thread::spawn(move || {
+//!     tx.send(10).unwrap();
+//! });
+//! assert_eq!(rx.recv().unwrap(), 10);
+//! ```
+//!
+//! Shared usage:
+//!
+//! ```
+//! #![feature(mpmc_channel)]
+//!
+//! use std::thread;
+//! use std::sync::mpmc::channel;
+//!
+//! thread::scope(|s| {
+//!     // Create a shared channel that can be sent along from many threads
+//!     // where tx is the sending half (tx for transmission), and rx is the receiving
+//!     // half (rx for receiving).
+//!     let (tx, rx) = channel();
+//!     for i in 0..10 {
+//!         let tx = tx.clone();
+//!         s.spawn(move || {
+//!             tx.send(i).unwrap();
+//!         });
+//!     }
+//!
+//!     for _ in 0..5 {
+//!         let rx1 = rx.clone();
+//!         let rx2 = rx.clone();
+//!         s.spawn(move || {
+//!             let j = rx1.recv().unwrap();
+//!             assert!(0 <= j && j < 10);
+//!         });
+//!         s.spawn(move || {
+//!             let j = rx2.recv().unwrap();
+//!             assert!(0 <= j && j < 10);
+//!         });
+//!     }
+//! })
+//! ```
+//!
+//! Propagating panics:
+//!
+//! ```
+//! #![feature(mpmc_channel)]
+//!
+//! use std::sync::mpmc::channel;
+//!
+//! // The call to recv() will return an error because the channel has already
+//! // hung up (or been deallocated)
+//! let (tx, rx) = channel::<i32>();
+//! drop(tx);
+//! assert!(rx.recv().is_err());
+//! ```
 
-// This module is not currently exposed publicly, but is used
-// as the implementation for the channels in `sync::mpsc`. The
-// implementation comes from the crossbeam-channel crate:
+// This module is used as the implementation for the channels in `sync::mpsc`.
+// The implementation comes from the crossbeam-channel crate:
 //
 // Copyright (c) 2019 The Crossbeam Project Developers
 //
@@ -46,9 +152,47 @@ use crate::fmt;
 use crate::panic::{RefUnwindSafe, UnwindSafe};
 use crate::time::{Duration, Instant};
 
-/// Creates a channel of unbounded capacity.
+/// Creates a new asynchronous channel, returning the sender/receiver halves.
+/// All data sent on the [`Sender`] will become available on the [`Receiver`] in
+/// the same order as it was sent, and no [`send`] will block the calling thread
+/// (this channel has an "infinite buffer", unlike [`sync_channel`], which will
+/// block after its buffer limit is reached). [`recv`] will block until a message
+/// is available while there is at least one [`Sender`] alive (including clones).
 ///
-/// This channel has a growable buffer that can hold any number of messages at a time.
+/// The [`Sender`] can be cloned to [`send`] to the same channel multiple times.
+/// The [`Receiver`] also can be cloned to have multi receivers.
+///
+/// If the [`Receiver`] is disconnected while trying to [`send`] with the
+/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, if the
+/// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will
+/// return a [`RecvError`].
+///
+/// [`send`]: Sender::send
+/// [`recv`]: Receiver::recv
+///
+/// # Examples
+///
+/// ```
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+///
+/// let (sender, receiver) = channel();
+///
+/// // Spawn off an expensive computation
+/// thread::spawn(move || {
+/// #   fn expensive_computation() {}
+///     sender.send(expensive_computation()).unwrap();
+/// });
+///
+/// // Do some useful work for awhile
+///
+/// // Let's see what that answer was
+/// println!("{:?}", receiver.recv().unwrap());
+/// ```
+#[must_use]
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
     let (s, r) = counter::new(list::Channel::new());
     let s = Sender { flavor: SenderFlavor::List(s) };
@@ -56,12 +200,50 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
     (s, r)
 }
 
-/// Creates a channel of bounded capacity.
+/// Creates a new synchronous, bounded channel.
+/// All data sent on the [`Sender`] will become available on the [`Receiver`]
+/// in the same order as it was sent. Like asynchronous [`channel`]s, the
+/// [`Receiver`] will block until a message becomes available. `sync_channel`
+/// differs greatly in the semantics of the sender, however.
+///
+/// This channel has an internal buffer on which messages will be queued.
+/// `bound` specifies the buffer size. When the internal buffer becomes full,
+/// future sends will *block* waiting for the buffer to open up. Note that a
+/// buffer size of 0 is valid, in which case this becomes "rendezvous channel"
+/// where each [`send`] will not return until a [`recv`] is paired with it.
+///
+/// The [`Sender`] can be cloned to [`send`] to the same channel multiple
+/// times. The [`Receiver`] also can be cloned to have multi receivers.
+///
+/// Like asynchronous channels, if the [`Receiver`] is disconnected while trying
+/// to [`send`] with the [`Sender`], the [`send`] method will return a
+/// [`SendError`]. Similarly, If the [`Sender`] is disconnected while trying
+/// to [`recv`], the [`recv`] method will return a [`RecvError`].
+///
+/// [`send`]: Sender::send
+/// [`recv`]: Receiver::recv
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::mpsc::sync_channel;
+/// use std::thread;
+///
+/// let (sender, receiver) = sync_channel(1);
 ///
-/// This channel has a buffer that can hold at most `cap` messages at a time.
+/// // this returns immediately
+/// sender.send(1).unwrap();
 ///
-/// A special case is zero-capacity channel, which cannot hold any messages. Instead, send and
-/// receive operations must appear at the same time in order to pair up and pass the message over.
+/// thread::spawn(move || {
+///     // this will block until the previous message has been received
+///     sender.send(2).unwrap();
+/// });
+///
+/// assert_eq!(receiver.recv().unwrap(), 1);
+/// assert_eq!(receiver.recv().unwrap(), 2);
+/// ```
+#[must_use]
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 pub fn sync_channel<T>(cap: usize) -> (Sender<T>, Receiver<T>) {
     if cap == 0 {
         let (s, r) = counter::new(zero::Channel::new());
@@ -76,7 +258,42 @@ pub fn sync_channel<T>(cap: usize) -> (Sender<T>, Receiver<T>) {
     }
 }
 
-/// The sending side of a channel.
+/// The sending-half of Rust's synchronous [`channel`] type.
+///
+/// Messages can be sent through this channel with [`send`].
+///
+/// Note: all senders (the original and its clones) need to be dropped for the receiver
+/// to stop blocking to receive messages with [`Receiver::recv`].
+///
+/// [`send`]: Sender::send
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+///
+/// let (sender, receiver) = channel();
+/// let sender2 = sender.clone();
+///
+/// // First thread owns sender
+/// thread::spawn(move || {
+///     sender.send(1).unwrap();
+/// });
+///
+/// // Second thread owns sender2
+/// thread::spawn(move || {
+///     sender2.send(2).unwrap();
+/// });
+///
+/// let msg = receiver.recv().unwrap();
+/// let msg2 = receiver.recv().unwrap();
+///
+/// assert_eq!(3, msg + msg2);
+/// ```
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 pub struct Sender<T> {
     flavor: SenderFlavor<T>,
 }
@@ -93,10 +310,14 @@ enum SenderFlavor<T> {
     Zero(counter::Sender<zero::Channel<T>>),
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 unsafe impl<T: Send> Send for Sender<T> {}
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 unsafe impl<T: Send> Sync for Sender<T> {}
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> UnwindSafe for Sender<T> {}
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> RefUnwindSafe for Sender<T> {}
 
 impl<T> Sender<T> {
@@ -107,6 +328,19 @@ impl<T> Sender<T> {
     ///
     /// If called on a zero-capacity channel, this method will send the message only if there
     /// happens to be a receive operation on the other side of the channel at the same time.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::{channel, Receiver, Sender};
+    ///
+    /// let (sender, _receiver): (Sender<i32>, Receiver<i32>) = channel();
+    ///
+    /// assert!(sender.try_send(1).is_ok());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn try_send(&self, msg: T) -> Result<(), TrySendError<T>> {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.try_send(msg),
@@ -115,14 +349,36 @@ impl<T> Sender<T> {
         }
     }
 
-    /// Blocks the current thread until a message is sent or the channel is disconnected.
+    /// Attempts to send a value on this channel, returning it back if it could
+    /// not be sent.
     ///
-    /// If the channel is full and not disconnected, this call will block until the send operation
-    /// can proceed. If the channel becomes disconnected, this call will wake up and return an
-    /// error. The returned error contains the original message.
+    /// A successful send occurs when it is determined that the other end of
+    /// the channel has not hung up already. An unsuccessful send would be one
+    /// where the corresponding receiver has already been deallocated. Note
+    /// that a return value of [`Err`] means that the data will never be
+    /// received, but a return value of [`Ok`] does *not* mean that the data
+    /// will be received. It is possible for the corresponding receiver to
+    /// hang up immediately after this function returns [`Ok`].
     ///
-    /// If called on a zero-capacity channel, this method will wait for a receive operation to
-    /// appear on the other side of the channel.
+    /// This method will never block the current thread.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    ///
+    /// let (tx, rx) = channel();
+    ///
+    /// // This send is always successful
+    /// tx.send(1).unwrap();
+    ///
+    /// // This send will fail because the receiver is gone
+    /// drop(rx);
+    /// assert!(tx.send(1).is_err());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn send(&self, msg: T) -> Result<(), SendError<T>> {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.send(msg, None),
@@ -136,10 +392,6 @@ impl<T> Sender<T> {
     }
 }
 
-// The methods below are not used by `sync::mpsc`, but
-// are useful and we'll likely want to expose them
-// eventually
-#[allow(unused)]
 impl<T> Sender<T> {
     /// Waits for a message to be sent into the channel, but only for a limited time.
     ///
@@ -149,6 +401,20 @@ impl<T> Sender<T> {
     ///
     /// If called on a zero-capacity channel, this method will wait for a receive operation to
     /// appear on the other side of the channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    /// use std::time::Duration;
+    ///
+    /// let (tx, rx) = channel();
+    ///
+    /// tx.send_timeout(1, Duration::from_millis(400)).unwrap();
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn send_timeout(&self, msg: T, timeout: Duration) -> Result<(), SendTimeoutError<T>> {
         match Instant::now().checked_add(timeout) {
             Some(deadline) => self.send_deadline(msg, deadline),
@@ -165,6 +431,21 @@ impl<T> Sender<T> {
     ///
     /// If called on a zero-capacity channel, this method will wait for a receive operation to
     /// appear on the other side of the channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    /// use std::time::{Duration, Instant};
+    ///
+    /// let (tx, rx) = channel();
+    ///
+    /// let t = Instant::now() + Duration::from_millis(400);
+    /// tx.send_deadline(1, t).unwrap();
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn send_deadline(&self, msg: T, deadline: Instant) -> Result<(), SendTimeoutError<T>> {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.send(msg, Some(deadline)),
@@ -176,6 +457,31 @@ impl<T> Sender<T> {
     /// Returns `true` if the channel is empty.
     ///
     /// Note: Zero-capacity channels are always empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, _recv) = mpmc::channel();
+    ///
+    /// let tx1 = send.clone();
+    /// let tx2 = send.clone();
+    ///
+    /// assert!(tx1.is_empty());
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     tx2.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert!(!tx1.is_empty());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn is_empty(&self) -> bool {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.is_empty(),
@@ -187,6 +493,29 @@ impl<T> Sender<T> {
     /// Returns `true` if the channel is full.
     ///
     /// Note: Zero-capacity channels are always full.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, _recv) = mpmc::sync_channel(1);
+    ///
+    /// let (tx1, tx2) = (send.clone(), send.clone());
+    /// assert!(!tx1.is_full());
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     tx2.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert!(tx1.is_full());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn is_full(&self) -> bool {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.is_full(),
@@ -196,6 +525,29 @@ impl<T> Sender<T> {
     }
 
     /// Returns the number of messages in the channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, _recv) = mpmc::channel();
+    /// let (tx1, tx2) = (send.clone(), send.clone());
+    ///
+    /// assert_eq!(tx1.len(), 0);
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     tx2.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(tx1.len(), 1);
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn len(&self) -> usize {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.len(),
@@ -205,6 +557,29 @@ impl<T> Sender<T> {
     }
 
     /// If the channel is bounded, returns its capacity.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, _recv) = mpmc::sync_channel(3);
+    /// let (tx1, tx2) = (send.clone(), send.clone());
+    ///
+    /// assert_eq!(tx1.capacity(), Some(3));
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     tx2.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(tx1.capacity(), Some(3));
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn capacity(&self) -> Option<usize> {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.capacity(),
@@ -214,6 +589,21 @@ impl<T> Sender<T> {
     }
 
     /// Returns `true` if senders belong to the same channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    ///
+    /// let (tx1, _) = mpmc::channel::<i32>();
+    /// let (tx2, _) = mpmc::channel::<i32>();
+    ///
+    /// assert!(tx1.same_channel(&tx1));
+    /// assert!(!tx1.same_channel(&tx2));
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn same_channel(&self, other: &Sender<T>) -> bool {
         match (&self.flavor, &other.flavor) {
             (SenderFlavor::Array(ref a), SenderFlavor::Array(ref b)) => a == b,
@@ -224,6 +614,7 @@ impl<T> Sender<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> Drop for Sender<T> {
     fn drop(&mut self) {
         unsafe {
@@ -236,6 +627,7 @@ impl<T> Drop for Sender<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> Clone for Sender<T> {
     fn clone(&self) -> Self {
         let flavor = match &self.flavor {
@@ -248,17 +640,216 @@ impl<T> Clone for Sender<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> fmt::Debug for Sender<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.pad("Sender { .. }")
     }
 }
 
-/// The receiving side of a channel.
+/// The receiving half of Rust's [`channel`] (or [`sync_channel`]) type.
+/// Different threads can share this [`Sender`] by cloning it.
+///
+/// Messages sent to the channel can be retrieved using [`recv`].
+///
+/// [`recv`]: Receiver::recv
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+/// use std::time::Duration;
+///
+/// let (send, recv) = channel();
+///
+/// let tx_thread = thread::spawn(move || {
+///     send.send("Hello world!").unwrap();
+///     thread::sleep(Duration::from_secs(2)); // block for two seconds
+///     send.send("Delayed for 2 seconds").unwrap();
+/// });
+///
+/// let (rx1, rx2) = (recv.clone(), recv.clone());
+/// let rx_thread_1 = thread::spawn(move || {
+///     println!("{}", rx1.recv().unwrap()); // Received immediately
+/// });
+/// let rx_thread_2 = thread::spawn(move || {
+///     println!("{}", rx2.recv().unwrap()); // Received after 2 seconds
+/// });
+///
+/// tx_thread.join().unwrap();
+/// rx_thread_1.join().unwrap();
+/// rx_thread_2.join().unwrap();
+/// ```
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 pub struct Receiver<T> {
     flavor: ReceiverFlavor<T>,
 }
 
+/// An iterator over messages on a [`Receiver`], created by [`iter`].
+///
+/// This iterator will block whenever [`next`] is called,
+/// waiting for a new message, and [`None`] will be returned
+/// when the corresponding channel has hung up.
+///
+/// [`iter`]: Receiver::iter
+/// [`next`]: Iterator::next
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+///
+/// let (send, recv) = channel();
+///
+/// thread::spawn(move || {
+///     send.send(1u8).unwrap();
+///     send.send(2u8).unwrap();
+///     send.send(3u8).unwrap();
+/// });
+///
+/// for x in recv.iter() {
+///     println!("Got: {x}");
+/// }
+/// ```
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+#[derive(Debug)]
+pub struct Iter<'a, T: 'a> {
+    rx: &'a Receiver<T>,
+}
+
+/// An iterator that attempts to yield all pending values for a [`Receiver`],
+/// created by [`try_iter`].
+///
+/// [`None`] will be returned when there are no pending values remaining or
+/// if the corresponding channel has hung up.
+///
+/// This iterator will never block the caller in order to wait for data to
+/// become available. Instead, it will return [`None`].
+///
+/// [`try_iter`]: Receiver::try_iter
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+/// use std::time::Duration;
+///
+/// let (sender, receiver) = channel();
+///
+/// // Nothing is in the buffer yet
+/// assert!(receiver.try_iter().next().is_none());
+/// println!("Nothing in the buffer...");
+///
+/// thread::spawn(move || {
+///     sender.send(1).unwrap();
+///     sender.send(2).unwrap();
+///     sender.send(3).unwrap();
+/// });
+///
+/// println!("Going to sleep...");
+/// thread::sleep(Duration::from_secs(2)); // block for two seconds
+///
+/// for x in receiver.try_iter() {
+///     println!("Got: {x}");
+/// }
+/// ```
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+#[derive(Debug)]
+pub struct TryIter<'a, T: 'a> {
+    rx: &'a Receiver<T>,
+}
+
+/// An owning iterator over messages on a [`Receiver`],
+/// created by [`into_iter`].
+///
+/// This iterator will block whenever [`next`]
+/// is called, waiting for a new message, and [`None`] will be
+/// returned if the corresponding channel has hung up.
+///
+/// [`into_iter`]: Receiver::into_iter
+/// [`next`]: Iterator::next
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+///
+/// let (send, recv) = channel();
+///
+/// thread::spawn(move || {
+///     send.send(1u8).unwrap();
+///     send.send(2u8).unwrap();
+///     send.send(3u8).unwrap();
+/// });
+///
+/// for x in recv.into_iter() {
+///     println!("Got: {x}");
+/// }
+/// ```
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+#[derive(Debug)]
+pub struct IntoIter<T> {
+    rx: Receiver<T>,
+}
+
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+impl<'a, T> Iterator for Iter<'a, T> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<T> {
+        self.rx.recv().ok()
+    }
+}
+
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+impl<'a, T> Iterator for TryIter<'a, T> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<T> {
+        self.rx.try_recv().ok()
+    }
+}
+
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+impl<'a, T> IntoIterator for &'a Receiver<T> {
+    type Item = T;
+    type IntoIter = Iter<'a, T>;
+
+    fn into_iter(self) -> Iter<'a, T> {
+        self.iter()
+    }
+}
+
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+impl<T> Iterator for IntoIter<T> {
+    type Item = T;
+    fn next(&mut self) -> Option<T> {
+        self.rx.recv().ok()
+    }
+}
+
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+impl<T> IntoIterator for Receiver<T> {
+    type Item = T;
+    type IntoIter = IntoIter<T>;
+
+    fn into_iter(self) -> IntoIter<T> {
+        IntoIter { rx: self }
+    }
+}
+
 /// Receiver flavors.
 enum ReceiverFlavor<T> {
     /// Bounded channel based on a preallocated array.
@@ -271,20 +862,46 @@ enum ReceiverFlavor<T> {
     Zero(counter::Receiver<zero::Channel<T>>),
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 unsafe impl<T: Send> Send for Receiver<T> {}
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 unsafe impl<T: Send> Sync for Receiver<T> {}
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> UnwindSafe for Receiver<T> {}
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> RefUnwindSafe for Receiver<T> {}
 
 impl<T> Receiver<T> {
     /// Attempts to receive a message from the channel without blocking.
     ///
-    /// This method will either receive a message from the channel immediately or return an error
-    /// if the channel is empty.
+    /// This method will never block the caller in order to wait for data to
+    /// become available. Instead, this will always return immediately with a
+    /// possible option of pending data on the channel.
     ///
     /// If called on a zero-capacity channel, this method will receive a message only if there
     /// happens to be a send operation on the other side of the channel at the same time.
+    ///
+    /// This is useful for a flavor of "optimistic check" before deciding to
+    /// block on a receiver.
+    ///
+    /// Compared with [`recv`], this function has two failure cases instead of one
+    /// (one for disconnection, one for an empty buffer).
+    ///
+    /// [`recv`]: Self::recv
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::{Receiver, channel};
+    ///
+    /// let (_, receiver): (_, Receiver<i32>) = channel();
+    ///
+    /// assert!(receiver.try_recv().is_err());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn try_recv(&self) -> Result<T, TryRecvError> {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.try_recv(),
@@ -293,15 +910,64 @@ impl<T> Receiver<T> {
         }
     }
 
-    /// Blocks the current thread until a message is received or the channel is empty and
-    /// disconnected.
+    /// Attempts to wait for a value on this receiver, returning an error if the
+    /// corresponding channel has hung up.
     ///
-    /// If the channel is empty and not disconnected, this call will block until the receive
-    /// operation can proceed. If the channel is empty and becomes disconnected, this call will
-    /// wake up and return an error.
+    /// This function will always block the current thread if there is no data
+    /// available and it's possible for more data to be sent (at least one sender
+    /// still exists). Once a message is sent to the corresponding [`Sender`],
+    /// this receiver will wake up and return that message.
     ///
-    /// If called on a zero-capacity channel, this method will wait for a send operation to appear
-    /// on the other side of the channel.
+    /// If the corresponding [`Sender`] has disconnected, or it disconnects while
+    /// this call is blocking, this call will wake up and return [`Err`] to
+    /// indicate that no more messages can ever be received on this channel.
+    /// However, since channels are buffered, messages sent before the disconnect
+    /// will still be properly received.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(Ok(1), recv.recv());
+    /// ```
+    ///
+    /// Buffering behavior:
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    /// use std::sync::mpmc::RecvError;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    ///     send.send(2).unwrap();
+    ///     send.send(3).unwrap();
+    ///     drop(send);
+    /// });
+    ///
+    /// // wait for the thread to join so we ensure the sender is dropped
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(Ok(1), recv.recv());
+    /// assert_eq!(Ok(2), recv.recv());
+    /// assert_eq!(Ok(3), recv.recv());
+    /// assert_eq!(Err(RecvError), recv.recv());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn recv(&self) -> Result<T, RecvError> {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.recv(None),
@@ -311,14 +977,65 @@ impl<T> Receiver<T> {
         .map_err(|_| RecvError)
     }
 
-    /// Waits for a message to be received from the channel, but only for a limited time.
+    /// Attempts to wait for a value on this receiver, returning an error if the
+    /// corresponding channel has hung up, or if it waits more than `timeout`.
+    ///
+    /// This function will always block the current thread if there is no data
+    /// available and it's possible for more data to be sent (at least one sender
+    /// still exists). Once a message is sent to the corresponding [`Sender`],
+    /// this receiver will wake up and return that message.
+    ///
+    /// If the corresponding [`Sender`] has disconnected, or it disconnects while
+    /// this call is blocking, this call will wake up and return [`Err`] to
+    /// indicate that no more messages can ever be received on this channel.
+    /// However, since channels are buffered, messages sent before the disconnect
+    /// will still be properly received.
+    ///
+    /// # Examples
+    ///
+    /// Successfully receiving value before encountering timeout:
     ///
-    /// If the channel is empty and not disconnected, this call will block until the receive
-    /// operation can proceed or the operation times out. If the channel is empty and becomes
-    /// disconnected, this call will wake up and return an error.
+    /// ```no_run
+    /// #![feature(mpmc_channel)]
     ///
-    /// If called on a zero-capacity channel, this method will wait for a send operation to appear
-    /// on the other side of the channel.
+    /// use std::thread;
+    /// use std::time::Duration;
+    /// use std::sync::mpmc;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    ///
+    /// thread::spawn(move || {
+    ///     send.send('a').unwrap();
+    /// });
+    ///
+    /// assert_eq!(
+    ///     recv.recv_timeout(Duration::from_millis(400)),
+    ///     Ok('a')
+    /// );
+    /// ```
+    ///
+    /// Receiving an error upon reaching timeout:
+    ///
+    /// ```no_run
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::thread;
+    /// use std::time::Duration;
+    /// use std::sync::mpmc;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    ///
+    /// thread::spawn(move || {
+    ///     thread::sleep(Duration::from_millis(800));
+    ///     send.send('a').unwrap();
+    /// });
+    ///
+    /// assert_eq!(
+    ///     recv.recv_timeout(Duration::from_millis(400)),
+    ///     Err(mpmc::RecvTimeoutError::Timeout)
+    /// );
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvTimeoutError> {
         match Instant::now().checked_add(timeout) {
             Some(deadline) => self.recv_deadline(deadline),
@@ -327,14 +1044,65 @@ impl<T> Receiver<T> {
         }
     }
 
-    /// Waits for a message to be received from the channel, but only for a limited time.
+    /// Attempts to wait for a value on this receiver, returning an error if the
+    /// corresponding channel has hung up, or if `deadline` is reached.
+    ///
+    /// This function will always block the current thread if there is no data
+    /// available and it's possible for more data to be sent. Once a message is
+    /// sent to the corresponding [`Sender`], then this receiver will wake up
+    /// and return that message.
+    ///
+    /// If the corresponding [`Sender`] has disconnected, or it disconnects while
+    /// this call is blocking, this call will wake up and return [`Err`] to
+    /// indicate that no more messages can ever be received on this channel.
+    /// However, since channels are buffered, messages sent before the disconnect
+    /// will still be properly received.
+    ///
+    /// # Examples
+    ///
+    /// Successfully receiving value before reaching deadline:
+    ///
+    /// ```no_run
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::thread;
+    /// use std::time::{Duration, Instant};
+    /// use std::sync::mpmc;
     ///
-    /// If the channel is empty and not disconnected, this call will block until the receive
-    /// operation can proceed or the operation times out. If the channel is empty and becomes
-    /// disconnected, this call will wake up and return an error.
+    /// let (send, recv) = mpmc::channel();
     ///
-    /// If called on a zero-capacity channel, this method will wait for a send operation to appear
-    /// on the other side of the channel.
+    /// thread::spawn(move || {
+    ///     send.send('a').unwrap();
+    /// });
+    ///
+    /// assert_eq!(
+    ///     recv.recv_deadline(Instant::now() + Duration::from_millis(400)),
+    ///     Ok('a')
+    /// );
+    /// ```
+    ///
+    /// Receiving an error upon reaching deadline:
+    ///
+    /// ```no_run
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::thread;
+    /// use std::time::{Duration, Instant};
+    /// use std::sync::mpmc;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    ///
+    /// thread::spawn(move || {
+    ///     thread::sleep(Duration::from_millis(800));
+    ///     send.send('a').unwrap();
+    /// });
+    ///
+    /// assert_eq!(
+    ///     recv.recv_deadline(Instant::now() + Duration::from_millis(400)),
+    ///     Err(mpmc::RecvTimeoutError::Timeout)
+    /// );
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn recv_deadline(&self, deadline: Instant) -> Result<T, RecvTimeoutError> {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.recv(Some(deadline)),
@@ -342,16 +1110,77 @@ impl<T> Receiver<T> {
             ReceiverFlavor::Zero(chan) => chan.recv(Some(deadline)),
         }
     }
+
+    /// Returns an iterator that will attempt to yield all pending values.
+    /// It will return `None` if there are no more pending values or if the
+    /// channel has hung up. The iterator will never [`panic!`] or block the
+    /// user by waiting for values.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    /// use std::thread;
+    /// use std::time::Duration;
+    ///
+    /// let (sender, receiver) = channel();
+    ///
+    /// // nothing is in the buffer yet
+    /// assert!(receiver.try_iter().next().is_none());
+    ///
+    /// thread::spawn(move || {
+    ///     thread::sleep(Duration::from_secs(1));
+    ///     sender.send(1).unwrap();
+    ///     sender.send(2).unwrap();
+    ///     sender.send(3).unwrap();
+    /// });
+    ///
+    /// // nothing is in the buffer yet
+    /// assert!(receiver.try_iter().next().is_none());
+    ///
+    /// // block for two seconds
+    /// thread::sleep(Duration::from_secs(2));
+    ///
+    /// let mut iter = receiver.try_iter();
+    /// assert_eq!(iter.next(), Some(1));
+    /// assert_eq!(iter.next(), Some(2));
+    /// assert_eq!(iter.next(), Some(3));
+    /// assert_eq!(iter.next(), None);
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
+    pub fn try_iter(&self) -> TryIter<'_, T> {
+        TryIter { rx: self }
+    }
 }
 
-// The methods below are not used by `sync::mpsc`, but
-// are useful and we'll likely want to expose them
-// eventually
-#[allow(unused)]
 impl<T> Receiver<T> {
     /// Returns `true` if the channel is empty.
     ///
     /// Note: Zero-capacity channels are always empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    ///
+    /// assert!(recv.is_empty());
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert!(!recv.is_empty());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn is_empty(&self) -> bool {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.is_empty(),
@@ -363,6 +1192,28 @@ impl<T> Receiver<T> {
     /// Returns `true` if the channel is full.
     ///
     /// Note: Zero-capacity channels are always full.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = mpmc::sync_channel(1);
+    ///
+    /// assert!(!recv.is_full());
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert!(recv.is_full());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn is_full(&self) -> bool {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.is_full(),
@@ -372,6 +1223,28 @@ impl<T> Receiver<T> {
     }
 
     /// Returns the number of messages in the channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    ///
+    /// assert_eq!(recv.len(), 0);
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(recv.len(), 1);
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn len(&self) -> usize {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.len(),
@@ -381,6 +1254,28 @@ impl<T> Receiver<T> {
     }
 
     /// If the channel is bounded, returns its capacity.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = mpmc::sync_channel(3);
+    ///
+    /// assert_eq!(recv.capacity(), Some(3));
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(recv.capacity(), Some(3));
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn capacity(&self) -> Option<usize> {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.capacity(),
@@ -390,6 +1285,21 @@ impl<T> Receiver<T> {
     }
 
     /// Returns `true` if receivers belong to the same channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    ///
+    /// let (_, rx1) = mpmc::channel::<i32>();
+    /// let (_, rx2) = mpmc::channel::<i32>();
+    ///
+    /// assert!(rx1.same_channel(&rx1));
+    /// assert!(!rx1.same_channel(&rx2));
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn same_channel(&self, other: &Receiver<T>) -> bool {
         match (&self.flavor, &other.flavor) {
             (ReceiverFlavor::Array(a), ReceiverFlavor::Array(b)) => a == b,
@@ -398,8 +1308,39 @@ impl<T> Receiver<T> {
             _ => false,
         }
     }
+
+    /// Returns an iterator that will block waiting for messages, but never
+    /// [`panic!`]. It will return [`None`] when the channel has hung up.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = channel();
+    ///
+    /// thread::spawn(move || {
+    ///     send.send(1).unwrap();
+    ///     send.send(2).unwrap();
+    ///     send.send(3).unwrap();
+    /// });
+    ///
+    /// let mut iter = recv.iter();
+    /// assert_eq!(iter.next(), Some(1));
+    /// assert_eq!(iter.next(), Some(2));
+    /// assert_eq!(iter.next(), Some(3));
+    /// assert_eq!(iter.next(), None);
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
+    pub fn iter(&self) -> Iter<'_, T> {
+        Iter { rx: self }
+    }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> Drop for Receiver<T> {
     fn drop(&mut self) {
         unsafe {
@@ -412,6 +1353,7 @@ impl<T> Drop for Receiver<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> Clone for Receiver<T> {
     fn clone(&self) -> Self {
         let flavor = match &self.flavor {
@@ -424,6 +1366,7 @@ impl<T> Clone for Receiver<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> fmt::Debug for Receiver<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.pad("Receiver { .. }")
diff --git a/library/std/src/sync/mpmc/tests.rs b/library/std/src/sync/mpmc/tests.rs
new file mode 100644
index 00000000000..ab14050df6c
--- /dev/null
+++ b/library/std/src/sync/mpmc/tests.rs
@@ -0,0 +1,728 @@
+use super::*;
+use crate::{env, thread};
+
+pub fn stress_factor() -> usize {
+    match env::var("RUST_TEST_STRESS") {
+        Ok(val) => val.parse().unwrap(),
+        Err(..) => 1,
+    }
+}
+
+#[test]
+fn smoke() {
+    let (tx, rx) = channel::<i32>();
+    tx.send(1).unwrap();
+    assert_eq!(rx.recv().unwrap(), 1);
+}
+
+#[test]
+fn drop_full() {
+    let (tx, _rx) = channel::<Box<isize>>();
+    tx.send(Box::new(1)).unwrap();
+}
+
+#[test]
+fn drop_full_shared() {
+    let (tx, _rx) = channel::<Box<isize>>();
+    drop(tx.clone());
+    drop(tx.clone());
+    tx.send(Box::new(1)).unwrap();
+}
+
+#[test]
+fn smoke_shared() {
+    let (tx, rx) = channel::<i32>();
+    tx.send(1).unwrap();
+    assert_eq!(rx.recv().unwrap(), 1);
+    let tx = tx.clone();
+    tx.send(1).unwrap();
+    assert_eq!(rx.recv().unwrap(), 1);
+}
+
+#[test]
+fn smoke_threads() {
+    let (tx, rx) = channel::<i32>();
+    let t1 = thread::spawn(move || {
+        for i in 0..2 {
+            tx.send(i).unwrap();
+        }
+    });
+    let t2 = thread::spawn(move || {
+        assert_eq!(rx.recv().unwrap(), 0);
+        assert_eq!(rx.recv().unwrap(), 1);
+    });
+    t1.join().unwrap();
+    t2.join().unwrap();
+}
+
+#[test]
+fn smoke_port_gone() {
+    let (tx, rx) = channel::<i32>();
+    drop(rx);
+    assert!(tx.send(1).is_err());
+}
+
+#[test]
+fn smoke_shared_port_gone() {
+    let (tx, rx) = channel::<i32>();
+    drop(rx);
+    assert!(tx.send(1).is_err())
+}
+
+#[test]
+fn smoke_shared_port_gone2() {
+    let (tx, rx) = channel::<i32>();
+    drop(rx);
+    let tx2 = tx.clone();
+    drop(tx);
+    assert!(tx2.send(1).is_err());
+}
+
+#[test]
+fn port_gone_concurrent() {
+    let (tx, rx) = channel::<i32>();
+    let _t = thread::spawn(move || {
+        rx.recv().unwrap();
+    });
+    while tx.send(1).is_ok() {}
+}
+
+#[test]
+fn port_gone_concurrent_shared() {
+    let (tx, rx) = channel::<i32>();
+    let tx2 = tx.clone();
+    let _t = thread::spawn(move || {
+        rx.recv().unwrap();
+    });
+    while tx.send(1).is_ok() && tx2.send(1).is_ok() {}
+}
+
+#[test]
+fn smoke_chan_gone() {
+    let (tx, rx) = channel::<i32>();
+    drop(tx);
+    assert!(rx.recv().is_err());
+}
+
+#[test]
+fn smoke_chan_gone_shared() {
+    let (tx, rx) = channel::<()>();
+    let tx2 = tx.clone();
+    drop(tx);
+    drop(tx2);
+    assert!(rx.recv().is_err());
+}
+
+#[test]
+fn chan_gone_concurrent() {
+    let (tx, rx) = channel::<i32>();
+    let _t = thread::spawn(move || {
+        tx.send(1).unwrap();
+        tx.send(1).unwrap();
+    });
+    while rx.recv().is_ok() {}
+}
+
+#[test]
+fn stress() {
+    let count = if cfg!(miri) { 100 } else { 10000 };
+    let (tx, rx) = channel::<i32>();
+    let t = thread::spawn(move || {
+        for _ in 0..count {
+            tx.send(1).unwrap();
+        }
+    });
+    for _ in 0..count {
+        assert_eq!(rx.recv().unwrap(), 1);
+    }
+    t.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn stress_shared() {
+    const AMT: u32 = if cfg!(miri) { 100 } else { 10000 };
+    const NTHREADS: u32 = 8;
+    let (tx, rx) = channel::<i32>();
+
+    let t = thread::spawn(move || {
+        for _ in 0..AMT * NTHREADS {
+            assert_eq!(rx.recv().unwrap(), 1);
+        }
+        match rx.try_recv() {
+            Ok(..) => panic!(),
+            _ => {}
+        }
+    });
+
+    for _ in 0..NTHREADS {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            for _ in 0..AMT {
+                tx.send(1).unwrap();
+            }
+        });
+    }
+    drop(tx);
+    t.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn send_from_outside_runtime() {
+    let (tx1, rx1) = channel::<()>();
+    let (tx2, rx2) = channel::<i32>();
+    let t1 = thread::spawn(move || {
+        tx1.send(()).unwrap();
+        for _ in 0..40 {
+            assert_eq!(rx2.recv().unwrap(), 1);
+        }
+    });
+    rx1.recv().unwrap();
+    let t2 = thread::spawn(move || {
+        for _ in 0..40 {
+            tx2.send(1).unwrap();
+        }
+    });
+    t1.join().ok().expect("thread panicked");
+    t2.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn recv_from_outside_runtime() {
+    let (tx, rx) = channel::<i32>();
+    let t = thread::spawn(move || {
+        for _ in 0..40 {
+            assert_eq!(rx.recv().unwrap(), 1);
+        }
+    });
+    for _ in 0..40 {
+        tx.send(1).unwrap();
+    }
+    t.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn no_runtime() {
+    let (tx1, rx1) = channel::<i32>();
+    let (tx2, rx2) = channel::<i32>();
+    let t1 = thread::spawn(move || {
+        assert_eq!(rx1.recv().unwrap(), 1);
+        tx2.send(2).unwrap();
+    });
+    let t2 = thread::spawn(move || {
+        tx1.send(1).unwrap();
+        assert_eq!(rx2.recv().unwrap(), 2);
+    });
+    t1.join().ok().expect("thread panicked");
+    t2.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn oneshot_single_thread_close_port_first() {
+    // Simple test of closing without sending
+    let (_tx, rx) = channel::<i32>();
+    drop(rx);
+}
+
+#[test]
+fn oneshot_single_thread_close_chan_first() {
+    // Simple test of closing without sending
+    let (tx, _rx) = channel::<i32>();
+    drop(tx);
+}
+
+#[test]
+fn oneshot_single_thread_send_port_close() {
+    // Testing that the sender cleans up the payload if receiver is closed
+    let (tx, rx) = channel::<Box<i32>>();
+    drop(rx);
+    assert!(tx.send(Box::new(0)).is_err());
+}
+
+#[test]
+fn oneshot_single_thread_recv_chan_close() {
+    // Receiving on a closed chan will panic
+    let res = thread::spawn(move || {
+        let (tx, rx) = channel::<i32>();
+        drop(tx);
+        rx.recv().unwrap();
+    })
+    .join();
+    // What is our res?
+    assert!(res.is_err());
+}
+
+#[test]
+fn oneshot_single_thread_send_then_recv() {
+    let (tx, rx) = channel::<Box<i32>>();
+    tx.send(Box::new(10)).unwrap();
+    assert!(*rx.recv().unwrap() == 10);
+}
+
+#[test]
+fn oneshot_single_thread_try_send_open() {
+    let (tx, rx) = channel::<i32>();
+    assert!(tx.send(10).is_ok());
+    assert!(rx.recv().unwrap() == 10);
+}
+
+#[test]
+fn oneshot_single_thread_try_send_closed() {
+    let (tx, rx) = channel::<i32>();
+    drop(rx);
+    assert!(tx.send(10).is_err());
+}
+
+#[test]
+fn oneshot_single_thread_try_recv_open() {
+    let (tx, rx) = channel::<i32>();
+    tx.send(10).unwrap();
+    assert!(rx.recv() == Ok(10));
+}
+
+#[test]
+fn oneshot_single_thread_try_recv_closed() {
+    let (tx, rx) = channel::<i32>();
+    drop(tx);
+    assert!(rx.recv().is_err());
+}
+
+#[test]
+fn oneshot_single_thread_peek_data() {
+    let (tx, rx) = channel::<i32>();
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
+    tx.send(10).unwrap();
+    assert_eq!(rx.try_recv(), Ok(10));
+}
+
+#[test]
+fn oneshot_single_thread_peek_close() {
+    let (tx, rx) = channel::<i32>();
+    drop(tx);
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
+}
+
+#[test]
+fn oneshot_single_thread_peek_open() {
+    let (_tx, rx) = channel::<i32>();
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
+}
+
+#[test]
+fn oneshot_multi_task_recv_then_send() {
+    let (tx, rx) = channel::<Box<i32>>();
+    let _t = thread::spawn(move || {
+        assert!(*rx.recv().unwrap() == 10);
+    });
+
+    tx.send(Box::new(10)).unwrap();
+}
+
+#[test]
+fn oneshot_multi_task_recv_then_close() {
+    let (tx, rx) = channel::<Box<i32>>();
+    let _t = thread::spawn(move || {
+        drop(tx);
+    });
+    let res = thread::spawn(move || {
+        assert!(*rx.recv().unwrap() == 10);
+    })
+    .join();
+    assert!(res.is_err());
+}
+
+#[test]
+fn oneshot_multi_thread_close_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel::<i32>();
+        let _t = thread::spawn(move || {
+            drop(rx);
+        });
+        drop(tx);
+    }
+}
+
+#[test]
+fn oneshot_multi_thread_send_close_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel::<i32>();
+        let _t = thread::spawn(move || {
+            drop(rx);
+        });
+        let _ = thread::spawn(move || {
+            tx.send(1).unwrap();
+        })
+        .join();
+    }
+}
+
+#[test]
+fn oneshot_multi_thread_recv_close_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel::<i32>();
+        thread::spawn(move || {
+            let res = thread::spawn(move || {
+                rx.recv().unwrap();
+            })
+            .join();
+            assert!(res.is_err());
+        });
+        let _t = thread::spawn(move || {
+            thread::spawn(move || {
+                drop(tx);
+            });
+        });
+    }
+}
+
+#[test]
+fn oneshot_multi_thread_send_recv_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel::<Box<isize>>();
+        let _t = thread::spawn(move || {
+            tx.send(Box::new(10)).unwrap();
+        });
+        assert!(*rx.recv().unwrap() == 10);
+    }
+}
+
+#[test]
+fn stream_send_recv_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel();
+
+        send(tx, 0);
+        recv(rx, 0);
+
+        fn send(tx: Sender<Box<i32>>, i: i32) {
+            if i == 10 {
+                return;
+            }
+
+            thread::spawn(move || {
+                tx.send(Box::new(i)).unwrap();
+                send(tx, i + 1);
+            });
+        }
+
+        fn recv(rx: Receiver<Box<i32>>, i: i32) {
+            if i == 10 {
+                return;
+            }
+
+            thread::spawn(move || {
+                assert!(*rx.recv().unwrap() == i);
+                recv(rx, i + 1);
+            });
+        }
+    }
+}
+
+#[test]
+fn oneshot_single_thread_recv_timeout() {
+    let (tx, rx) = channel();
+    tx.send(()).unwrap();
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
+    tx.send(()).unwrap();
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+}
+
+#[test]
+fn stress_recv_timeout_two_threads() {
+    let (tx, rx) = channel();
+    let stress = stress_factor() + 100;
+    let timeout = Duration::from_millis(100);
+
+    thread::spawn(move || {
+        for i in 0..stress {
+            if i % 2 == 0 {
+                thread::sleep(timeout * 2);
+            }
+            tx.send(1usize).unwrap();
+        }
+    });
+
+    let mut recv_count = 0;
+    loop {
+        match rx.recv_timeout(timeout) {
+            Ok(n) => {
+                assert_eq!(n, 1usize);
+                recv_count += 1;
+            }
+            Err(RecvTimeoutError::Timeout) => continue,
+            Err(RecvTimeoutError::Disconnected) => break,
+        }
+    }
+
+    assert_eq!(recv_count, stress);
+}
+
+#[test]
+fn recv_timeout_upgrade() {
+    let (tx, rx) = channel::<()>();
+    let timeout = Duration::from_millis(1);
+    let _tx_clone = tx.clone();
+
+    let start = Instant::now();
+    assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout));
+    assert!(Instant::now() >= start + timeout);
+}
+
+#[test]
+fn stress_recv_timeout_shared() {
+    let (tx, rx) = channel();
+    let stress = stress_factor() + 100;
+
+    for i in 0..stress {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            thread::sleep(Duration::from_millis(i as u64 * 10));
+            tx.send(1usize).unwrap();
+        });
+    }
+
+    drop(tx);
+
+    let mut recv_count = 0;
+    loop {
+        match rx.recv_timeout(Duration::from_millis(10)) {
+            Ok(n) => {
+                assert_eq!(n, 1usize);
+                recv_count += 1;
+            }
+            Err(RecvTimeoutError::Timeout) => continue,
+            Err(RecvTimeoutError::Disconnected) => break,
+        }
+    }
+
+    assert_eq!(recv_count, stress);
+}
+
+#[test]
+fn very_long_recv_timeout_wont_panic() {
+    let (tx, rx) = channel::<()>();
+    let join_handle = thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::MAX)));
+    thread::sleep(Duration::from_secs(1));
+    assert!(tx.send(()).is_ok());
+    assert_eq!(join_handle.join().unwrap(), Ok(()));
+}
+
+#[test]
+fn recv_a_lot() {
+    let count = if cfg!(miri) { 1000 } else { 10000 };
+    // Regression test that we don't run out of stack in scheduler context
+    let (tx, rx) = channel();
+    for _ in 0..count {
+        tx.send(()).unwrap();
+    }
+    for _ in 0..count {
+        rx.recv().unwrap();
+    }
+}
+
+#[test]
+fn shared_recv_timeout() {
+    let (tx, rx) = channel();
+    let total = 5;
+    for _ in 0..total {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            tx.send(()).unwrap();
+        });
+    }
+
+    for _ in 0..total {
+        rx.recv().unwrap();
+    }
+
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
+    tx.send(()).unwrap();
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+}
+
+#[test]
+fn shared_chan_stress() {
+    let (tx, rx) = channel();
+    let total = stress_factor() + 100;
+    for _ in 0..total {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            tx.send(()).unwrap();
+        });
+    }
+
+    for _ in 0..total {
+        rx.recv().unwrap();
+    }
+}
+
+#[test]
+fn test_nested_recv_iter() {
+    let (tx, rx) = channel::<i32>();
+    let (total_tx, total_rx) = channel::<i32>();
+
+    let _t = thread::spawn(move || {
+        let mut acc = 0;
+        for x in rx.iter() {
+            acc += x;
+        }
+        total_tx.send(acc).unwrap();
+    });
+
+    tx.send(3).unwrap();
+    tx.send(1).unwrap();
+    tx.send(2).unwrap();
+    drop(tx);
+    assert_eq!(total_rx.recv().unwrap(), 6);
+}
+
+#[test]
+fn test_recv_iter_break() {
+    let (tx, rx) = channel::<i32>();
+    let (count_tx, count_rx) = channel();
+
+    let _t = thread::spawn(move || {
+        let mut count = 0;
+        for x in rx.iter() {
+            if count >= 3 {
+                break;
+            } else {
+                count += x;
+            }
+        }
+        count_tx.send(count).unwrap();
+    });
+
+    tx.send(2).unwrap();
+    tx.send(2).unwrap();
+    tx.send(2).unwrap();
+    let _ = tx.send(2);
+    drop(tx);
+    assert_eq!(count_rx.recv().unwrap(), 4);
+}
+
+#[test]
+fn test_recv_try_iter() {
+    let (request_tx, request_rx) = channel();
+    let (response_tx, response_rx) = channel();
+
+    // Request `x`s until we have `6`.
+    let t = thread::spawn(move || {
+        let mut count = 0;
+        loop {
+            for x in response_rx.try_iter() {
+                count += x;
+                if count == 6 {
+                    return count;
+                }
+            }
+            request_tx.send(()).unwrap();
+        }
+    });
+
+    for _ in request_rx.iter() {
+        if response_tx.send(2).is_err() {
+            break;
+        }
+    }
+
+    assert_eq!(t.join().unwrap(), 6);
+}
+
+#[test]
+fn test_recv_into_iter_owned() {
+    let mut iter = {
+        let (tx, rx) = channel::<i32>();
+        tx.send(1).unwrap();
+        tx.send(2).unwrap();
+
+        rx.into_iter()
+    };
+    assert_eq!(iter.next().unwrap(), 1);
+    assert_eq!(iter.next().unwrap(), 2);
+    assert_eq!(iter.next().is_none(), true);
+}
+
+#[test]
+fn test_recv_into_iter_borrowed() {
+    let (tx, rx) = channel::<i32>();
+    tx.send(1).unwrap();
+    tx.send(2).unwrap();
+    drop(tx);
+    let mut iter = (&rx).into_iter();
+    assert_eq!(iter.next().unwrap(), 1);
+    assert_eq!(iter.next().unwrap(), 2);
+    assert_eq!(iter.next().is_none(), true);
+}
+
+#[test]
+fn try_recv_states() {
+    let (tx1, rx1) = channel::<i32>();
+    let (tx2, rx2) = channel::<()>();
+    let (tx3, rx3) = channel::<()>();
+    let _t = thread::spawn(move || {
+        rx2.recv().unwrap();
+        tx1.send(1).unwrap();
+        tx3.send(()).unwrap();
+        rx2.recv().unwrap();
+        drop(tx1);
+        tx3.send(()).unwrap();
+    });
+
+    assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
+    tx2.send(()).unwrap();
+    rx3.recv().unwrap();
+    assert_eq!(rx1.try_recv(), Ok(1));
+    assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
+    tx2.send(()).unwrap();
+    rx3.recv().unwrap();
+    assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected));
+}
+
+// This bug used to end up in a livelock inside of the Receiver destructor
+// because the internal state of the Shared packet was corrupted
+#[test]
+fn destroy_upgraded_shared_port_when_sender_still_active() {
+    let (tx, rx) = channel();
+    let (tx2, rx2) = channel();
+    let _t = thread::spawn(move || {
+        rx.recv().unwrap(); // wait on a oneshot
+        drop(rx); // destroy a shared
+        tx2.send(()).unwrap();
+    });
+    // make sure the other thread has gone to sleep
+    for _ in 0..5000 {
+        thread::yield_now();
+    }
+
+    // upgrade to a shared chan and send a message
+    let t = tx.clone();
+    drop(tx);
+    t.send(()).unwrap();
+
+    // wait for the child thread to exit before we exit
+    rx2.recv().unwrap();
+}
+
+#[test]
+fn issue_32114() {
+    let (tx, _) = channel();
+    let _ = tx.send(123);
+    assert_eq!(tx.send(123), Err(SendError(123)));
+}
+
+#[test]
+fn issue_39364() {
+    let (tx, rx) = channel::<()>();
+    let t = thread::spawn(move || {
+        thread::sleep(Duration::from_millis(300));
+        let _ = tx.clone();
+        // Don't drop; hand back to caller.
+        tx
+    });
+
+    let _ = rx.recv_timeout(Duration::from_millis(500));
+    let _tx = t.join().unwrap(); // delay dropping until end of test
+    let _ = rx.recv_timeout(Duration::from_millis(500));
+}
diff --git a/library/std/src/sync/mpmc/waker.rs b/library/std/src/sync/mpmc/waker.rs
index fb877887f9c..1895466f95d 100644
--- a/library/std/src/sync/mpmc/waker.rs
+++ b/library/std/src/sync/mpmc/waker.rs
@@ -3,8 +3,8 @@
 use super::context::Context;
 use super::select::{Operation, Selected};
 use crate::ptr;
-use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sync::Mutex;
+use crate::sync::atomic::{AtomicBool, Ordering};
 
 /// Represents a thread blocked on a specific channel operation.
 pub(crate) struct Entry {
diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs
index 2b82eeda3d5..446881291e6 100644
--- a/library/std/src/sync/mpmc/zero.rs
+++ b/library/std/src/sync/mpmc/zero.rs
@@ -9,8 +9,8 @@ use super::utils::Backoff;
 use super::waker::Waker;
 use crate::cell::UnsafeCell;
 use crate::marker::PhantomData;
-use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sync::Mutex;
+use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::time::Instant;
 use crate::{fmt, ptr};
 
@@ -185,11 +185,7 @@ impl<T> Channel<T> {
             // Prepare for blocking until a receiver wakes us up.
             let oper = Operation::hook(token);
             let mut packet = Packet::<T>::message_on_stack(msg);
-            inner.senders.register_with_packet(
-                oper,
-                core::ptr::addr_of_mut!(packet) as *mut (),
-                cx,
-            );
+            inner.senders.register_with_packet(oper, (&raw mut packet) as *mut (), cx);
             inner.receivers.notify();
             drop(inner);
 
@@ -256,11 +252,7 @@ impl<T> Channel<T> {
             // Prepare for blocking until a sender wakes us up.
             let oper = Operation::hook(token);
             let mut packet = Packet::<T>::empty_on_stack();
-            inner.receivers.register_with_packet(
-                oper,
-                core::ptr::addr_of_mut!(packet) as *mut (),
-                cx,
-            );
+            inner.receivers.register_with_packet(oper, (&raw mut packet) as *mut (), cx);
             inner.senders.notify();
             drop(inner);
 
diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs
index 26d5b9515a2..83a93a06369 100644
--- a/library/std/src/sync/mpsc/mod.rs
+++ b/library/std/src/sync/mpsc/mod.rs
@@ -137,10 +137,10 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod sync_tests;
 
 // MPSC channels are built as a wrapper around MPMC channels, which
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index d417034f5af..fe2aca031a2 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -1,4 +1,4 @@
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 use crate::cell::UnsafeCell;
@@ -7,7 +7,7 @@ use crate::marker::PhantomData;
 use crate::mem::ManuallyDrop;
 use crate::ops::{Deref, DerefMut};
 use crate::ptr::NonNull;
-use crate::sync::{poison, LockResult, TryLockError, TryLockResult};
+use crate::sync::{LockResult, TryLockError, TryLockResult, poison};
 use crate::sys::sync as sys;
 
 /// A mutual exclusion primitive useful for protecting shared data
diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs
index 5a1cd7d0b8b..993df9314fc 100644
--- a/library/std/src/sync/once.rs
+++ b/library/std/src/sync/once.rs
@@ -3,7 +3,7 @@
 //! This primitive is meant to be used to run one-time initialization. An
 //! example use case would be for initializing an FFI library.
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 use crate::fmt;
diff --git a/library/std/src/sync/once_lock/tests.rs b/library/std/src/sync/once_lock/tests.rs
index 176830c6748..5113d436c3c 100644
--- a/library/std/src/sync/once_lock/tests.rs
+++ b/library/std/src/sync/once_lock/tests.rs
@@ -1,7 +1,7 @@
+use crate::sync::OnceLock;
 use crate::sync::atomic::AtomicUsize;
 use crate::sync::atomic::Ordering::SeqCst;
 use crate::sync::mpsc::channel;
-use crate::sync::OnceLock;
 use crate::{panic, thread};
 
 fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
@@ -9,7 +9,7 @@ fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) ->
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn sync_once_cell() {
     static ONCE_CELL: OnceLock<i32> = OnceLock::new();
 
@@ -43,7 +43,7 @@ fn sync_once_cell_get_unchecked() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn sync_once_cell_drop() {
     static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
     struct Dropper;
@@ -81,6 +81,7 @@ fn clone() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn get_or_try_init() {
     let cell: OnceLock<String> = OnceLock::new();
     assert!(cell.get().is_none());
@@ -154,7 +155,7 @@ fn eval_once_macro() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
     static ONCE_CELL: OnceLock<String> = OnceLock::new();
 
diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs
index 0b23681e907..0140e0d2129 100644
--- a/library/std/src/sync/reentrant_lock.rs
+++ b/library/std/src/sync/reentrant_lock.rs
@@ -1,4 +1,4 @@
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 use cfg_if::cfg_if;
@@ -8,7 +8,7 @@ use crate::fmt;
 use crate::ops::Deref;
 use crate::panic::{RefUnwindSafe, UnwindSafe};
 use crate::sys::sync as sys;
-use crate::thread::{current_id, ThreadId};
+use crate::thread::{ThreadId, current_id};
 
 /// A re-entrant mutual exclusion lock
 ///
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index d995a16e056..da2da6f9dfc 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -1,4 +1,4 @@
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 use crate::cell::UnsafeCell;
@@ -7,7 +7,7 @@ use crate::marker::PhantomData;
 use crate::mem::ManuallyDrop;
 use crate::ops::{Deref, DerefMut};
 use crate::ptr::NonNull;
-use crate::sync::{poison, LockResult, TryLockError, TryLockResult};
+use crate::sync::{LockResult, TryLockError, TryLockResult, poison};
 use crate::sys::sync as sys;
 
 /// A reader-writer lock
diff --git a/library/std/src/sys/alloc/solid.rs b/library/std/src/sys/alloc/solid.rs
index abb534a1c5c..47cfa2eb116 100644
--- a/library/std/src/sys/alloc/solid.rs
+++ b/library/std/src/sys/alloc/solid.rs
@@ -1,4 +1,4 @@
-use super::{realloc_fallback, MIN_ALIGN};
+use super::{MIN_ALIGN, realloc_fallback};
 use crate::alloc::{GlobalAlloc, Layout, System};
 
 #[stable(feature = "alloc_system_type", since = "1.28.0")]
diff --git a/library/std/src/sys/alloc/unix.rs b/library/std/src/sys/alloc/unix.rs
index 46ed7de7162..1af9d766290 100644
--- a/library/std/src/sys/alloc/unix.rs
+++ b/library/std/src/sys/alloc/unix.rs
@@ -1,4 +1,4 @@
-use super::{realloc_fallback, MIN_ALIGN};
+use super::{MIN_ALIGN, realloc_fallback};
 use crate::alloc::{GlobalAlloc, Layout, System};
 use crate::ptr;
 
@@ -71,6 +71,7 @@ cfg_if::cfg_if! {
         }
     } else {
         #[inline]
+        #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
         unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
             let mut out = ptr::null_mut();
             // We prefer posix_memalign over aligned_alloc since it is more widely available, and
diff --git a/library/std/src/sys/alloc/wasm.rs b/library/std/src/sys/alloc/wasm.rs
index ef9d753d7f8..a308fafc68b 100644
--- a/library/std/src/sys/alloc/wasm.rs
+++ b/library/std/src/sys/alloc/wasm.rs
@@ -16,6 +16,9 @@
 //! The crate itself provides a global allocator which on wasm has no
 //! synchronization as there are no threads!
 
+// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
+#![allow(static_mut_refs)]
+
 use crate::alloc::{GlobalAlloc, Layout, System};
 
 static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::Dlmalloc::new();
diff --git a/library/std/src/sys/alloc/windows.rs b/library/std/src/sys/alloc/windows.rs
index e91956966aa..a77dda6e817 100644
--- a/library/std/src/sys/alloc/windows.rs
+++ b/library/std/src/sys/alloc/windows.rs
@@ -1,4 +1,4 @@
-use super::{realloc_fallback, MIN_ALIGN};
+use super::{MIN_ALIGN, realloc_fallback};
 use crate::alloc::{GlobalAlloc, Layout, System};
 use crate::ffi::c_void;
 use crate::mem::MaybeUninit;
diff --git a/library/std/src/sys/dbg.rs b/library/std/src/sys/dbg.rs
deleted file mode 100644
index a6e78db3c86..00000000000
--- a/library/std/src/sys/dbg.rs
+++ /dev/null
@@ -1,229 +0,0 @@
-//! Debugging aids.
-
-/// Presence of a debugger. The debugger being concerned
-/// is expected to use the OS API to debug this process.
-#[derive(Copy, Clone, Debug)]
-#[allow(unused)]
-pub(crate) enum DebuggerPresence {
-    /// The debugger is attached to this process.
-    Detected,
-    /// The debugger is not attached to this process.
-    NotDetected,
-}
-
-#[cfg(target_os = "windows")]
-mod os {
-    use super::DebuggerPresence;
-
-    #[link(name = "kernel32")]
-    extern "system" {
-        fn IsDebuggerPresent() -> i32;
-    }
-
-    pub(super) fn is_debugger_present() -> Option<DebuggerPresence> {
-        // SAFETY: No state is shared between threads. The call reads
-        // a field from the Thread Environment Block using the OS API
-        // as required by the documentation.
-        if unsafe { IsDebuggerPresent() } != 0 {
-            Some(DebuggerPresence::Detected)
-        } else {
-            Some(DebuggerPresence::NotDetected)
-        }
-    }
-}
-
-#[cfg(any(target_vendor = "apple", target_os = "freebsd"))]
-mod os {
-    use libc::{c_int, sysctl, CTL_KERN, KERN_PROC, KERN_PROC_PID};
-
-    use super::DebuggerPresence;
-    use crate::io::{Cursor, Read, Seek, SeekFrom};
-    use crate::process;
-
-    const P_TRACED: i32 = 0x00000800;
-
-    // The assumption is that the kernel structures available to the
-    // user space may not shrink or repurpose the existing fields over
-    // time. The kernels normally adhere to that for the backward
-    // compatibility of the user space.
-
-    // The macOS 14.5 SDK comes with a header `MacOSX14.5.sdk/usr/include/sys/sysctl.h`
-    // that defines `struct kinfo_proc` be of `648` bytes on the 64-bit system. That has
-    // not changed since macOS 10.13 (released in 2017) at least, validated by building
-    // a C program in XCode while changing the build target. Apple provides this example
-    // for reference: https://developer.apple.com/library/archive/qa/qa1361/_index.html.
-    #[cfg(target_vendor = "apple")]
-    const KINFO_PROC_SIZE: usize = if cfg!(target_pointer_width = "64") { 648 } else { 492 };
-    #[cfg(target_vendor = "apple")]
-    const KINFO_PROC_FLAGS_OFFSET: u64 = if cfg!(target_pointer_width = "64") { 32 } else { 16 };
-
-    // Works for FreeBSD stable (13.3, 13.4) and current (14.0, 14.1).
-    // The size of the structure has stayed the same for a long time,
-    // at least since 2005:
-    // https://lists.freebsd.org/pipermail/freebsd-stable/2005-November/019899.html
-    #[cfg(target_os = "freebsd")]
-    const KINFO_PROC_SIZE: usize = if cfg!(target_pointer_width = "64") { 1088 } else { 768 };
-    #[cfg(target_os = "freebsd")]
-    const KINFO_PROC_FLAGS_OFFSET: u64 = if cfg!(target_pointer_width = "64") { 368 } else { 296 };
-
-    pub(super) fn is_debugger_present() -> Option<DebuggerPresence> {
-        debug_assert_ne!(KINFO_PROC_SIZE, 0);
-
-        let mut flags = [0u8; 4]; // `ki_flag` under FreeBSD and `p_flag` under macOS.
-        let mut mib = [CTL_KERN, KERN_PROC, KERN_PROC_PID, process::id() as c_int];
-        let mut info_size = KINFO_PROC_SIZE;
-        let mut kinfo_proc = [0u8; KINFO_PROC_SIZE];
-
-        // SAFETY: No state is shared with other threads. The sysctl call
-        // is safe according to the documentation.
-        if unsafe {
-            sysctl(
-                mib.as_mut_ptr(),
-                mib.len() as u32,
-                kinfo_proc.as_mut_ptr().cast(),
-                &mut info_size,
-                core::ptr::null_mut(),
-                0,
-            )
-        } != 0
-        {
-            return None;
-        }
-        debug_assert_eq!(info_size, KINFO_PROC_SIZE);
-
-        let mut reader = Cursor::new(kinfo_proc);
-        reader.seek(SeekFrom::Start(KINFO_PROC_FLAGS_OFFSET)).ok()?;
-        reader.read_exact(&mut flags).ok()?;
-        // Just in case, not limiting this to the little-endian systems.
-        let flags = i32::from_ne_bytes(flags);
-
-        if flags & P_TRACED != 0 {
-            Some(DebuggerPresence::Detected)
-        } else {
-            Some(DebuggerPresence::NotDetected)
-        }
-    }
-}
-
-#[cfg(target_os = "linux")]
-mod os {
-    use super::DebuggerPresence;
-    use crate::fs::File;
-    use crate::io::Read;
-
-    pub(super) fn is_debugger_present() -> Option<DebuggerPresence> {
-        // This function is crafted with the following goals:
-        // * Memory efficiency: It avoids crashing the panicking process due to
-        //   out-of-memory (OOM) conditions by not using large heap buffers or
-        //   allocating significant stack space, which could lead to stack overflow.
-        // * Minimal binary size: The function uses a minimal set of facilities
-        //   from the standard library to avoid increasing the resulting binary size.
-        //
-        // To achieve these goals, the function does not use `[std::io::BufReader]`
-        // and instead reads the file byte by byte using a sliding window approach.
-        // It's important to note that the "/proc/self/status" pseudo-file is synthesized
-        // by the Virtual File System (VFS), meaning it is not read from a slow or
-        // non-volatile storage medium so buffering might not be as beneficial because
-        // all data is read from memory, though this approach does incur a syscall for
-        // each byte read.
-        //
-        // We cannot make assumptions about the file size or the position of the
-        // target prefix ("TracerPid:"), so the function does not use
-        // `[std::fs::read_to_string]` thus not employing UTF-8 to ASCII checking,
-        // conversion, or parsing as we're looking for an ASCII prefix.
-        //
-        // These condiderations make the function deviate from the familiar concise pattern
-        // of searching for a string in a text file.
-
-        fn read_byte(file: &mut File) -> Option<u8> {
-            let mut buffer = [0];
-            file.read_exact(&mut buffer).ok()?;
-            Some(buffer[0])
-        }
-
-        // The ASCII prefix of the datum we're interested in.
-        const TRACER_PID: &[u8] = b"TracerPid:\t";
-
-        let mut file = File::open("/proc/self/status").ok()?;
-        let mut matched = 0;
-
-        // Look for the `TRACER_PID` prefix.
-        while let Some(byte) = read_byte(&mut file) {
-            if byte == TRACER_PID[matched] {
-                matched += 1;
-                if matched == TRACER_PID.len() {
-                    break;
-                }
-            } else {
-                matched = 0;
-            }
-        }
-
-        // Was the prefix found?
-        if matched != TRACER_PID.len() {
-            return None;
-        }
-
-        // It was; get the ASCII representation of the first digit
-        // of the PID. That is enough to see if there is a debugger
-        // attached as the kernel does not pad the PID on the left
-        // with the leading zeroes.
-        let byte = read_byte(&mut file)?;
-        if byte.is_ascii_digit() && byte != b'0' {
-            Some(DebuggerPresence::Detected)
-        } else {
-            Some(DebuggerPresence::NotDetected)
-        }
-    }
-}
-
-#[cfg(not(any(
-    target_os = "windows",
-    target_vendor = "apple",
-    target_os = "freebsd",
-    target_os = "linux"
-)))]
-mod os {
-    pub(super) fn is_debugger_present() -> Option<super::DebuggerPresence> {
-        None
-    }
-}
-
-/// Detect the debugger presence.
-///
-/// The code does not try to detect the debugger at all costs (e.g., when anti-debugger
-/// tricks are at play), it relies on the interfaces provided by the OS.
-///
-/// Return value:
-/// * `None`: it's not possible to conclude whether the debugger is attached to this
-///    process or not. When checking for the presence of the debugger, the detection logic
-///    encountered an issue, such as the OS API throwing an error or the feature not being
-///    implemented.
-/// * `Some(DebuggerPresence::Detected)`: yes, the debugger is attached
-///   to this process.
-/// * `Some(DebuggerPresence::NotDetected)`: no, the debugger is not
-///    attached to this process.
-pub(crate) fn is_debugger_present() -> Option<DebuggerPresence> {
-    if cfg!(miri) { None } else { os::is_debugger_present() }
-}
-
-/// Execute the breakpoint instruction if the debugger presence is detected.
-/// Useful for breaking into the debugger without the need to set a breakpoint
-/// in the debugger.
-///
-/// Note that there is a race between attaching or detaching the debugger, and running the
-/// breakpoint instruction. This is nonetheless memory-safe, like [`crate::process::abort`]
-/// is. In case the debugger is attached and the function is about
-/// to run the breakpoint instruction yet right before that the debugger detaches, the
-/// process will crash due to running the breakpoint instruction and the debugger not
-/// handling the trap exception.
-pub(crate) fn breakpoint_if_debugging() -> Option<DebuggerPresence> {
-    let debugger_present = is_debugger_present();
-    if let Some(DebuggerPresence::Detected) = debugger_present {
-        // SAFETY: Executing the breakpoint instruction. No state is shared
-        // or modified by this code.
-        unsafe { core::intrinsics::breakpoint() };
-    }
-
-    debugger_present
-}
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index 96d6f2c87c4..f17dd47dece 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -11,10 +11,10 @@ mod personality;
 pub mod anonymous_pipe;
 pub mod backtrace;
 pub mod cmath;
-pub mod dbg;
 pub mod exit_guard;
 pub mod os_str;
 pub mod path;
+pub mod random;
 pub mod sync;
 pub mod thread_local;
 
diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs
index 992767211d0..8e0609fe48c 100644
--- a/library/std/src/sys/os_str/bytes.rs
+++ b/library/std/src/sys/os_str/bytes.rs
@@ -2,7 +2,6 @@
 //! systems: just a `Vec<u8>`/`[u8]`.
 
 use core::clone::CloneToUninit;
-use core::ptr::addr_of_mut;
 
 use crate::borrow::Cow;
 use crate::collections::TryReserveError;
@@ -355,6 +354,6 @@ unsafe impl CloneToUninit for Slice {
     #[cfg_attr(debug_assertions, track_caller)]
     unsafe fn clone_to_uninit(&self, dst: *mut Self) {
         // SAFETY: we're just a wrapper around [u8]
-        unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) }
+        unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) }
     }
 }
diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs
index 433237aa6e7..b3834388df6 100644
--- a/library/std/src/sys/os_str/wtf8.rs
+++ b/library/std/src/sys/os_str/wtf8.rs
@@ -1,13 +1,12 @@
 //! The underlying OsString/OsStr implementation on Windows is a
 //! wrapper around the "WTF-8" encoding; see the `wtf8` module for more.
 use core::clone::CloneToUninit;
-use core::ptr::addr_of_mut;
 
 use crate::borrow::Cow;
 use crate::collections::TryReserveError;
 use crate::rc::Rc;
 use crate::sync::Arc;
-use crate::sys_common::wtf8::{check_utf8_boundary, Wtf8, Wtf8Buf};
+use crate::sys_common::wtf8::{Wtf8, Wtf8Buf, check_utf8_boundary};
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::{fmt, mem};
 
@@ -278,6 +277,6 @@ unsafe impl CloneToUninit for Slice {
     #[cfg_attr(debug_assertions, track_caller)]
     unsafe fn clone_to_uninit(&self, dst: *mut Self) {
         // SAFETY: we're just a wrapper around Wtf8
-        unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) }
+        unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) }
     }
 }
diff --git a/library/std/src/sys/pal/hermit/args.rs b/library/std/src/sys/pal/hermit/args.rs
index 51afe3434ae..44024260277 100644
--- a/library/std/src/sys/pal/hermit/args.rs
+++ b/library/std/src/sys/pal/hermit/args.rs
@@ -1,4 +1,4 @@
-use crate::ffi::{c_char, CStr, OsString};
+use crate::ffi::{CStr, OsString, c_char};
 use crate::os::hermit::ffi::OsStringExt;
 use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
 use crate::sync::atomic::{AtomicIsize, AtomicPtr};
diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs
index aaf1a044d06..70f6981f717 100644
--- a/library/std/src/sys/pal/hermit/fs.rs
+++ b/library/std/src/sys/pal/hermit/fs.rs
@@ -1,7 +1,7 @@
 use super::fd::FileDesc;
 use super::hermit_abi::{
-    self, dirent64, stat as stat_struct, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT,
-    O_DIRECTORY, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG,
+    self, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, O_DIRECTORY, O_EXCL, O_RDONLY,
+    O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, dirent64, stat as stat_struct,
 };
 use crate::ffi::{CStr, OsStr, OsString};
 use crate::io::{self, BorrowedCursor, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom};
diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs
index 1f2e5d9469f..b62afb40a61 100644
--- a/library/std/src/sys/pal/hermit/mod.rs
+++ b/library/std/src/sys/pal/hermit/mod.rs
@@ -52,20 +52,6 @@ pub fn abort_internal() -> ! {
     unsafe { hermit_abi::abort() }
 }
 
-pub fn hashmap_random_keys() -> (u64, u64) {
-    let mut buf = [0; 16];
-    let mut slice = &mut buf[..];
-    while !slice.is_empty() {
-        let res = cvt(unsafe { hermit_abi::read_entropy(slice.as_mut_ptr(), slice.len(), 0) })
-            .expect("failed to generate random hashmap keys");
-        slice = &mut slice[res as usize..];
-    }
-
-    let key1 = buf[..8].try_into().unwrap();
-    let key2 = buf[8..].try_into().unwrap();
-    (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2))
-}
-
 // This function is needed by the panic runtime. The symbol is named in
 // pre-link args for the target specification, so keep that in sync.
 #[cfg(not(test))]
@@ -106,7 +92,11 @@ pub unsafe extern "C" fn runtime_entry(
     unsafe {
         crate::sys::thread_local::destructors::run();
     }
-    unsafe { hermit_abi::exit(result) }
+    crate::rt::thread_cleanup();
+
+    unsafe {
+        hermit_abi::exit(result);
+    }
 }
 
 #[inline]
diff --git a/library/std/src/sys/pal/hermit/net.rs b/library/std/src/sys/pal/hermit/net.rs
index 416469c0037..d9baa091a23 100644
--- a/library/std/src/sys/pal/hermit/net.rs
+++ b/library/std/src/sys/pal/hermit/net.rs
@@ -192,7 +192,7 @@ impl Socket {
                 buf.as_mut_ptr(),
                 buf.len(),
                 flags,
-                core::ptr::addr_of_mut!(storage) as *mut _,
+                (&raw mut storage) as *mut _,
                 &mut addrlen,
             )
         })?;
@@ -298,7 +298,7 @@ impl Socket {
             netc::ioctl(
                 self.as_raw_fd(),
                 netc::FIONBIO,
-                core::ptr::addr_of_mut!(nonblocking) as *mut core::ffi::c_void,
+                (&raw mut nonblocking) as *mut core::ffi::c_void,
             )
         })
         .map(drop)
diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs
index 4c0c0919f47..41f2c3e2123 100644
--- a/library/std/src/sys/pal/hermit/thread.rs
+++ b/library/std/src/sys/pal/hermit/thread.rs
@@ -53,6 +53,7 @@ impl Thread {
 
                 // run all destructors
                 crate::sys::thread_local::destructors::run();
+                crate::rt::thread_cleanup();
             }
         }
     }
diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs
index 2c87c4860a2..e0b6eb76b03 100644
--- a/library/std/src/sys/pal/hermit/time.rs
+++ b/library/std/src/sys/pal/hermit/time.rs
@@ -2,7 +2,7 @@
 
 use core::hash::{Hash, Hasher};
 
-use super::hermit_abi::{self, timespec, CLOCK_MONOTONIC, CLOCK_REALTIME};
+use super::hermit_abi::{self, CLOCK_MONOTONIC, CLOCK_REALTIME, timespec};
 use crate::cmp::Ordering;
 use crate::ops::{Add, AddAssign, Sub, SubAssign};
 use crate::time::Duration;
@@ -107,8 +107,7 @@ pub struct Instant(Timespec);
 impl Instant {
     pub fn now() -> Instant {
         let mut time: Timespec = Timespec::zero();
-        let _ =
-            unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, core::ptr::addr_of_mut!(time.t)) };
+        let _ = unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, &raw mut time.t) };
 
         Instant(time)
     }
@@ -209,8 +208,7 @@ impl SystemTime {
 
     pub fn now() -> SystemTime {
         let mut time: Timespec = Timespec::zero();
-        let _ =
-            unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, core::ptr::addr_of_mut!(time.t)) };
+        let _ = unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, &raw mut time.t) };
 
         SystemTime(time)
     }
diff --git a/library/std/src/sys/pal/itron/task.rs b/library/std/src/sys/pal/itron/task.rs
index 5da0c591788..49c420baca2 100644
--- a/library/std/src/sys/pal/itron/task.rs
+++ b/library/std/src/sys/pal/itron/task.rs
@@ -1,5 +1,5 @@
 use super::abi;
-use super::error::{fail, fail_aborting, ItronError};
+use super::error::{ItronError, fail, fail_aborting};
 use crate::mem::MaybeUninit;
 
 /// Gets the ID of the task in Running state. Panics on failure.
diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs
index 01e69afa99e..04095e1a7cf 100644
--- a/library/std/src/sys/pal/itron/thread.rs
+++ b/library/std/src/sys/pal/itron/thread.rs
@@ -1,7 +1,7 @@
 //! Thread implementation backed by μITRON tasks. Assumes `acre_tsk` and
 //! `exd_tsk` are available.
 
-use super::error::{expect_success, expect_success_aborting, ItronError};
+use super::error::{ItronError, expect_success, expect_success_aborting};
 use super::time::dur2reltims;
 use super::{abi, task};
 use crate::cell::UnsafeCell;
diff --git a/library/std/src/sys/pal/itron/time/tests.rs b/library/std/src/sys/pal/itron/time/tests.rs
index d14035d9da4..28db4f8b679 100644
--- a/library/std/src/sys/pal/itron/time/tests.rs
+++ b/library/std/src/sys/pal/itron/time/tests.rs
@@ -8,26 +8,24 @@ fn reltim2dur(t: u64) -> Duration {
 fn test_dur2reltims() {
     assert_eq!(dur2reltims(reltim2dur(0)).collect::<Vec<_>>(), vec![]);
     assert_eq!(dur2reltims(reltim2dur(42)).collect::<Vec<_>>(), vec![42]);
-    assert_eq!(
-        dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64)).collect::<Vec<_>>(),
-        vec![abi::TMAX_RELTIM]
-    );
-    assert_eq!(
-        dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::<Vec<_>>(),
-        vec![abi::TMAX_RELTIM, 10000]
-    );
+    assert_eq!(dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64)).collect::<Vec<_>>(), vec![
+        abi::TMAX_RELTIM
+    ]);
+    assert_eq!(dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::<Vec<_>>(), vec![
+        abi::TMAX_RELTIM,
+        10000
+    ]);
 }
 
 #[test]
 fn test_dur2tmos() {
     assert_eq!(dur2tmos(reltim2dur(0)).collect::<Vec<_>>(), vec![0]);
     assert_eq!(dur2tmos(reltim2dur(42)).collect::<Vec<_>>(), vec![42]);
-    assert_eq!(
-        dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64)).collect::<Vec<_>>(),
-        vec![abi::TMAX_RELTIM]
-    );
-    assert_eq!(
-        dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::<Vec<_>>(),
-        vec![abi::TMAX_RELTIM, 10000]
-    );
+    assert_eq!(dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64)).collect::<Vec<_>>(), vec![
+        abi::TMAX_RELTIM
+    ]);
+    assert_eq!(dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::<Vec<_>>(), vec![
+        abi::TMAX_RELTIM,
+        10000
+    ]);
 }
diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs
index def1ccdf81a..90b9b59471a 100644
--- a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs
+++ b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs
@@ -1,6 +1,6 @@
 use crate::cmp;
 use crate::io::{Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult};
-use crate::sys::rand::rdrand64;
+use crate::random::{DefaultRandomSource, Random};
 use crate::time::{Duration, Instant};
 
 pub(crate) mod alloc;
@@ -164,7 +164,7 @@ pub fn wait(event_mask: u64, mut timeout: u64) -> IoResult<u64> {
         // 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);
+            let deviation = i64::random(&mut DefaultRandomSource).checked_rem(tenth).unwrap_or(0);
             timeout = timeout_signed.saturating_add(deviation) as _;
         }
     }
diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/tests.rs b/library/std/src/sys/pal/sgx/abi/usercalls/tests.rs
index ef824d35f4a..5978ae5a0fa 100644
--- a/library/std/src/sys/pal/sgx/abi/usercalls/tests.rs
+++ b/library/std/src/sys/pal/sgx/abi/usercalls/tests.rs
@@ -1,4 +1,4 @@
-use super::alloc::{copy_from_userspace, copy_to_userspace, User};
+use super::alloc::{User, copy_from_userspace, copy_to_userspace};
 
 #[test]
 fn test_copy_to_userspace_function() {
diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs
index 8d29b2ec619..586ccd18c2f 100644
--- a/library/std/src/sys/pal/sgx/mod.rs
+++ b/library/std/src/sys/pal/sgx/mod.rs
@@ -132,24 +132,6 @@ pub extern "C" fn __rust_abort() {
     abort_internal();
 }
 
-pub mod rand {
-    pub fn rdrand64() -> u64 {
-        unsafe {
-            let mut ret: u64 = 0;
-            for _ in 0..10 {
-                if crate::arch::x86_64::_rdrand64_step(&mut ret) == 1 {
-                    return ret;
-                }
-            }
-            rtabort!("Failed to obtain random data");
-        }
-    }
-}
-
-pub fn hashmap_random_keys() -> (u64, u64) {
-    (self::rand::rdrand64(), self::rand::rdrand64())
-}
-
 pub use crate::sys_common::{AsInner, FromInner, IntoInner};
 
 pub trait TryIntoInner<Inner>: Sized {
diff --git a/library/std/src/sys/pal/sgx/net.rs b/library/std/src/sys/pal/sgx/net.rs
index f2e751c5119..c966886d163 100644
--- a/library/std/src/sys/pal/sgx/net.rs
+++ b/library/std/src/sys/pal/sgx/net.rs
@@ -3,7 +3,7 @@ use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs};
 use crate::sync::Arc;
 use crate::sys::fd::FileDesc;
-use crate::sys::{sgx_ineffective, unsupported, AsInner, FromInner, IntoInner, TryIntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner, TryIntoInner, sgx_ineffective, unsupported};
 use crate::time::Duration;
 use crate::{error, fmt};
 
@@ -78,9 +78,8 @@ fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result<String> {
     }
 }
 
-fn addr_to_sockaddr(addr: &Option<String>) -> io::Result<SocketAddr> {
-    addr.as_ref()
-        .ok_or(io::ErrorKind::AddrNotAvailable)?
+fn addr_to_sockaddr(addr: Option<&str>) -> io::Result<SocketAddr> {
+    addr.ok_or(io::ErrorKind::AddrNotAvailable)?
         .to_socket_addrs()
         // unwrap OK: if an iterator is returned, we're guaranteed to get exactly one entry
         .map(|mut it| it.next().unwrap())
@@ -161,11 +160,11 @@ impl TcpStream {
     }
 
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-        addr_to_sockaddr(&self.peer_addr)
+        addr_to_sockaddr(self.peer_addr.as_deref())
     }
 
     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        addr_to_sockaddr(&self.inner.local_addr)
+        addr_to_sockaddr(self.inner.local_addr.as_deref())
     }
 
     pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
@@ -255,13 +254,14 @@ impl TcpListener {
     }
 
     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        addr_to_sockaddr(&self.inner.local_addr)
+        addr_to_sockaddr(self.inner.local_addr.as_deref())
     }
 
     pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
         let (fd, local_addr, peer_addr) = usercalls::accept_stream(self.inner.inner.raw())?;
         let peer_addr = Some(peer_addr);
-        let ret_peer = addr_to_sockaddr(&peer_addr).unwrap_or_else(|_| ([0; 4], 0).into());
+        let ret_peer =
+            addr_to_sockaddr(peer_addr.as_deref()).unwrap_or_else(|_| ([0; 4], 0).into());
         Ok((TcpStream { inner: Socket::new(fd, local_addr), peer_addr }, ret_peer))
     }
 
diff --git a/library/std/src/sys/pal/sgx/waitqueue/mod.rs b/library/std/src/sys/pal/sgx/waitqueue/mod.rs
index bd114523fe8..41d1413fcde 100644
--- a/library/std/src/sys/pal/sgx/waitqueue/mod.rs
+++ b/library/std/src/sys/pal/sgx/waitqueue/mod.rs
@@ -16,9 +16,9 @@ mod tests;
 mod spin_mutex;
 mod unsafe_list;
 
-use fortanix_sgx_abi::{Tcs, EV_UNPARK, WAIT_INDEFINITE};
+use fortanix_sgx_abi::{EV_UNPARK, Tcs, WAIT_INDEFINITE};
 
-pub use self::spin_mutex::{try_lock_or_false, SpinMutex, SpinMutexGuard};
+pub use self::spin_mutex::{SpinMutex, SpinMutexGuard, try_lock_or_false};
 use self::unsafe_list::{UnsafeList, UnsafeListEntry};
 use super::abi::{thread, usercalls};
 use crate::num::NonZero;
diff --git a/library/std/src/sys/pal/solid/abi/fs.rs b/library/std/src/sys/pal/solid/abi/fs.rs
index 394be15b006..6864a3e7745 100644
--- a/library/std/src/sys/pal/solid/abi/fs.rs
+++ b/library/std/src/sys/pal/solid/abi/fs.rs
@@ -1,8 +1,8 @@
 //! `solid_fs.h`
 
 pub use libc::{
-    ino_t, off_t, stat, time_t, O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY,
-    SEEK_CUR, SEEK_END, SEEK_SET, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFMT, S_IFREG, S_IWRITE,
+    O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, S_IFBLK, S_IFCHR, S_IFDIR,
+    S_IFIFO, S_IFMT, S_IFREG, S_IWRITE, SEEK_CUR, SEEK_END, SEEK_SET, ino_t, off_t, stat, time_t,
 };
 
 use crate::os::raw::{c_char, c_int, c_uchar};
diff --git a/library/std/src/sys/pal/solid/abi/mod.rs b/library/std/src/sys/pal/solid/abi/mod.rs
index 62cd86236bb..4d097057217 100644
--- a/library/std/src/sys/pal/solid/abi/mod.rs
+++ b/library/std/src/sys/pal/solid/abi/mod.rs
@@ -4,7 +4,7 @@ mod fs;
 pub mod sockets;
 pub use self::fs::*;
 // `solid_types.h`
-pub use super::itron::abi::{ER, ER_ID, E_TMOUT, ID};
+pub use super::itron::abi::{E_TMOUT, ER, ER_ID, ID};
 
 pub const SOLID_ERR_NOTFOUND: ER = -1000;
 pub const SOLID_ERR_NOTSUPPORTED: ER = -1001;
diff --git a/library/std/src/sys/pal/solid/error.rs b/library/std/src/sys/pal/solid/error.rs
index 66c4d8a0ea2..e092497856d 100644
--- a/library/std/src/sys/pal/solid/error.rs
+++ b/library/std/src/sys/pal/solid/error.rs
@@ -1,4 +1,4 @@
-pub use self::itron::error::{expect_success, ItronError as SolidError};
+pub use self::itron::error::{ItronError as SolidError, expect_success};
 use super::{abi, itron, net};
 use crate::io::ErrorKind;
 
diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs
index 6ebcf5b7c48..d41042be518 100644
--- a/library/std/src/sys/pal/solid/mod.rs
+++ b/library/std/src/sys/pal/solid/mod.rs
@@ -62,13 +62,3 @@ pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind {
 pub fn abort_internal() -> ! {
     unsafe { libc::abort() }
 }
-
-pub fn hashmap_random_keys() -> (u64, u64) {
-    unsafe {
-        let mut out = crate::mem::MaybeUninit::<[u64; 2]>::uninit();
-        let result = abi::SOLID_RNG_SampleRandomBytes(out.as_mut_ptr() as *mut u8, 16);
-        assert_eq!(result, 0, "SOLID_RNG_SampleRandomBytes failed: {result}");
-        let [x1, x2] = out.assume_init();
-        (x1, x2)
-    }
-}
diff --git a/library/std/src/sys/pal/solid/net.rs b/library/std/src/sys/pal/solid/net.rs
index b6a31395095..c0818ecd856 100644
--- a/library/std/src/sys/pal/solid/net.rs
+++ b/library/std/src/sys/pal/solid/net.rs
@@ -1,6 +1,6 @@
 use libc::{c_int, c_void, size_t};
 
-use self::netc::{sockaddr, socklen_t, MSG_PEEK};
+use self::netc::{MSG_PEEK, sockaddr, socklen_t};
 use super::abi;
 use crate::ffi::CStr;
 use crate::io::{self, BorrowedBuf, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut};
diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs
index 00e38604240..60a227afb84 100644
--- a/library/std/src/sys/pal/teeos/mod.rs
+++ b/library/std/src/sys/pal/teeos/mod.rs
@@ -6,8 +6,6 @@
 #![allow(unused_variables)]
 #![allow(dead_code)]
 
-pub use self::rand::hashmap_random_keys;
-
 #[path = "../unsupported/args.rs"]
 pub mod args;
 #[path = "../unsupported/env.rs"]
@@ -23,7 +21,6 @@ pub mod os;
 pub mod pipe;
 #[path = "../unsupported/process.rs"]
 pub mod process;
-mod rand;
 pub mod stdio;
 pub mod thread;
 #[allow(non_upper_case_globals)]
diff --git a/library/std/src/sys/pal/teeos/rand.rs b/library/std/src/sys/pal/teeos/rand.rs
deleted file mode 100644
index b45c3bb40e7..00000000000
--- a/library/std/src/sys/pal/teeos/rand.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-pub fn hashmap_random_keys() -> (u64, u64) {
-    const KEY_LEN: usize = core::mem::size_of::<u64>();
-
-    let mut v = [0u8; KEY_LEN * 2];
-    imp::fill_bytes(&mut v);
-
-    let key1 = v[0..KEY_LEN].try_into().unwrap();
-    let key2 = v[KEY_LEN..].try_into().unwrap();
-
-    (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2))
-}
-
-mod imp {
-    extern "C" {
-        fn TEE_GenerateRandom(randomBuffer: *mut core::ffi::c_void, randomBufferLen: libc::size_t);
-    }
-
-    pub fn fill_bytes(v: &mut [u8]) {
-        unsafe { TEE_GenerateRandom(v.as_mut_ptr() as _, v.len() * crate::mem::size_of::<u8>()) }
-    }
-}
diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs
index 4031d33ba80..bd8a6684b64 100644
--- a/library/std/src/sys/pal/uefi/helpers.rs
+++ b/library/std/src/sys/pal/uefi/helpers.rs
@@ -14,7 +14,7 @@ use r_efi::protocols::{device_path, device_path_to_text};
 
 use crate::ffi::{OsStr, OsString};
 use crate::io::{self, const_io_error};
-use crate::mem::{size_of, MaybeUninit};
+use crate::mem::{MaybeUninit, size_of};
 use crate::os::uefi::env::boot_services;
 use crate::os::uefi::ffi::{OsStrExt, OsStringExt};
 use crate::os::uefi::{self};
diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs
index ac22f4ded88..c0ab52f650a 100644
--- a/library/std/src/sys/pal/uefi/mod.rs
+++ b/library/std/src/sys/pal/uefi/mod.rs
@@ -179,39 +179,6 @@ pub extern "C" fn __rust_abort() {
     abort_internal();
 }
 
-#[inline]
-pub fn hashmap_random_keys() -> (u64, u64) {
-    get_random().unwrap()
-}
-
-fn get_random() -> Option<(u64, u64)> {
-    use r_efi::protocols::rng;
-
-    let mut buf = [0u8; 16];
-    let handles = helpers::locate_handles(rng::PROTOCOL_GUID).ok()?;
-    for handle in handles {
-        if let Ok(protocol) = helpers::open_protocol::<rng::Protocol>(handle, rng::PROTOCOL_GUID) {
-            let r = unsafe {
-                ((*protocol.as_ptr()).get_rng)(
-                    protocol.as_ptr(),
-                    crate::ptr::null_mut(),
-                    buf.len(),
-                    buf.as_mut_ptr(),
-                )
-            };
-            if r.is_error() {
-                continue;
-            } else {
-                return Some((
-                    u64::from_le_bytes(buf[..8].try_into().ok()?),
-                    u64::from_le_bytes(buf[8..].try_into().ok()?),
-                ));
-            }
-        }
-    }
-    None
-}
-
 /// Disable access to BootServices if `EVT_SIGNAL_EXIT_BOOT_SERVICES` is signaled
 extern "efiapi" fn exit_boot_service_handler(_e: r_efi::efi::Event, _ctx: *mut crate::ffi::c_void) {
     uefi::env::disable_boot_services();
diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/pal/uefi/os.rs
index 4d2d7264704..9aee67d622f 100644
--- a/library/std/src/sys/pal/uefi/os.rs
+++ b/library/std/src/sys/pal/uefi/os.rs
@@ -1,7 +1,7 @@
-use r_efi::efi::protocols::{device_path, loaded_image_device_path};
 use r_efi::efi::Status;
+use r_efi::efi::protocols::{device_path, loaded_image_device_path};
 
-use super::{helpers, unsupported, RawOsError};
+use super::{RawOsError, helpers, unsupported};
 use crate::error::Error as StdError;
 use crate::ffi::{OsStr, OsString};
 use crate::marker::PhantomData;
diff --git a/library/std/src/sys/pal/unix/args.rs b/library/std/src/sys/pal/unix/args.rs
index a943e3a581a..8438a61e90f 100644
--- a/library/std/src/sys/pal/unix/args.rs
+++ b/library/std/src/sys/pal/unix/args.rs
@@ -113,6 +113,7 @@ impl DoubleEndedIterator for Args {
     target_os = "nto",
     target_os = "hurd",
     target_os = "rtems",
+    target_os = "nuttx",
 ))]
 mod imp {
     use crate::ffi::c_char;
diff --git a/library/std/src/sys/pal/unix/env.rs b/library/std/src/sys/pal/unix/env.rs
index b2d399b8791..2aee0b5d460 100644
--- a/library/std/src/sys/pal/unix/env.rs
+++ b/library/std/src/sys/pal/unix/env.rs
@@ -283,3 +283,14 @@ pub mod os {
     pub const EXE_SUFFIX: &str = "";
     pub const EXE_EXTENSION: &str = "";
 }
+
+#[cfg(target_os = "nuttx")]
+pub mod os {
+    pub const FAMILY: &str = "unix";
+    pub const OS: &str = "nuttx";
+    pub const DLL_PREFIX: &str = "lib";
+    pub const DLL_SUFFIX: &str = ".so";
+    pub const DLL_EXTENSION: &str = "so";
+    pub const EXE_SUFFIX: &str = "";
+    pub const EXE_EXTENSION: &str = "";
+}
diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs
index d8e239ee23e..6a28799ca55 100644
--- a/library/std/src/sys/pal/unix/fd.rs
+++ b/library/std/src/sys/pal/unix/fd.rs
@@ -3,14 +3,6 @@
 #[cfg(test)]
 mod tests;
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "linux",
-    target_os = "emscripten",
-    target_os = "l4re",
-    target_os = "hurd",
-))]
-use libc::off64_t;
 #[cfg(not(any(
     target_os = "linux",
     target_os = "emscripten",
@@ -19,6 +11,14 @@ use libc::off64_t;
     target_os = "hurd",
 )))]
 use libc::off_t as off64_t;
+#[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "emscripten",
+    target_os = "l4re",
+    target_os = "hurd",
+))]
+use libc::off64_t;
 
 use crate::cmp;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read};
@@ -98,7 +98,12 @@ impl FileDesc {
         Ok(ret as usize)
     }
 
-    #[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))]
+    #[cfg(not(any(
+        target_os = "espidf",
+        target_os = "horizon",
+        target_os = "vita",
+        target_os = "nuttx"
+    )))]
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         let ret = cvt(unsafe {
             libc::readv(
@@ -110,14 +115,24 @@ impl FileDesc {
         Ok(ret as usize)
     }
 
-    #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))]
+    #[cfg(any(
+        target_os = "espidf",
+        target_os = "horizon",
+        target_os = "vita",
+        target_os = "nuttx"
+    ))]
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         io::default_read_vectored(|b| self.read(b), bufs)
     }
 
     #[inline]
     pub fn is_read_vectored(&self) -> bool {
-        cfg!(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))
+        cfg!(not(any(
+            target_os = "espidf",
+            target_os = "horizon",
+            target_os = "vita",
+            target_os = "nuttx"
+        )))
     }
 
     pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
@@ -297,7 +312,12 @@ impl FileDesc {
         Ok(ret as usize)
     }
 
-    #[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))]
+    #[cfg(not(any(
+        target_os = "espidf",
+        target_os = "horizon",
+        target_os = "vita",
+        target_os = "nuttx"
+    )))]
     pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
         let ret = cvt(unsafe {
             libc::writev(
@@ -309,14 +329,24 @@ impl FileDesc {
         Ok(ret as usize)
     }
 
-    #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))]
+    #[cfg(any(
+        target_os = "espidf",
+        target_os = "horizon",
+        target_os = "vita",
+        target_os = "nuttx"
+    ))]
     pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
         io::default_write_vectored(|b| self.write(b), bufs)
     }
 
     #[inline]
     pub fn is_write_vectored(&self) -> bool {
-        cfg!(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))
+        cfg!(not(any(
+            target_os = "espidf",
+            target_os = "horizon",
+            target_os = "vita",
+            target_os = "nuttx"
+        )))
     }
 
     #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs
index d09cee2e89c..e80299f1868 100644
--- a/library/std/src/sys/pal/unix/fs.rs
+++ b/library/std/src/sys/pal/unix/fs.rs
@@ -31,10 +31,6 @@ use libc::fstatat64;
     all(target_os = "linux", target_env = "musl"),
 ))]
 use libc::readdir as readdir64;
-#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))]
-use libc::readdir64;
-#[cfg(any(target_os = "emscripten", target_os = "l4re"))]
-use libc::readdir64_r;
 #[cfg(not(any(
     target_os = "android",
     target_os = "linux",
@@ -50,6 +46,10 @@ use libc::readdir64_r;
     target_os = "hurd",
 )))]
 use libc::readdir_r as readdir64_r;
+#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))]
+use libc::readdir64;
+#[cfg(any(target_os = "emscripten", target_os = "l4re"))]
+use libc::readdir64_r;
 use libc::{c_int, mode_t};
 #[cfg(target_os = "android")]
 use libc::{
@@ -479,6 +479,7 @@ impl FileAttr {
         target_os = "vita",
         target_os = "hurd",
         target_os = "rtems",
+        target_os = "nuttx",
     )))]
     pub fn modified(&self) -> io::Result<SystemTime> {
         #[cfg(target_pointer_width = "32")]
@@ -501,7 +502,7 @@ impl FileAttr {
         SystemTime::new(self.stat.st_mtime as i64, 0)
     }
 
-    #[cfg(any(target_os = "horizon", target_os = "hurd"))]
+    #[cfg(any(target_os = "horizon", target_os = "hurd", target_os = "nuttx"))]
     pub fn modified(&self) -> io::Result<SystemTime> {
         SystemTime::new(self.stat.st_mtim.tv_sec as i64, self.stat.st_mtim.tv_nsec as i64)
     }
@@ -513,6 +514,7 @@ impl FileAttr {
         target_os = "vita",
         target_os = "hurd",
         target_os = "rtems",
+        target_os = "nuttx",
     )))]
     pub fn accessed(&self) -> io::Result<SystemTime> {
         #[cfg(target_pointer_width = "32")]
@@ -535,7 +537,7 @@ impl FileAttr {
         SystemTime::new(self.stat.st_atime as i64, 0)
     }
 
-    #[cfg(any(target_os = "horizon", target_os = "hurd"))]
+    #[cfg(any(target_os = "horizon", target_os = "hurd", target_os = "nuttx"))]
     pub fn accessed(&self) -> io::Result<SystemTime> {
         SystemTime::new(self.stat.st_atim.tv_sec as i64, self.stat.st_atim.tv_nsec as i64)
     }
@@ -738,7 +740,7 @@ impl Iterator for ReadDir {
                 //
                 // Like for uninitialized contents, converting entry_ptr to `&dirent64`
                 // would not be legal. However, unique to dirent64 is that we don't even
-                // get to use `addr_of!((*entry_ptr).d_name)` because that operation
+                // get to use `&raw const (*entry_ptr).d_name` because that operation
                 // requires the full extent of *entry_ptr to be in bounds of the same
                 // allocation, which is not necessarily the case here.
                 //
@@ -752,7 +754,7 @@ impl Iterator for ReadDir {
                         } else {
                             #[allow(deref_nullptr)]
                             {
-                                ptr::addr_of!((*ptr::null::<dirent64>()).$field)
+                                &raw const (*ptr::null::<dirent64>()).$field
                             }
                         }
                     }};
@@ -866,6 +868,7 @@ impl Drop for Dir {
             target_os = "horizon",
             target_os = "vxworks",
             target_os = "rtems",
+            target_os = "nuttx",
         )))]
         {
             let fd = unsafe { libc::dirfd(self.0) };
@@ -896,7 +899,7 @@ impl DirEntry {
             target_os = "android",
             target_os = "hurd"
         ),
-        not(miri)
+        not(miri) // no dirfd on Miri
     ))]
     pub fn metadata(&self) -> io::Result<FileAttr> {
         let fd = cvt(unsafe { dirfd(self.dir.dirp.0) })?;
@@ -1000,6 +1003,13 @@ impl DirEntry {
         self.entry.d_fileno as u64
     }
 
+    #[cfg(target_os = "nuttx")]
+    pub fn ino(&self) -> u64 {
+        // Leave this 0 for now, as NuttX does not provide an inode number
+        // in its directory entries.
+        0
+    }
+
     #[cfg(any(
         target_os = "netbsd",
         target_os = "openbsd",
@@ -1327,7 +1337,8 @@ impl File {
             target_os = "redox",
             target_os = "espidf",
             target_os = "horizon",
-            target_os = "vxworks"
+            target_os = "vxworks",
+            target_os = "nuttx",
         )))]
         let to_timespec = |time: Option<SystemTime>| match time {
             Some(time) if let Some(ts) = time.t.to_timespec() => Ok(ts),
@@ -1342,7 +1353,7 @@ impl File {
             None => Ok(libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ }),
         };
         cfg_if::cfg_if! {
-            if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "vxworks"))] {
+            if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "vxworks", target_os = "nuttx"))] {
                 // Redox doesn't appear to support `UTIME_OMIT`.
                 // ESP-IDF and HorizonOS do not support `futimens` at all and the behavior for those OS is therefore
                 // the same as for Redox.
@@ -1374,7 +1385,7 @@ impl File {
                 }
                 cvt(unsafe { libc::fsetattrlist(
                     self.as_raw_fd(),
-                    core::ptr::addr_of!(attrlist).cast::<libc::c_void>().cast_mut(),
+                    (&raw const attrlist).cast::<libc::c_void>().cast_mut(),
                     buf.as_ptr().cast::<libc::c_void>().cast_mut(),
                     num_times * mem::size_of::<libc::timespec>(),
                     0
@@ -1866,7 +1877,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
     let max_len = u64::MAX;
     let (mut writer, _) = open_to_and_set_permissions(to, reader_metadata)?;
 
-    use super::kernel_copy::{copy_regular_files, CopyResult};
+    use super::kernel_copy::{CopyResult, copy_regular_files};
 
     match copy_regular_files(reader.as_raw_fd(), writer.as_raw_fd(), max_len) {
         CopyResult::Ended(bytes) => Ok(bytes),
@@ -1933,7 +1944,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
         libc::copyfile_state_get(
             state.0,
             libc::COPYFILE_STATE_COPIED as u32,
-            core::ptr::addr_of_mut!(bytes_copied) as *mut libc::c_void,
+            (&raw mut bytes_copied) as *mut libc::c_void,
         )
     })?;
     Ok(bytes_copied as u64)
@@ -2008,7 +2019,7 @@ mod remove_dir_impl {
     #[cfg(all(target_os = "linux", target_env = "gnu"))]
     use libc::{fdopendir, openat64 as openat, unlinkat};
 
-    use super::{lstat, Dir, DirEntry, InnerReadDir, ReadDir};
+    use super::{Dir, DirEntry, InnerReadDir, ReadDir, lstat};
     use crate::ffi::CStr;
     use crate::io;
     use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index e8428eccb16..4fe18daa204 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -1,6 +1,5 @@
 #![allow(missing_docs, nonstandard_style)]
 
-pub use self::rand::hashmap_random_keys;
 use crate::io::ErrorKind;
 
 #[cfg(not(target_os = "espidf"))]
@@ -26,7 +25,6 @@ pub use self::l4re::net;
 pub mod os;
 pub mod pipe;
 pub mod process;
-pub mod rand;
 pub mod stack_overflow;
 pub mod stdio;
 pub mod thread;
@@ -224,6 +222,7 @@ static ON_BROKEN_PIPE_FLAG_USED: crate::sync::atomic::AtomicBool =
     target_os = "horizon",
     target_os = "vxworks",
     target_os = "vita",
+    target_os = "nuttx",
 )))]
 pub(crate) fn on_broken_pipe_flag_used() -> bool {
     ON_BROKEN_PIPE_FLAG_USED.load(crate::sync::atomic::Ordering::Relaxed)
@@ -281,6 +280,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         libc::ETIMEDOUT => TimedOut,
         libc::ETXTBSY => ExecutableFileBusy,
         libc::EXDEV => CrossesDevices,
+        libc::EINPROGRESS => InProgress,
 
         libc::EACCES | libc::EPERM => PermissionDenied,
 
@@ -426,7 +426,7 @@ cfg_if::cfg_if! {
     }
 }
 
-#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))]
+#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))]
 mod unsupported {
     use crate::io;
 
diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs
index d75a666d350..6a67bb0a101 100644
--- a/library/std/src/sys/pal/unix/net.rs
+++ b/library/std/src/sys/pal/unix/net.rs
@@ -1,4 +1,4 @@
-use libc::{c_int, c_void, size_t, sockaddr, socklen_t, MSG_PEEK};
+use libc::{MSG_PEEK, c_int, c_void, size_t, sockaddr, socklen_t};
 
 use crate::ffi::CStr;
 use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
@@ -38,19 +38,19 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> {
     // We may need to trigger a glibc workaround. See on_resolver_failure() for details.
     on_resolver_failure();
 
-    #[cfg(not(target_os = "espidf"))]
+    #[cfg(not(any(target_os = "espidf", target_os = "nuttx")))]
     if err == libc::EAI_SYSTEM {
         return Err(io::Error::last_os_error());
     }
 
-    #[cfg(not(target_os = "espidf"))]
+    #[cfg(not(any(target_os = "espidf", target_os = "nuttx")))]
     let detail = unsafe {
         // We can't always expect a UTF-8 environment. When we don't get that luxury,
         // it's better to give a low-quality error message than none at all.
         CStr::from_ptr(libc::gai_strerror(err)).to_string_lossy()
     };
 
-    #[cfg(target_os = "espidf")]
+    #[cfg(any(target_os = "espidf", target_os = "nuttx"))]
     let detail = "";
 
     Err(io::Error::new(
@@ -329,7 +329,7 @@ impl Socket {
                 buf.as_mut_ptr() as *mut c_void,
                 buf.len(),
                 flags,
-                core::ptr::addr_of_mut!(storage) as *mut _,
+                (&raw mut storage) as *mut _,
                 &mut addrlen,
             )
         })?;
diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs
index 503f8915256..f983d174ed6 100644
--- a/library/std/src/sys/pal/unix/os.rs
+++ b/library/std/src/sys/pal/unix/os.rs
@@ -48,6 +48,7 @@ extern "C" {
             target_os = "openbsd",
             target_os = "android",
             target_os = "redox",
+            target_os = "nuttx",
             target_env = "newlib"
         ),
         link_name = "__errno"
@@ -399,6 +400,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
     target_os = "linux",
     target_os = "hurd",
     target_os = "android",
+    target_os = "nuttx",
     target_os = "emscripten"
 ))]
 pub fn current_exe() -> io::Result<PathBuf> {
@@ -610,7 +612,7 @@ pub unsafe fn environ() -> *mut *const *const c_char {
     extern "C" {
         static mut environ: *const *const c_char;
     }
-    ptr::addr_of_mut!(environ)
+    &raw mut environ
 }
 
 static ENV_LOCK: RwLock<()> = RwLock::new(());
@@ -717,6 +719,7 @@ pub fn home_dir() -> Option<PathBuf> {
         target_os = "espidf",
         target_os = "horizon",
         target_os = "vita",
+        target_os = "nuttx",
         all(target_vendor = "apple", not(target_os = "macos")),
     ))]
     unsafe fn fallback() -> Option<OsString> {
@@ -730,6 +733,7 @@ pub fn home_dir() -> Option<PathBuf> {
         target_os = "espidf",
         target_os = "horizon",
         target_os = "vita",
+        target_os = "nuttx",
         all(target_vendor = "apple", not(target_os = "macos")),
     )))]
     unsafe fn fallback() -> Option<OsString> {
diff --git a/library/std/src/sys/pal/unix/process/mod.rs b/library/std/src/sys/pal/unix/process/mod.rs
index 074f0a105e3..2751d51c44d 100644
--- a/library/std/src/sys/pal/unix/process/mod.rs
+++ b/library/std/src/sys/pal/unix/process/mod.rs
@@ -2,10 +2,10 @@ pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes
 pub use self::process_inner::{ExitStatus, ExitStatusError, Process};
 pub use crate::ffi::OsString as EnvKey;
 
-#[cfg_attr(any(target_os = "espidf", target_os = "horizon"), allow(unused))]
+#[cfg_attr(any(target_os = "espidf", target_os = "horizon", target_os = "nuttx"), allow(unused))]
 mod process_common;
 
-#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))]
+#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))]
 mod process_unsupported;
 
 cfg_if::cfg_if! {
@@ -16,7 +16,7 @@ cfg_if::cfg_if! {
     } else if #[cfg(target_os = "vxworks")] {
         #[path = "process_vxworks.rs"]
         mod process_inner;
-    } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] {
+    } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] {
         mod process_inner {
             pub use super::process_unsupported::*;
         }
diff --git a/library/std/src/sys/pal/unix/process/process_common.rs b/library/std/src/sys/pal/unix/process/process_common.rs
index fec82505419..13290fed762 100644
--- a/library/std/src/sys/pal/unix/process/process_common.rs
+++ b/library/std/src/sys/pal/unix/process/process_common.rs
@@ -1,7 +1,7 @@
 #[cfg(all(test, not(target_os = "emscripten")))]
 mod tests;
 
-use libc::{c_char, c_int, gid_t, pid_t, uid_t, EXIT_FAILURE, EXIT_SUCCESS};
+use libc::{EXIT_FAILURE, EXIT_SUCCESS, c_char, c_int, gid_t, pid_t, uid_t};
 
 use crate::collections::BTreeMap;
 use crate::ffi::{CStr, CString, OsStr, OsString};
@@ -312,8 +312,8 @@ impl Command {
     }
 
     #[allow(dead_code)]
-    pub fn get_cwd(&self) -> &Option<CString> {
-        &self.cwd
+    pub fn get_cwd(&self) -> Option<&CStr> {
+        self.cwd.as_deref()
     }
     #[allow(dead_code)]
     pub fn get_uid(&self) -> Option<uid_t> {
diff --git a/library/std/src/sys/pal/unix/process/process_fuchsia.rs b/library/std/src/sys/pal/unix/process/process_fuchsia.rs
index f3d5fdec4c2..5d0110cf55d 100644
--- a/library/std/src/sys/pal/unix/process/process_fuchsia.rs
+++ b/library/std/src/sys/pal/unix/process/process_fuchsia.rs
@@ -2,7 +2,7 @@ use libc::{c_int, size_t};
 
 use crate::num::NonZero;
 use crate::sys::process::process_common::*;
-use crate::sys::process::zircon::{zx_handle_t, Handle};
+use crate::sys::process::zircon::{Handle, zx_handle_t};
 use crate::{fmt, io, mem, ptr};
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -178,7 +178,7 @@ impl Process {
             zx_cvt(zx_object_get_info(
                 self.handle.raw(),
                 ZX_INFO_PROCESS,
-                core::ptr::addr_of_mut!(proc_info) as *mut libc::c_void,
+                (&raw mut proc_info) as *mut libc::c_void,
                 mem::size_of::<zx_info_process_t>(),
                 &mut actual,
                 &mut avail,
@@ -215,7 +215,7 @@ impl Process {
             zx_cvt(zx_object_get_info(
                 self.handle.raw(),
                 ZX_INFO_PROCESS,
-                core::ptr::addr_of_mut!(proc_info) as *mut libc::c_void,
+                (&raw mut proc_info) as *mut libc::c_void,
                 mem::size_of::<zx_info_process_t>(),
                 &mut actual,
                 &mut avail,
diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs
index 4bb22f36709..4551d49e841 100644
--- a/library/std/src/sys/pal/unix/process/process_unix.rs
+++ b/library/std/src/sys/pal/unix/process/process_unix.rs
@@ -335,7 +335,7 @@ impl Command {
                 cvt(libc::setuid(u as uid_t))?;
             }
         }
-        if let Some(ref cwd) = *self.get_cwd() {
+        if let Some(cwd) = self.get_cwd() {
             cvt(libc::chdir(cwd.as_ptr()))?;
         }
 
@@ -788,15 +788,15 @@ impl Command {
             let mut iov = [IoSlice::new(b"")];
             let mut msg: libc::msghdr = mem::zeroed();
 
-            msg.msg_iov = core::ptr::addr_of_mut!(iov) as *mut _;
+            msg.msg_iov = (&raw mut iov) as *mut _;
             msg.msg_iovlen = 1;
 
             // only attach cmsg if we successfully acquired the pidfd
             if pidfd >= 0 {
                 msg.msg_controllen = mem::size_of_val(&cmsg.buf) as _;
-                msg.msg_control = core::ptr::addr_of_mut!(cmsg.buf) as *mut _;
+                msg.msg_control = (&raw mut cmsg.buf) as *mut _;
 
-                let hdr = CMSG_FIRSTHDR(core::ptr::addr_of_mut!(msg) as *mut _);
+                let hdr = CMSG_FIRSTHDR((&raw mut msg) as *mut _);
                 (*hdr).cmsg_level = SOL_SOCKET;
                 (*hdr).cmsg_type = SCM_RIGHTS;
                 (*hdr).cmsg_len = CMSG_LEN(SCM_MSG_LEN as _) as _;
@@ -838,17 +838,17 @@ impl Command {
 
             let mut msg: libc::msghdr = mem::zeroed();
 
-            msg.msg_iov = core::ptr::addr_of_mut!(iov) as *mut _;
+            msg.msg_iov = (&raw mut iov) as *mut _;
             msg.msg_iovlen = 1;
             msg.msg_controllen = mem::size_of::<Cmsg>() as _;
-            msg.msg_control = core::ptr::addr_of_mut!(cmsg) as *mut _;
+            msg.msg_control = (&raw mut cmsg) as *mut _;
 
             match cvt_r(|| libc::recvmsg(sock.as_raw(), &mut msg, libc::MSG_CMSG_CLOEXEC)) {
                 Err(_) => return -1,
                 Ok(_) => {}
             }
 
-            let hdr = CMSG_FIRSTHDR(core::ptr::addr_of_mut!(msg) as *mut _);
+            let hdr = CMSG_FIRSTHDR((&raw mut msg) as *mut _);
             if hdr.is_null()
                 || (*hdr).cmsg_level != SOL_SOCKET
                 || (*hdr).cmsg_type != SCM_RIGHTS
@@ -1190,8 +1190,8 @@ impl ExitStatusError {
 mod linux_child_ext {
 
     use crate::os::linux::process as os;
-    use crate::sys::pal::unix::linux::pidfd as imp;
     use crate::sys::pal::unix::ErrorKind;
+    use crate::sys::pal::unix::linux::pidfd as imp;
     use crate::sys_common::FromInner;
     use crate::{io, mem};
 
diff --git a/library/std/src/sys/pal/unix/process/process_vxworks.rs b/library/std/src/sys/pal/unix/process/process_vxworks.rs
index 0477b3d9a70..38daf6af918 100644
--- a/library/std/src/sys/pal/unix/process/process_vxworks.rs
+++ b/library/std/src/sys/pal/unix/process/process_vxworks.rs
@@ -1,5 +1,5 @@
 #![forbid(unsafe_op_in_unsafe_fn)]
-use libc::{self, c_char, c_int, RTP_ID};
+use libc::{self, RTP_ID, c_char, c_int};
 
 use crate::io::{self, ErrorKind};
 use crate::num::NonZero;
@@ -57,7 +57,7 @@ impl Command {
                 t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO)));
             }
 
-            if let Some(ref cwd) = *self.get_cwd() {
+            if let Some(cwd) = self.get_cwd() {
                 t!(cvt(libc::chdir(cwd.as_ptr())));
             }
 
diff --git a/library/std/src/sys/pal/unix/rand.rs b/library/std/src/sys/pal/unix/rand.rs
deleted file mode 100644
index cc0852aab43..00000000000
--- a/library/std/src/sys/pal/unix/rand.rs
+++ /dev/null
@@ -1,302 +0,0 @@
-pub fn hashmap_random_keys() -> (u64, u64) {
-    const KEY_LEN: usize = core::mem::size_of::<u64>();
-
-    let mut v = [0u8; KEY_LEN * 2];
-    if let Err(err) = read(&mut v) {
-        panic!("failed to retrieve random hash map seed: {err}");
-    }
-
-    let key1 = v[0..KEY_LEN].try_into().unwrap();
-    let key2 = v[KEY_LEN..].try_into().unwrap();
-
-    (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2))
-}
-
-cfg_if::cfg_if! {
-    if #[cfg(any(
-        target_vendor = "apple",
-        target_os = "openbsd",
-        target_os = "emscripten",
-        target_os = "vita",
-        all(target_os = "netbsd", not(netbsd10)),
-        target_os = "fuchsia",
-        target_os = "vxworks",
-    ))] {
-        // Some systems have a syscall that directly retrieves random data.
-        // If that is guaranteed to be available, use it.
-        use imp::syscall as read;
-    } else {
-        // Otherwise, try the syscall to see if it exists only on some systems
-        // and fall back to reading from the random device otherwise.
-        fn read(bytes: &mut [u8]) -> crate::io::Result<()> {
-            use crate::fs::File;
-            use crate::io::Read;
-            use crate::sync::OnceLock;
-
-            #[cfg(any(
-                target_os = "linux",
-                target_os = "android",
-                target_os = "espidf",
-                target_os = "horizon",
-                target_os = "freebsd",
-                target_os = "dragonfly",
-                target_os = "solaris",
-                target_os = "illumos",
-                netbsd10,
-            ))]
-            if let Some(res) = imp::syscall(bytes) {
-                return res;
-            }
-
-            const PATH: &'static str = if cfg!(target_os = "redox") {
-                "/scheme/rand"
-            } else {
-                "/dev/urandom"
-            };
-
-            static FILE: OnceLock<File> = OnceLock::new();
-
-            FILE.get_or_try_init(|| File::open(PATH))?.read_exact(bytes)
-        }
-    }
-}
-
-// All these systems a `getrandom` syscall.
-//
-// It is not guaranteed to be available, so return None to fallback to the file
-// implementation.
-#[cfg(any(
-    target_os = "linux",
-    target_os = "android",
-    target_os = "espidf",
-    target_os = "horizon",
-    target_os = "freebsd",
-    target_os = "dragonfly",
-    target_os = "solaris",
-    target_os = "illumos",
-    netbsd10,
-))]
-mod imp {
-    use crate::io::{Error, Result};
-    use crate::sync::atomic::{AtomicBool, Ordering};
-    use crate::sys::os::errno;
-
-    #[cfg(any(target_os = "linux", target_os = "android"))]
-    fn getrandom(buf: &mut [u8]) -> libc::ssize_t {
-        use crate::sys::weak::syscall;
-
-        // A weak symbol allows interposition, e.g. for perf measurements that want to
-        // disable randomness for consistency. Otherwise, we'll try a raw syscall.
-        // (`getrandom` was added in glibc 2.25, musl 1.1.20, android API level 28)
-        syscall! {
-            fn getrandom(
-                buffer: *mut libc::c_void,
-                length: libc::size_t,
-                flags: libc::c_uint
-            ) -> libc::ssize_t
-        }
-
-        // This provides the best quality random numbers available at the given moment
-        // without ever blocking, and is preferable to falling back to /dev/urandom.
-        static GRND_INSECURE_AVAILABLE: AtomicBool = AtomicBool::new(true);
-        if GRND_INSECURE_AVAILABLE.load(Ordering::Relaxed) {
-            let ret = unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_INSECURE) };
-            if ret == -1 && errno() as libc::c_int == libc::EINVAL {
-                GRND_INSECURE_AVAILABLE.store(false, Ordering::Relaxed);
-            } else {
-                return ret;
-            }
-        }
-
-        unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_NONBLOCK) }
-    }
-
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "espidf",
-        target_os = "horizon",
-        target_os = "freebsd",
-        netbsd10,
-        target_os = "illumos",
-        target_os = "solaris"
-    ))]
-    fn getrandom(buf: &mut [u8]) -> libc::ssize_t {
-        unsafe { libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) }
-    }
-
-    pub fn syscall(v: &mut [u8]) -> Option<Result<()>> {
-        static GETRANDOM_UNAVAILABLE: AtomicBool = AtomicBool::new(false);
-
-        if GETRANDOM_UNAVAILABLE.load(Ordering::Relaxed) {
-            return None;
-        }
-
-        let mut read = 0;
-        while read < v.len() {
-            let result = getrandom(&mut v[read..]);
-            if result == -1 {
-                let err = errno() as libc::c_int;
-                if err == libc::EINTR {
-                    continue;
-                } else if err == libc::ENOSYS || err == libc::EPERM {
-                    // `getrandom` is not supported on the current system.
-                    //
-                    // Also fall back in case it is disabled by something like
-                    // seccomp or inside of docker.
-                    //
-                    // If the `getrandom` syscall is not implemented in the current kernel version it should return an
-                    // `ENOSYS` error. Docker also blocks the whole syscall inside unprivileged containers, and
-                    // returns `EPERM` (instead of `ENOSYS`) when a program tries to invoke the syscall. Because of
-                    // that we need to check for *both* `ENOSYS` and `EPERM`.
-                    //
-                    // Note that Docker's behavior is breaking other projects (notably glibc), so they're planning
-                    // to update their filtering to return `ENOSYS` in a future release:
-                    //
-                    //     https://github.com/moby/moby/issues/42680
-                    //
-                    GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed);
-                    return None;
-                } else if err == libc::EAGAIN {
-                    // getrandom has failed because it would have blocked as the
-                    // non-blocking pool (urandom) has not been initialized in
-                    // the kernel yet due to a lack of entropy. Fallback to
-                    // reading from `/dev/urandom` which will return potentially
-                    // insecure random data to avoid blocking applications which
-                    // could depend on this call without ever knowing they do and
-                    // don't have a work around.
-                    return None;
-                } else {
-                    return Some(Err(Error::from_raw_os_error(err)));
-                }
-            } else {
-                read += result as usize;
-            }
-        }
-
-        Some(Ok(()))
-    }
-}
-
-#[cfg(any(
-    target_os = "macos", // Supported since macOS 10.12+.
-    target_os = "openbsd",
-    target_os = "emscripten",
-    target_os = "vita",
-))]
-mod imp {
-    use crate::io::{Error, Result};
-
-    pub fn syscall(v: &mut [u8]) -> Result<()> {
-        // getentropy(2) permits a maximum buffer size of 256 bytes
-        for s in v.chunks_mut(256) {
-            let ret = unsafe { libc::getentropy(s.as_mut_ptr().cast(), s.len()) };
-            if ret == -1 {
-                return Err(Error::last_os_error());
-            }
-        }
-
-        Ok(())
-    }
-}
-
-// On Apple platforms, `CCRandomGenerateBytes` and `SecRandomCopyBytes` simply
-// call into `CCRandomCopyBytes` with `kCCRandomDefault`. `CCRandomCopyBytes`
-// manages a CSPRNG which is seeded from the kernel's CSPRNG and which runs on
-// its own thread accessed via GCD. This seems needlessly heavyweight for our purposes
-// so we only use it when `getentropy` is blocked, which appears to be the case
-// on all platforms except macOS (see #102643).
-//
-// `CCRandomGenerateBytes` is used instead of `SecRandomCopyBytes` because the former is accessible
-// via `libSystem` (libc) while the other needs to link to `Security.framework`.
-#[cfg(all(target_vendor = "apple", not(target_os = "macos")))]
-mod imp {
-    use libc::size_t;
-
-    use crate::ffi::{c_int, c_void};
-    use crate::io::{Error, Result};
-
-    pub fn syscall(v: &mut [u8]) -> Result<()> {
-        extern "C" {
-            fn CCRandomGenerateBytes(bytes: *mut c_void, count: size_t) -> c_int;
-        }
-
-        let ret = unsafe { CCRandomGenerateBytes(v.as_mut_ptr().cast(), v.len()) };
-        if ret != -1 { Ok(()) } else { Err(Error::last_os_error()) }
-    }
-}
-
-// FIXME: once the 10.x release becomes the minimum, this can be dropped for simplification.
-#[cfg(all(target_os = "netbsd", not(netbsd10)))]
-mod imp {
-    use crate::io::{Error, Result};
-    use crate::ptr;
-
-    pub fn syscall(v: &mut [u8]) -> Result<()> {
-        let mib = [libc::CTL_KERN, libc::KERN_ARND];
-        // kern.arandom permits a maximum buffer size of 256 bytes
-        for s in v.chunks_mut(256) {
-            let mut s_len = s.len();
-            let ret = unsafe {
-                libc::sysctl(
-                    mib.as_ptr(),
-                    mib.len() as libc::c_uint,
-                    s.as_mut_ptr() as *mut _,
-                    &mut s_len,
-                    ptr::null(),
-                    0,
-                )
-            };
-            if ret == -1 {
-                return Err(Error::last_os_error());
-            } else if s_len != s.len() {
-                // FIXME(joboet): this can't actually happen, can it?
-                panic!("read less bytes than requested from kern.arandom");
-            }
-        }
-
-        Ok(())
-    }
-}
-
-#[cfg(target_os = "fuchsia")]
-mod imp {
-    use crate::io::Result;
-
-    #[link(name = "zircon")]
-    extern "C" {
-        fn zx_cprng_draw(buffer: *mut u8, len: usize);
-    }
-
-    pub fn syscall(v: &mut [u8]) -> Result<()> {
-        unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) };
-        Ok(())
-    }
-}
-
-#[cfg(target_os = "vxworks")]
-mod imp {
-    use core::sync::atomic::AtomicBool;
-    use core::sync::atomic::Ordering::Relaxed;
-
-    use crate::io::{Error, Result};
-
-    pub fn syscall(v: &mut [u8]) -> Result<()> {
-        static RNG_INIT: AtomicBool = AtomicBool::new(false);
-        while !RNG_INIT.load(Relaxed) {
-            let ret = unsafe { libc::randSecure() };
-            if ret < 0 {
-                return Err(Error::last_os_error());
-            } else if ret > 0 {
-                RNG_INIT.store(true, Relaxed);
-                break;
-            }
-
-            unsafe { libc::usleep(10) };
-        }
-
-        let ret = unsafe {
-            libc::randABytes(v.as_mut_ptr() as *mut libc::c_uchar, v.len() as libc::c_int)
-        };
-        if ret >= 0 { Ok(()) } else { Err(Error::last_os_error()) }
-    }
-}
diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs
index 728ce8d60f6..ac0858e1de8 100644
--- a/library/std/src/sys/pal/unix/stack_overflow.rs
+++ b/library/std/src/sys/pal/unix/stack_overflow.rs
@@ -36,21 +36,20 @@ impl Drop for Handler {
     target_os = "illumos",
 ))]
 mod imp {
+    use libc::{
+        MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SA_ONSTACK,
+        SA_SIGINFO, SIG_DFL, SIGBUS, SIGSEGV, SS_DISABLE, sigaction, sigaltstack, sighandler_t,
+    };
     #[cfg(not(all(target_os = "linux", target_env = "gnu")))]
     use libc::{mmap as mmap64, mprotect, munmap};
     #[cfg(all(target_os = "linux", target_env = "gnu"))]
     use libc::{mmap64, mprotect, munmap};
-    use libc::{
-        sigaction, sigaltstack, sighandler_t, MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_PRIVATE,
-        PROT_NONE, PROT_READ, PROT_WRITE, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIGSEGV, SIG_DFL,
-        SS_DISABLE,
-    };
 
     use super::Handler;
     use crate::cell::Cell;
     use crate::ops::Range;
-    use crate::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering};
     use crate::sync::OnceLock;
+    use crate::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering};
     use crate::sys::pal::unix::os;
     use crate::{io, mem, ptr, thread};
 
@@ -427,8 +426,8 @@ mod imp {
             match sysctlbyname.get() {
                 Some(fcn) if unsafe {
                     fcn(oid.as_ptr(),
-                        ptr::addr_of_mut!(guard).cast(),
-                        ptr::addr_of_mut!(size),
+                        (&raw mut guard).cast(),
+                        &raw mut size,
                         ptr::null_mut(),
                         0) == 0
                 } => guard,
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index c9dcc5ad97a..04024661836 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -117,13 +117,15 @@ impl Thread {
     pub fn set_name(name: &CStr) {
         const PR_SET_NAME: libc::c_int = 15;
         unsafe {
-            libc::prctl(
+            let res = libc::prctl(
                 PR_SET_NAME,
                 name.as_ptr(),
                 0 as libc::c_ulong,
                 0 as libc::c_ulong,
                 0 as libc::c_ulong,
             );
+            // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
+            debug_assert_eq!(res, 0);
         }
     }
 
@@ -140,7 +142,12 @@ impl Thread {
         }
     }
 
-    #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "dragonfly",
+        target_os = "openbsd",
+        target_os = "nuttx"
+    ))]
     pub fn set_name(name: &CStr) {
         unsafe {
             libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr());
@@ -253,7 +260,7 @@ impl Thread {
                     tv_nsec: nsecs,
                 };
                 secs -= ts.tv_sec as u64;
-                let ts_ptr = core::ptr::addr_of_mut!(ts);
+                let ts_ptr = &raw mut ts;
                 if libc::nanosleep(ts_ptr, ts_ptr) == -1 {
                     assert_eq!(os::errno(), libc::EINTR);
                     secs += ts.tv_sec as u64;
@@ -442,8 +449,8 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                     libc::sysctl(
                         mib.as_mut_ptr(),
                         2,
-                        core::ptr::addr_of_mut!(cpus) as *mut _,
-                        core::ptr::addr_of_mut!(cpus_size) as *mut _,
+                        (&raw mut cpus) as *mut _,
+                        (&raw mut cpus_size) as *mut _,
                         ptr::null_mut(),
                         0,
                     )
@@ -516,8 +523,8 @@ mod cgroups {
 
     use crate::borrow::Cow;
     use crate::ffi::OsString;
-    use crate::fs::{exists, File};
-    use crate::io::{BufRead, BufReader, Read};
+    use crate::fs::{File, exists};
+    use crate::io::{BufRead, Read};
     use crate::os::unix::ffi::OsStringExt;
     use crate::path::{Path, PathBuf};
     use crate::str::from_utf8;
@@ -690,7 +697,7 @@ mod cgroups {
     /// If the cgroupfs is a bind mount then `group_path` is adjusted to skip
     /// over the already-included prefix
     fn find_mountpoint(group_path: &Path) -> Option<(Cow<'static, str>, &Path)> {
-        let mut reader = BufReader::new(File::open("/proc/self/mountinfo").ok()?);
+        let mut reader = File::open_buffered("/proc/self/mountinfo").ok()?;
         let mut line = String::with_capacity(256);
         loop {
             line.clear();
@@ -747,12 +754,15 @@ unsafe fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
 }
 
 // No point in looking up __pthread_get_minstack() on non-glibc platforms.
-#[cfg(all(not(all(target_os = "linux", target_env = "gnu")), not(target_os = "netbsd")))]
+#[cfg(all(
+    not(all(target_os = "linux", target_env = "gnu")),
+    not(any(target_os = "netbsd", target_os = "nuttx"))
+))]
 unsafe fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
     libc::PTHREAD_STACK_MIN
 }
 
-#[cfg(target_os = "netbsd")]
+#[cfg(any(target_os = "netbsd", target_os = "nuttx"))]
 unsafe fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
     static STACK: crate::sync::OnceLock<usize> = crate::sync::OnceLock::new();
 
diff --git a/library/std/src/sys/pal/unix/thread_parking.rs b/library/std/src/sys/pal/unix/thread_parking.rs
index 1da5fce3cd3..72dd2031479 100644
--- a/library/std/src/sys/pal/unix/thread_parking.rs
+++ b/library/std/src/sys/pal/unix/thread_parking.rs
@@ -2,7 +2,7 @@
 // separate modules for each platform.
 #![cfg(target_os = "netbsd")]
 
-use libc::{_lwp_self, c_long, clockid_t, lwpid_t, time_t, timespec, CLOCK_MONOTONIC};
+use libc::{_lwp_self, CLOCK_MONOTONIC, c_long, clockid_t, lwpid_t, time_t, timespec};
 
 use crate::ffi::{c_int, c_void};
 use crate::ptr;
diff --git a/library/std/src/sys/pal/unsupported/common.rs b/library/std/src/sys/pal/unsupported/common.rs
index 76f80291f0e..34a76668383 100644
--- a/library/std/src/sys/pal/unsupported/common.rs
+++ b/library/std/src/sys/pal/unsupported/common.rs
@@ -27,7 +27,3 @@ pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind {
 pub fn abort_internal() -> ! {
     core::intrinsics::abort();
 }
-
-pub fn hashmap_random_keys() -> (u64, u64) {
-    (1, 2)
-}
diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs
index e1c61cae9f8..59ecc45b06a 100644
--- a/library/std/src/sys/pal/wasi/fs.rs
+++ b/library/std/src/sys/pal/wasi/fs.rs
@@ -13,7 +13,7 @@ use crate::sys::common::small_c_string::run_path_with_cstr;
 use crate::sys::time::SystemTime;
 use crate::sys::unsupported;
 pub use crate::sys_common::fs::exists;
-use crate::sys_common::{ignore_notfound, AsInner, FromInner, IntoInner};
+use crate::sys_common::{AsInner, FromInner, IntoInner, ignore_notfound};
 use crate::{fmt, iter, ptr};
 
 pub struct File {
diff --git a/library/std/src/sys/pal/wasi/helpers.rs b/library/std/src/sys/pal/wasi/helpers.rs
index 37ef17858cb..404747f0dc7 100644
--- a/library/std/src/sys/pal/wasi/helpers.rs
+++ b/library/std/src/sys/pal/wasi/helpers.rs
@@ -1,6 +1,6 @@
 #![forbid(unsafe_op_in_unsafe_fn)]
 
-use crate::{io as std_io, mem};
+use crate::io as std_io;
 
 #[inline]
 pub fn is_interrupted(errno: i32) -> bool {
@@ -108,16 +108,6 @@ pub fn abort_internal() -> ! {
     unsafe { libc::abort() }
 }
 
-pub fn hashmap_random_keys() -> (u64, u64) {
-    let mut ret = (0u64, 0u64);
-    unsafe {
-        let base = &mut ret as *mut (u64, u64) as *mut u8;
-        let len = mem::size_of_val(&ret);
-        wasi::random_get(base, len).expect("random_get failure");
-    }
-    ret
-}
-
 #[inline]
 pub(crate) fn err2io(err: wasi::Errno) -> std_io::Error {
     std_io::Error::from_raw_os_error(err.raw().into())
diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs
index 8051021a588..5d54c790306 100644
--- a/library/std/src/sys/pal/wasi/mod.rs
+++ b/library/std/src/sys/pal/wasi/mod.rs
@@ -47,4 +47,4 @@ mod helpers;
 // then the compiler complains about conflicts.
 
 use helpers::err2io;
-pub use helpers::{abort_internal, decode_error_kind, hashmap_random_keys, is_interrupted};
+pub use helpers::{abort_internal, decode_error_kind, is_interrupted};
diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs
index 546fadbe501..320712fdcc9 100644
--- a/library/std/src/sys/pal/wasip2/mod.rs
+++ b/library/std/src/sys/pal/wasip2/mod.rs
@@ -20,7 +20,6 @@ pub mod futex;
 #[path = "../wasi/io.rs"]
 pub mod io;
 
-#[path = "../wasi/net.rs"]
 pub mod net;
 #[path = "../wasi/os.rs"]
 pub mod os;
@@ -50,6 +49,6 @@ mod helpers;
 // then the compiler complains about conflicts.
 
 use helpers::err2io;
-pub use helpers::{abort_internal, decode_error_kind, hashmap_random_keys, is_interrupted};
+pub use helpers::{abort_internal, decode_error_kind, is_interrupted};
 
 mod cabi_realloc;
diff --git a/library/std/src/sys/pal/wasip2/net.rs b/library/std/src/sys/pal/wasip2/net.rs
new file mode 100644
index 00000000000..06e623df843
--- /dev/null
+++ b/library/std/src/sys/pal/wasip2/net.rs
@@ -0,0 +1,417 @@
+#![deny(unsafe_op_in_unsafe_fn)]
+
+use libc::{c_int, c_void, size_t};
+
+use crate::ffi::CStr;
+use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
+use crate::net::{Shutdown, SocketAddr};
+use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+use crate::sys::unsupported;
+use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::time::{Duration, Instant};
+use crate::{cmp, mem, str};
+
+pub extern crate libc as netc;
+
+#[allow(non_camel_case_types)]
+pub type wrlen_t = size_t;
+
+#[doc(hidden)]
+pub trait IsMinusOne {
+    fn is_minus_one(&self) -> bool;
+}
+
+macro_rules! impl_is_minus_one {
+    ($($t:ident)*) => ($(impl IsMinusOne for $t {
+        fn is_minus_one(&self) -> bool {
+            *self == -1
+        }
+    })*)
+}
+
+impl_is_minus_one! { i8 i16 i32 i64 isize }
+
+pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
+    if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) }
+}
+
+pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
+where
+    T: IsMinusOne,
+    F: FnMut() -> T,
+{
+    loop {
+        match cvt(f()) {
+            Err(ref e) if e.is_interrupted() => {}
+            other => return other,
+        }
+    }
+}
+
+pub fn cvt_gai(err: c_int) -> io::Result<()> {
+    if err == 0 {
+        return Ok(());
+    }
+
+    if err == netc::EAI_SYSTEM {
+        return Err(io::Error::last_os_error());
+    }
+
+    let detail = unsafe {
+        str::from_utf8(CStr::from_ptr(netc::gai_strerror(err)).to_bytes()).unwrap().to_owned()
+    };
+
+    Err(io::Error::new(
+        io::ErrorKind::Uncategorized,
+        &format!("failed to lookup address information: {detail}")[..],
+    ))
+}
+
+pub fn init() {}
+
+pub struct WasiSocket(OwnedFd);
+
+pub struct Socket(WasiSocket);
+
+impl Socket {
+    pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
+        let fam = match *addr {
+            SocketAddr::V4(..) => netc::AF_INET,
+            SocketAddr::V6(..) => netc::AF_INET6,
+        };
+        Socket::new_raw(fam, ty)
+    }
+
+    pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
+        let fd = cvt(unsafe { netc::socket(fam, ty, 0) })?;
+        Ok(unsafe { Self::from_raw_fd(fd) })
+    }
+
+    pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
+        let (addr, len) = addr.into_inner();
+        cvt_r(|| unsafe { netc::connect(self.as_raw_fd(), addr.as_ptr(), len) })?;
+        Ok(())
+    }
+
+    pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
+        self.set_nonblocking(true)?;
+        let r = self.connect(addr);
+        self.set_nonblocking(false)?;
+
+        match r {
+            Ok(_) => return Ok(()),
+            // there's no ErrorKind for EINPROGRESS
+            Err(ref e) if e.raw_os_error() == Some(netc::EINPROGRESS) => {}
+            Err(e) => return Err(e),
+        }
+
+        let mut pollfd = netc::pollfd { fd: self.as_raw_fd(), events: netc::POLLOUT, revents: 0 };
+
+        if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
+            return Err(io::Error::ZERO_TIMEOUT);
+        }
+
+        let start = Instant::now();
+
+        loop {
+            let elapsed = start.elapsed();
+            if elapsed >= timeout {
+                return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out"));
+            }
+
+            let timeout = timeout - elapsed;
+            let mut timeout = timeout
+                .as_secs()
+                .saturating_mul(1_000)
+                .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000);
+            if timeout == 0 {
+                timeout = 1;
+            }
+
+            let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int;
+
+            match unsafe { netc::poll(&mut pollfd, 1, timeout) } {
+                -1 => {
+                    let err = io::Error::last_os_error();
+                    if !err.is_interrupted() {
+                        return Err(err);
+                    }
+                }
+                0 => {}
+                _ => {
+                    // WASI poll does not return  POLLHUP or POLLERR in revents. Check if the
+                    // connnection actually succeeded and return ok only when the socket is
+                    // ready and no errors were found.
+                    if let Some(e) = self.take_error()? {
+                        return Err(e);
+                    }
+
+                    return Ok(());
+                }
+            }
+        }
+    }
+
+    pub fn accept(
+        &self,
+        storage: *mut netc::sockaddr,
+        len: *mut netc::socklen_t,
+    ) -> io::Result<Socket> {
+        let fd = cvt_r(|| unsafe { netc::accept(self.as_raw_fd(), storage, len) })?;
+        Ok(unsafe { Self::from_raw_fd(fd) })
+    }
+
+    pub fn duplicate(&self) -> io::Result<Socket> {
+        unsupported()
+    }
+
+    fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> {
+        let ret = cvt(unsafe {
+            netc::recv(
+                self.as_raw_fd(),
+                buf.as_mut().as_mut_ptr() as *mut c_void,
+                buf.capacity(),
+                flags,
+            )
+        })?;
+        unsafe {
+            buf.advance_unchecked(ret as usize);
+        }
+        Ok(())
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        let mut buf = BorrowedBuf::from(buf);
+        self.recv_with_flags(buf.unfilled(), 0)?;
+        Ok(buf.len())
+    }
+
+    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+        let mut buf = BorrowedBuf::from(buf);
+        self.recv_with_flags(buf.unfilled(), netc::MSG_PEEK)?;
+        Ok(buf.len())
+    }
+
+    pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.recv_with_flags(buf, 0)
+    }
+
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        io::default_read_vectored(|b| self.read(b), bufs)
+    }
+
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        false
+    }
+
+    fn recv_from_with_flags(
+        &self,
+        buf: &mut [u8],
+        flags: c_int,
+    ) -> io::Result<(usize, SocketAddr)> {
+        let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() };
+        let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
+
+        let n = cvt(unsafe {
+            netc::recvfrom(
+                self.as_raw_fd(),
+                buf.as_mut_ptr() as *mut c_void,
+                buf.len(),
+                flags,
+                core::ptr::addr_of_mut!(storage) as *mut _,
+                &mut addrlen,
+            )
+        })?;
+        Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
+    }
+
+    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.recv_from_with_flags(buf, 0)
+    }
+
+    pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.recv_from_with_flags(buf, netc::MSG_PEEK)
+    }
+
+    fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
+        let ret = cvt(unsafe {
+            netc::send(self.as_raw(), buf.as_ptr() as *const c_void, len, netc::MSG_NOSIGNAL)
+        })?;
+        Ok(ret as usize)
+    }
+
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        io::default_write_vectored(|b| self.write(b), bufs)
+    }
+
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        false
+    }
+
+    pub fn set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()> {
+        let timeout = match dur {
+            Some(dur) => {
+                if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
+                    return Err(io::Error::ZERO_TIMEOUT);
+                }
+
+                let secs = dur.as_secs().try_into().unwrap_or(netc::time_t::MAX);
+                let mut timeout = netc::timeval {
+                    tv_sec: secs,
+                    tv_usec: dur.subsec_micros() as netc::suseconds_t,
+                };
+                if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+                    timeout.tv_usec = 1;
+                }
+                timeout
+            }
+            None => netc::timeval { tv_sec: 0, tv_usec: 0 },
+        };
+        setsockopt(self, netc::SOL_SOCKET, kind, timeout)
+    }
+
+    pub fn timeout(&self, kind: c_int) -> io::Result<Option<Duration>> {
+        let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?;
+        if raw.tv_sec == 0 && raw.tv_usec == 0 {
+            Ok(None)
+        } else {
+            let sec = raw.tv_sec as u64;
+            let nsec = (raw.tv_usec as u32) * 1000;
+            Ok(Some(Duration::new(sec, nsec)))
+        }
+    }
+
+    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+        let how = match how {
+            Shutdown::Write => netc::SHUT_WR,
+            Shutdown::Read => netc::SHUT_RD,
+            Shutdown::Both => netc::SHUT_RDWR,
+        };
+        cvt(unsafe { netc::shutdown(self.as_raw_fd(), how) })?;
+        Ok(())
+    }
+
+    pub fn set_linger(&self, _linger: Option<Duration>) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn linger(&self) -> io::Result<Option<Duration>> {
+        unsupported()
+    }
+
+    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+        setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int)
+    }
+
+    pub fn nodelay(&self) -> io::Result<bool> {
+        let raw: c_int = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?;
+        Ok(raw != 0)
+    }
+
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        let mut nonblocking = nonblocking as c_int;
+        cvt(unsafe { netc::ioctl(self.as_raw_fd(), netc::FIONBIO, &mut nonblocking) }).map(drop)
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        let raw: c_int = getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)?;
+        if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
+    }
+
+    // This is used by sys_common code to abstract over Windows and Unix.
+    pub fn as_raw(&self) -> RawFd {
+        self.as_raw_fd()
+    }
+}
+
+impl AsInner<OwnedFd> for WasiSocket {
+    #[inline]
+    fn as_inner(&self) -> &OwnedFd {
+        &self.0
+    }
+}
+
+impl IntoInner<OwnedFd> for WasiSocket {
+    fn into_inner(self) -> OwnedFd {
+        self.0
+    }
+}
+
+impl FromInner<OwnedFd> for WasiSocket {
+    fn from_inner(owned_fd: OwnedFd) -> Self {
+        Self(owned_fd)
+    }
+}
+
+impl AsFd for WasiSocket {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
+}
+
+impl AsRawFd for WasiSocket {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+
+impl IntoRawFd for WasiSocket {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
+    }
+}
+
+impl FromRawFd for WasiSocket {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) }
+    }
+}
+
+impl AsInner<WasiSocket> for Socket {
+    #[inline]
+    fn as_inner(&self) -> &WasiSocket {
+        &self.0
+    }
+}
+
+impl IntoInner<WasiSocket> for Socket {
+    fn into_inner(self) -> WasiSocket {
+        self.0
+    }
+}
+
+impl FromInner<WasiSocket> for Socket {
+    fn from_inner(sock: WasiSocket) -> Socket {
+        Socket(sock)
+    }
+}
+
+impl AsFd for Socket {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
+}
+
+impl AsRawFd for Socket {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+
+impl IntoRawFd for Socket {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
+    }
+}
+
+impl FromRawFd for Socket {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) }
+    }
+}
diff --git a/library/std/src/sys/pal/windows/api.rs b/library/std/src/sys/pal/windows/api.rs
index 9e336ff2d47..ebe207fde93 100644
--- a/library/std/src/sys/pal/windows/api.rs
+++ b/library/std/src/sys/pal/windows/api.rs
@@ -30,7 +30,6 @@
 //! should go in sys/pal/windows/mod.rs rather than here. See `IoResult` as an example.
 
 use core::ffi::c_void;
-use core::ptr::addr_of;
 
 use super::c;
 
@@ -186,7 +185,7 @@ unsafe trait SizedSetFileInformation: Sized {
 unsafe impl<T: SizedSetFileInformation> SetFileInformation for T {
     const CLASS: i32 = T::CLASS;
     fn as_ptr(&self) -> *const c_void {
-        addr_of!(*self).cast::<c_void>()
+        (&raw const *self).cast::<c_void>()
     }
     fn size(&self) -> u32 {
         win32_size_of::<Self>()
diff --git a/library/std/src/sys/pal/windows/args.rs b/library/std/src/sys/pal/windows/args.rs
index 77d82678f1d..848632ec2a7 100644
--- a/library/std/src/sys/pal/windows/args.rs
+++ b/library/std/src/sys/pal/windows/args.rs
@@ -14,8 +14,8 @@ use crate::path::{Path, PathBuf};
 use crate::sys::path::get_long_path;
 use crate::sys::process::ensure_no_nuls;
 use crate::sys::{c, to_u16s};
-use crate::sys_common::wstr::WStrUnits;
 use crate::sys_common::AsInner;
+use crate::sys_common::wstr::WStrUnits;
 use crate::{fmt, io, iter, vec};
 
 /// This is the const equivalent to `NonZero::new(n).unwrap()`
diff --git a/library/std/src/sys/pal/windows/args/tests.rs b/library/std/src/sys/pal/windows/args/tests.rs
index 484a90ab056..6d5c953cbd5 100644
--- a/library/std/src/sys/pal/windows/args/tests.rs
+++ b/library/std/src/sys/pal/windows/args/tests.rs
@@ -47,10 +47,10 @@ fn whitespace_behavior() {
 fn genius_quotes() {
     chk(r#"EXE "" """#, &["EXE", "", ""]);
     chk(r#"EXE "" """"#, &["EXE", "", r#"""#]);
-    chk(
-        r#"EXE "this is """all""" in the same argument""#,
-        &["EXE", r#"this is "all" in the same argument"#],
-    );
+    chk(r#"EXE "this is """all""" in the same argument""#, &[
+        "EXE",
+        r#"this is "all" in the same argument"#,
+    ]);
     chk(r#"EXE "a"""#, &["EXE", r#"a""#]);
     chk(r#"EXE "a"" a"#, &["EXE", r#"a" a"#]);
     // quotes cannot be escaped in command names
diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
index b888eb7d95c..9ce3e912caf 100644
--- a/library/std/src/sys/pal/windows/c.rs
+++ b/library/std/src/sys/pal/windows/c.rs
@@ -5,7 +5,7 @@
 #![unstable(issue = "none", feature = "windows_c")]
 #![allow(clippy::style)]
 
-use core::ffi::{c_uint, c_ulong, c_ushort, c_void, CStr};
+use core::ffi::{CStr, c_uint, c_ulong, c_ushort, c_void};
 use core::{mem, ptr};
 
 mod windows_sys;
@@ -175,9 +175,9 @@ extern "system" {
     pub fn WakeByAddressAll(address: *const c_void);
 }
 
+// These are loaded by `load_synch_functions`.
 #[cfg(target_vendor = "win7")]
 compat_fn_optional! {
-    crate::sys::compat::load_synch_functions();
     pub fn WaitOnAddress(
         address: *const c_void,
         compareaddress: *const c_void,
diff --git a/library/std/src/sys/pal/windows/compat.rs b/library/std/src/sys/pal/windows/compat.rs
index 75232dfc0b0..42999da1664 100644
--- a/library/std/src/sys/pal/windows/compat.rs
+++ b/library/std/src/sys/pal/windows/compat.rs
@@ -19,7 +19,7 @@
 //! function is called. In the worst case, multiple threads may all end up
 //! importing the same function unnecessarily.
 
-use crate::ffi::{c_void, CStr};
+use crate::ffi::{CStr, c_void};
 use crate::ptr::NonNull;
 use crate::sys::c;
 
@@ -198,11 +198,10 @@ macro_rules! compat_fn_with_fallback {
 
 /// Optionally loaded functions.
 ///
-/// Actual loading of the function defers to $load_functions.
+/// Relies on the functions being pre-loaded elsewhere.
 #[cfg(target_vendor = "win7")]
 macro_rules! compat_fn_optional {
-    ($load_functions:expr;
-    $(
+    ($(
         $(#[$meta:meta])*
         $vis:vis fn $symbol:ident($($argname:ident: $argtype:ty),*) $(-> $rettype:ty)?;
     )+) => (
@@ -221,9 +220,6 @@ macro_rules! compat_fn_optional {
 
                 #[inline(always)]
                 pub fn option() -> Option<F> {
-                    // Miri does not understand the way we do preloading
-                    // therefore load the function here instead.
-                    #[cfg(miri)] $load_functions;
                     NonNull::new(PTR.load(Ordering::Relaxed)).map(|f| unsafe { mem::transmute(f) })
                 }
             }
diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs
index 5b360640c4e..aab471e28ea 100644
--- a/library/std/src/sys/pal/windows/fs.rs
+++ b/library/std/src/sys/pal/windows/fs.rs
@@ -1,9 +1,7 @@
-use core::ptr::addr_of;
-
 use super::api::{self, WinError};
-use super::{to_u16s, IoResult};
+use super::{IoResult, to_u16s};
 use crate::borrow::Cow;
-use crate::ffi::{c_void, OsStr, OsString};
+use crate::ffi::{OsStr, OsString, c_void};
 use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
 use crate::mem::{self, MaybeUninit};
 use crate::os::windows::io::{AsHandle, BorrowedHandle};
@@ -13,7 +11,7 @@ use crate::sync::Arc;
 use crate::sys::handle::Handle;
 use crate::sys::path::maybe_verbatim;
 use crate::sys::time::SystemTime;
-use crate::sys::{c, cvt, Align8};
+use crate::sys::{Align8, c, cvt};
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::{fmt, ptr, slice};
 
@@ -325,7 +323,7 @@ impl File {
                     let result = c::SetFileInformationByHandle(
                         handle.as_raw_handle(),
                         c::FileEndOfFileInfo,
-                        ptr::addr_of!(eof).cast::<c_void>(),
+                        (&raw const eof).cast::<c_void>(),
                         mem::size_of::<c::FILE_END_OF_FILE_INFO>() as u32,
                     );
                     if result == 0 {
@@ -364,7 +362,7 @@ impl File {
                 cvt(c::GetFileInformationByHandleEx(
                     self.handle.as_raw_handle(),
                     c::FileAttributeTagInfo,
-                    ptr::addr_of_mut!(attr_tag).cast(),
+                    (&raw mut attr_tag).cast(),
                     mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
                 ))?;
                 if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
@@ -396,7 +394,7 @@ impl File {
             cvt(c::GetFileInformationByHandleEx(
                 self.handle.as_raw_handle(),
                 c::FileBasicInfo,
-                core::ptr::addr_of_mut!(info) as *mut c_void,
+                (&raw mut info) as *mut c_void,
                 size as u32,
             ))?;
             let mut attr = FileAttr {
@@ -428,7 +426,7 @@ impl File {
             cvt(c::GetFileInformationByHandleEx(
                 self.handle.as_raw_handle(),
                 c::FileStandardInfo,
-                core::ptr::addr_of_mut!(info) as *mut c_void,
+                (&raw mut info) as *mut c_void,
                 size as u32,
             ))?;
             attr.file_size = info.AllocationSize as u64;
@@ -438,7 +436,7 @@ impl File {
                 cvt(c::GetFileInformationByHandleEx(
                     self.handle.as_raw_handle(),
                     c::FileAttributeTagInfo,
-                    ptr::addr_of_mut!(attr_tag).cast(),
+                    (&raw mut attr_tag).cast(),
                     mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
                 ))?;
                 if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
@@ -545,22 +543,20 @@ impl File {
         unsafe {
             let (path_buffer, subst_off, subst_len, relative) = match (*buf).ReparseTag {
                 c::IO_REPARSE_TAG_SYMLINK => {
-                    let info: *mut c::SYMBOLIC_LINK_REPARSE_BUFFER =
-                        ptr::addr_of_mut!((*buf).rest).cast();
+                    let info: *mut c::SYMBOLIC_LINK_REPARSE_BUFFER = (&raw mut (*buf).rest).cast();
                     assert!(info.is_aligned());
                     (
-                        ptr::addr_of_mut!((*info).PathBuffer).cast::<u16>(),
+                        (&raw mut (*info).PathBuffer).cast::<u16>(),
                         (*info).SubstituteNameOffset / 2,
                         (*info).SubstituteNameLength / 2,
                         (*info).Flags & c::SYMLINK_FLAG_RELATIVE != 0,
                     )
                 }
                 c::IO_REPARSE_TAG_MOUNT_POINT => {
-                    let info: *mut c::MOUNT_POINT_REPARSE_BUFFER =
-                        ptr::addr_of_mut!((*buf).rest).cast();
+                    let info: *mut c::MOUNT_POINT_REPARSE_BUFFER = (&raw mut (*buf).rest).cast();
                     assert!(info.is_aligned());
                     (
-                        ptr::addr_of_mut!((*info).PathBuffer).cast::<u16>(),
+                        (&raw mut (*info).PathBuffer).cast::<u16>(),
                         (*info).SubstituteNameOffset / 2,
                         (*info).SubstituteNameLength / 2,
                         false,
@@ -643,7 +639,7 @@ impl File {
             cvt(c::GetFileInformationByHandleEx(
                 self.handle.as_raw_handle(),
                 c::FileBasicInfo,
-                core::ptr::addr_of_mut!(info) as *mut c_void,
+                (&raw mut info) as *mut c_void,
                 size as u32,
             ))?;
             Ok(info)
@@ -790,11 +786,11 @@ impl<'a> Iterator for DirBuffIter<'a> {
             // it does not seem that reality is so kind, and assuming this
             // caused crashes in some cases (https://github.com/rust-lang/rust/issues/104530)
             // presumably, this can be blamed on buggy filesystem drivers, but who knows.
-            let next_entry = ptr::addr_of!((*info).NextEntryOffset).read_unaligned() as usize;
-            let length = ptr::addr_of!((*info).FileNameLength).read_unaligned() as usize;
-            let attrs = ptr::addr_of!((*info).FileAttributes).read_unaligned();
+            let next_entry = (&raw const (*info).NextEntryOffset).read_unaligned() as usize;
+            let length = (&raw const (*info).FileNameLength).read_unaligned() as usize;
+            let attrs = (&raw const (*info).FileAttributes).read_unaligned();
             let name = from_maybe_unaligned(
-                ptr::addr_of!((*info).FileName).cast::<u16>(),
+                (&raw const (*info).FileName).cast::<u16>(),
                 length / size_of::<u16>(),
             );
             let is_directory = (attrs & c::FILE_ATTRIBUTE_DIRECTORY) != 0;
@@ -1326,7 +1322,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
             pfrom.as_ptr(),
             pto.as_ptr(),
             Some(callback),
-            core::ptr::addr_of_mut!(size) as *mut _,
+            (&raw mut size) as *mut _,
             ptr::null_mut(),
             0,
         )
@@ -1405,7 +1401,7 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> {
         cvt(c::DeviceIoControl(
             d.as_raw_handle(),
             c::FSCTL_SET_REPARSE_POINT,
-            addr_of!(header).cast::<c_void>(),
+            (&raw const header).cast::<c_void>(),
             data_len as u32 + 8,
             ptr::null_mut(),
             0,
diff --git a/library/std/src/sys/pal/windows/futex.rs b/library/std/src/sys/pal/windows/futex.rs
index 8c5081a607a..4d6c4df9a5a 100644
--- a/library/std/src/sys/pal/windows/futex.rs
+++ b/library/std/src/sys/pal/windows/futex.rs
@@ -1,7 +1,7 @@
 use core::ffi::c_void;
 use core::sync::atomic::{
-    AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicPtr, AtomicU16,
-    AtomicU32, AtomicU64, AtomicU8, AtomicUsize,
+    AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize, AtomicPtr, AtomicU8,
+    AtomicU16, AtomicU32, AtomicU64, AtomicUsize,
 };
 use core::time::Duration;
 use core::{mem, ptr};
@@ -57,7 +57,7 @@ pub fn wait_on_address<W: Waitable>(
     unsafe {
         let addr = ptr::from_ref(address).cast::<c_void>();
         let size = mem::size_of::<W>();
-        let compare_addr = ptr::addr_of!(compare).cast::<c_void>();
+        let compare_addr = (&raw const compare).cast::<c_void>();
         let timeout = timeout.map(dur2timeout).unwrap_or(c::INFINITE);
         c::WaitOnAddress(addr, compare_addr, size, timeout) == c::TRUE
     }
diff --git a/library/std/src/sys/pal/windows/handle/tests.rs b/library/std/src/sys/pal/windows/handle/tests.rs
index d836dae4c30..0c976ed84e6 100644
--- a/library/std/src/sys/pal/windows/handle/tests.rs
+++ b/library/std/src/sys/pal/windows/handle/tests.rs
@@ -1,4 +1,4 @@
-use crate::sys::pipe::{anon_pipe, Pipes};
+use crate::sys::pipe::{Pipes, anon_pipe};
 use crate::{thread, time};
 
 /// Test the synchronous fallback for overlapped I/O.
diff --git a/library/std/src/sys/pal/windows/io.rs b/library/std/src/sys/pal/windows/io.rs
index 785a3f6768b..1e7d02908f6 100644
--- a/library/std/src/sys/pal/windows/io.rs
+++ b/library/std/src/sys/pal/windows/io.rs
@@ -122,7 +122,7 @@ fn msys_tty_on(handle: BorrowedHandle<'_>) -> bool {
         c::GetFileInformationByHandleEx(
             handle.as_raw_handle(),
             c::FileNameInfo,
-            core::ptr::addr_of_mut!(name_info) as *mut c_void,
+            (&raw mut name_info) as *mut c_void,
             size_of::<FILE_NAME_INFO>() as u32,
         )
     };
diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs
index f5ed3e4628e..a9886012e8e 100644
--- a/library/std/src/sys/pal/windows/mod.rs
+++ b/library/std/src/sys/pal/windows/mod.rs
@@ -1,7 +1,6 @@
 #![allow(missing_docs, nonstandard_style)]
 #![forbid(unsafe_op_in_unsafe_fn)]
 
-pub use self::rand::hashmap_random_keys;
 use crate::ffi::{OsStr, OsString};
 use crate::io::ErrorKind;
 use crate::mem::MaybeUninit;
@@ -27,7 +26,6 @@ pub mod net;
 pub mod os;
 pub mod pipe;
 pub mod process;
-pub mod rand;
 pub mod stdio;
 pub mod thread;
 pub mod time;
@@ -348,7 +346,6 @@ pub fn abort_internal() -> ! {
     }
 }
 
-// miri is sensitive to changes here so check that miri is happy if touching this
 #[cfg(miri)]
 pub fn abort_internal() -> ! {
     crate::intrinsics::abort();
diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs
index ce995f5ed5a..fd62d1f407c 100644
--- a/library/std/src/sys/pal/windows/net.rs
+++ b/library/std/src/sys/pal/windows/net.rs
@@ -9,7 +9,7 @@ use crate::os::windows::io::{
 };
 use crate::sync::OnceLock;
 use crate::sys::c;
-use crate::sys_common::{net, AsInner, FromInner, IntoInner};
+use crate::sys_common::{AsInner, FromInner, IntoInner, net};
 use crate::time::Duration;
 use crate::{cmp, mem, ptr, sys};
 
@@ -27,12 +27,12 @@ pub mod netc {
     use crate::sys::c::{self, ADDRESS_FAMILY, ADDRINFOA, SOCKADDR, SOCKET};
     // re-exports from Windows API bindings.
     pub use crate::sys::c::{
-        bind, connect, freeaddrinfo, getpeername, getsockname, getsockopt, listen, setsockopt,
-        ADDRESS_FAMILY as sa_family_t, ADDRINFOA as addrinfo, IPPROTO_IP, IPPROTO_IPV6,
-        IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_MULTICAST_LOOP, IPV6_V6ONLY,
-        IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL,
-        SOCKADDR as sockaddr, SOCKADDR_STORAGE as sockaddr_storage, SOCK_DGRAM, SOCK_STREAM,
-        SOL_SOCKET, SO_BROADCAST, SO_RCVTIMEO, SO_SNDTIMEO,
+        ADDRESS_FAMILY as sa_family_t, ADDRINFOA as addrinfo, IP_ADD_MEMBERSHIP,
+        IP_DROP_MEMBERSHIP, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, IPPROTO_IP, IPPROTO_IPV6,
+        IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_MULTICAST_LOOP, IPV6_V6ONLY, SO_BROADCAST,
+        SO_RCVTIMEO, SO_SNDTIMEO, SOCK_DGRAM, SOCK_STREAM, SOCKADDR as sockaddr,
+        SOCKADDR_STORAGE as sockaddr_storage, SOL_SOCKET, bind, connect, freeaddrinfo, getpeername,
+        getsockname, getsockopt, listen, setsockopt,
     };
 
     #[allow(non_camel_case_types)]
@@ -390,7 +390,7 @@ impl Socket {
                 buf.as_mut_ptr() as *mut _,
                 length,
                 flags,
-                core::ptr::addr_of_mut!(storage) as *mut _,
+                (&raw mut storage) as *mut _,
                 &mut addrlen,
             )
         };
diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs
index 7d1b5aca1d5..a8f6617c9dc 100644
--- a/library/std/src/sys/pal/windows/pipe.rs
+++ b/library/std/src/sys/pal/windows/pipe.rs
@@ -2,12 +2,13 @@ use crate::ffi::OsStr;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::os::windows::prelude::*;
 use crate::path::Path;
+use crate::random::{DefaultRandomSource, Random};
 use crate::sync::atomic::AtomicUsize;
 use crate::sync::atomic::Ordering::Relaxed;
+use crate::sys::c;
 use crate::sys::fs::{File, OpenOptions};
 use crate::sys::handle::Handle;
 use crate::sys::pal::windows::api::{self, WinError};
-use crate::sys::{c, hashmap_random_keys};
 use crate::sys_common::{FromInner, IntoInner};
 use crate::{mem, ptr};
 
@@ -79,7 +80,7 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
             name = format!(
                 r"\\.\pipe\__rust_anonymous_pipe1__.{}.{}",
                 c::GetCurrentProcessId(),
-                random_number()
+                random_number(),
             );
             let wide_name = OsStr::new(&name).encode_wide().chain(Some(0)).collect::<Vec<_>>();
             let mut flags = c::FILE_FLAG_FIRST_PIPE_INSTANCE | c::FILE_FLAG_OVERLAPPED;
@@ -214,7 +215,7 @@ fn random_number() -> usize {
             return N.fetch_add(1, Relaxed);
         }
 
-        N.store(hashmap_random_keys().0 as usize, Relaxed);
+        N.store(usize::random(&mut DefaultRandomSource), Relaxed);
     }
 }
 
@@ -374,7 +375,7 @@ impl AnonPipe {
         let mut overlapped: c::OVERLAPPED = unsafe { crate::mem::zeroed() };
         // `hEvent` is unused by `ReadFileEx` and `WriteFileEx`.
         // Therefore the documentation suggests using it to smuggle a pointer to the callback.
-        overlapped.hEvent = core::ptr::addr_of_mut!(async_result) as *mut _;
+        overlapped.hEvent = (&raw mut async_result) as *mut _;
 
         // Asynchronous read of the pipe.
         // If successful, `callback` will be called once it completes.
diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs
index d40a537e359..95b51e704f9 100644
--- a/library/std/src/sys/pal/windows/process.rs
+++ b/library/std/src/sys/pal/windows/process.rs
@@ -22,8 +22,8 @@ use crate::sys::fs::{File, OpenOptions};
 use crate::sys::handle::Handle;
 use crate::sys::pipe::{self, AnonPipe};
 use crate::sys::{cvt, path, stdio};
-use crate::sys_common::process::{CommandEnv, CommandEnvs};
 use crate::sys_common::IntoInner;
+use crate::sys_common::process::{CommandEnv, CommandEnvs};
 use crate::{cmp, env, fmt, mem, ptr};
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -253,10 +253,10 @@ impl Command {
         attribute: usize,
         value: T,
     ) {
-        self.proc_thread_attributes.insert(
-            attribute,
-            ProcThreadAttributeValue { size: mem::size_of::<T>(), data: Box::new(value) },
-        );
+        self.proc_thread_attributes.insert(attribute, ProcThreadAttributeValue {
+            size: mem::size_of::<T>(),
+            data: Box::new(value),
+        });
     }
 
     pub fn spawn(
@@ -368,10 +368,10 @@ impl Command {
                 StartupInfo: si,
                 lpAttributeList: proc_thread_attribute_list.0.as_mut_ptr() as _,
             };
-            si_ptr = core::ptr::addr_of_mut!(si_ex) as _;
+            si_ptr = (&raw mut si_ex) as _;
         } else {
             si.cb = mem::size_of::<c::STARTUPINFOW>() as u32;
-            si_ptr = core::ptr::addr_of_mut!(si) as _;
+            si_ptr = (&raw mut si) as _;
         }
 
         unsafe {
@@ -953,7 +953,7 @@ fn make_proc_thread_attribute_list(
     // It's theoretically possible for the attribute count to exceed a u32 value.
     // Therefore, we ensure that we don't add more attributes than the buffer was initialized for.
     for (&attribute, value) in attributes.iter().take(attribute_count as usize) {
-        let value_ptr = core::ptr::addr_of!(*value.data) as _;
+        let value_ptr = (&raw const *value.data) as _;
         cvt(unsafe {
             c::UpdateProcThreadAttribute(
                 proc_thread_attribute_list.0.as_mut_ptr() as _,
diff --git a/library/std/src/sys/pal/windows/process/tests.rs b/library/std/src/sys/pal/windows/process/tests.rs
index 65325fa64a0..b567151b721 100644
--- a/library/std/src/sys/pal/windows/process/tests.rs
+++ b/library/std/src/sys/pal/windows/process/tests.rs
@@ -1,4 +1,4 @@
-use super::{make_command_line, Arg};
+use super::{Arg, make_command_line};
 use crate::env;
 use crate::ffi::{OsStr, OsString};
 use crate::process::Command;
diff --git a/library/std/src/sys/pal/windows/rand.rs b/library/std/src/sys/pal/windows/rand.rs
deleted file mode 100644
index e366bb99562..00000000000
--- a/library/std/src/sys/pal/windows/rand.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-use core::{mem, ptr};
-
-use crate::sys::c;
-
-#[cfg(not(target_vendor = "win7"))]
-#[inline]
-pub fn hashmap_random_keys() -> (u64, u64) {
-    let mut v = (0, 0);
-    let ret = unsafe { c::ProcessPrng(ptr::addr_of_mut!(v).cast::<u8>(), mem::size_of_val(&v)) };
-    // ProcessPrng is documented as always returning `TRUE`.
-    // https://learn.microsoft.com/en-us/windows/win32/seccng/processprng#return-value
-    debug_assert_eq!(ret, c::TRUE);
-    v
-}
-
-#[cfg(target_vendor = "win7")]
-pub fn hashmap_random_keys() -> (u64, u64) {
-    use crate::ffi::c_void;
-    use crate::io;
-
-    let mut v = (0, 0);
-    let ret = unsafe {
-        c::RtlGenRandom(ptr::addr_of_mut!(v).cast::<c_void>(), mem::size_of_val(&v) as u32)
-    };
-
-    if ret != 0 { v } else { panic!("RNG broken: {}", io::Error::last_os_error()) }
-}
diff --git a/library/std/src/sys/pal/xous/net/dns.rs b/library/std/src/sys/pal/xous/net/dns.rs
index 50efe978c4a..d0083c61837 100644
--- a/library/std/src/sys/pal/xous/net/dns.rs
+++ b/library/std/src/sys/pal/xous/net/dns.rs
@@ -3,7 +3,7 @@ use core::convert::{TryFrom, TryInto};
 use crate::io;
 use crate::net::{Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
 use crate::os::xous::ffi::lend_mut;
-use crate::os::xous::services::{dns_server, DnsLendMut};
+use crate::os::xous::services::{DnsLendMut, dns_server};
 
 pub struct DnsError {
     pub code: u8,
diff --git a/library/std/src/sys/pal/xous/stdio.rs b/library/std/src/sys/pal/xous/stdio.rs
index 11608964b52..dfd47a1775a 100644
--- a/library/std/src/sys/pal/xous/stdio.rs
+++ b/library/std/src/sys/pal/xous/stdio.rs
@@ -4,8 +4,8 @@ pub struct Stdin;
 pub struct Stdout {}
 pub struct Stderr;
 
-use crate::os::xous::ffi::{lend, try_lend, try_scalar, Connection};
-use crate::os::xous::services::{log_server, try_connect, LogLend, LogScalar};
+use crate::os::xous::ffi::{Connection, lend, try_lend, try_scalar};
+use crate::os::xous::services::{LogLend, LogScalar, log_server, try_connect};
 
 impl Stdin {
     pub const fn new() -> Stdin {
diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/pal/xous/thread.rs
index a95b0aa14d2..0ebb46dc19f 100644
--- a/library/std/src/sys/pal/xous/thread.rs
+++ b/library/std/src/sys/pal/xous/thread.rs
@@ -4,10 +4,10 @@ use crate::ffi::CStr;
 use crate::io;
 use crate::num::NonZero;
 use crate::os::xous::ffi::{
-    blocking_scalar, create_thread, do_yield, join_thread, map_memory, update_memory_flags,
-    MemoryFlags, Syscall, ThreadId,
+    MemoryFlags, Syscall, ThreadId, blocking_scalar, create_thread, do_yield, join_thread,
+    map_memory, update_memory_flags,
 };
-use crate::os::xous::services::{ticktimer_server, TicktimerScalar};
+use crate::os::xous::services::{TicktimerScalar, ticktimer_server};
 use crate::time::Duration;
 
 pub struct Thread {
diff --git a/library/std/src/sys/pal/zkvm/args.rs b/library/std/src/sys/pal/zkvm/args.rs
index 583c16e3a47..47857f6c448 100644
--- a/library/std/src/sys/pal/zkvm/args.rs
+++ b/library/std/src/sys/pal/zkvm/args.rs
@@ -1,4 +1,4 @@
-use super::{abi, WORD_SIZE};
+use super::{WORD_SIZE, abi};
 use crate::ffi::OsString;
 use crate::fmt;
 use crate::sys::os_str;
diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs
index 20fdb7468a4..6ea05772029 100644
--- a/library/std/src/sys/pal/zkvm/mod.rs
+++ b/library/std/src/sys/pal/zkvm/mod.rs
@@ -60,11 +60,3 @@ pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind {
 pub fn abort_internal() -> ! {
     core::intrinsics::abort();
 }
-
-pub fn hashmap_random_keys() -> (u64, u64) {
-    let mut buf = [0u32; 4];
-    unsafe {
-        abi::sys_rand(buf.as_mut_ptr(), 4);
-    };
-    ((buf[0] as u64) << 32 + buf[1] as u64, (buf[2] as u64) << 32 + buf[3] as u64)
-}
diff --git a/library/std/src/sys/pal/zkvm/os.rs b/library/std/src/sys/pal/zkvm/os.rs
index 68d91a123ac..5d224ffd1ba 100644
--- a/library/std/src/sys/pal/zkvm/os.rs
+++ b/library/std/src/sys/pal/zkvm/os.rs
@@ -1,4 +1,4 @@
-use super::{abi, unsupported, WORD_SIZE};
+use super::{WORD_SIZE, abi, unsupported};
 use crate::error::Error as StdError;
 use crate::ffi::{OsStr, OsString};
 use crate::marker::PhantomData;
diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs
index 2ae9a0a9199..9267602cb97 100644
--- a/library/std/src/sys/path/windows.rs
+++ b/library/std/src/sys/path/windows.rs
@@ -99,7 +99,7 @@ impl<'a> PrefixParserSlice<'a, '_> {
 }
 
 pub fn parse_prefix(path: &OsStr) -> Option<Prefix<'_>> {
-    use Prefix::{DeviceNS, Disk, Verbatim, VerbatimDisk, VerbatimUNC, UNC};
+    use Prefix::{DeviceNS, Disk, UNC, Verbatim, VerbatimDisk, VerbatimUNC};
 
     let parser = PrefixParser::<8>::new(path);
     let parser = parser.as_slice();
diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs
index 68085d026c4..9754e840d15 100644
--- a/library/std/src/sys/personality/mod.rs
+++ b/library/std/src/sys/personality/mod.rs
@@ -31,7 +31,7 @@ cfg_if::cfg_if! {
         target_os = "psp",
         target_os = "xous",
         target_os = "solid_asp3",
-        all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re"), not(target_os = "rtems")),
+        all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re"), not(target_os = "rtems"), not(target_os = "nuttx")),
         all(target_vendor = "fortanix", target_env = "sgx"),
     ))] {
         mod gcc;
diff --git a/library/std/src/sys/random/apple.rs b/library/std/src/sys/random/apple.rs
new file mode 100644
index 00000000000..417198c9d85
--- /dev/null
+++ b/library/std/src/sys/random/apple.rs
@@ -0,0 +1,15 @@
+//! Random data on Apple platforms.
+//!
+//! `CCRandomGenerateBytes` calls into `CCRandomCopyBytes` with `kCCRandomDefault`.
+//! `CCRandomCopyBytes` manages a CSPRNG which is seeded from the kernel's CSPRNG.
+//! We use `CCRandomGenerateBytes` instead of `SecCopyBytes` because it is accessible via
+//! `libSystem` (libc) while the other needs to link to `Security.framework`.
+//!
+//! Note that technically, `arc4random_buf` is available as well, but that calls
+//! into the same system service anyway, and `CCRandomGenerateBytes` has been
+//! proven to be App Store-compatible.
+
+pub fn fill_bytes(bytes: &mut [u8]) {
+    let ret = unsafe { libc::CCRandomGenerateBytes(bytes.as_mut_ptr().cast(), bytes.len()) };
+    assert_eq!(ret, libc::kCCSuccess, "failed to generate random data");
+}
diff --git a/library/std/src/sys/random/arc4random.rs b/library/std/src/sys/random/arc4random.rs
new file mode 100644
index 00000000000..32467e9ebaa
--- /dev/null
+++ b/library/std/src/sys/random/arc4random.rs
@@ -0,0 +1,34 @@
+//! Random data generation with `arc4random_buf`.
+//!
+//! Contrary to its name, `arc4random` doesn't actually use the horribly-broken
+//! RC4 cypher anymore, at least not on modern systems, but rather something
+//! like ChaCha20 with continual reseeding from the OS. That makes it an ideal
+//! source of large quantities of cryptographically secure data, which is exactly
+//! what we need for `DefaultRandomSource`. Unfortunately, it's not available
+//! on all UNIX systems, most notably Linux (until recently, but it's just a
+//! wrapper for `getrandom`. Since we need to hook into `getrandom` directly
+//! for `HashMap` keys anyway, we just keep our version).
+
+#[cfg(not(any(
+    target_os = "haiku",
+    target_os = "illumos",
+    target_os = "solaris",
+    target_os = "vita",
+)))]
+use libc::arc4random_buf;
+
+// FIXME: move these to libc (except Haiku, that one needs to link to libbsd.so).
+#[cfg(any(
+    target_os = "haiku", // See https://git.haiku-os.org/haiku/tree/headers/compatibility/bsd/stdlib.h
+    target_os = "illumos", // See https://www.illumos.org/man/3C/arc4random
+    target_os = "solaris", // See https://docs.oracle.com/cd/E88353_01/html/E37843/arc4random-3c.html
+    target_os = "vita", // See https://github.com/vitasdk/newlib/blob/b89e5bc183b516945f9ee07eef483ecb916e45ff/newlib/libc/include/stdlib.h#L74
+))]
+#[cfg_attr(target_os = "haiku", link(name = "bsd"))]
+extern "C" {
+    fn arc4random_buf(buf: *mut core::ffi::c_void, nbytes: libc::size_t);
+}
+
+pub fn fill_bytes(bytes: &mut [u8]) {
+    unsafe { arc4random_buf(bytes.as_mut_ptr().cast(), bytes.len()) }
+}
diff --git a/library/std/src/sys/random/espidf.rs b/library/std/src/sys/random/espidf.rs
new file mode 100644
index 00000000000..fd52cb5559c
--- /dev/null
+++ b/library/std/src/sys/random/espidf.rs
@@ -0,0 +1,9 @@
+use crate::ffi::c_void;
+
+extern "C" {
+    fn esp_fill_random(buf: *mut c_void, len: usize);
+}
+
+pub fn fill_bytes(bytes: &mut [u8]) {
+    unsafe { esp_fill_random(bytes.as_mut_ptr().cast(), bytes.len()) }
+}
diff --git a/library/std/src/sys/random/fuchsia.rs b/library/std/src/sys/random/fuchsia.rs
new file mode 100644
index 00000000000..77d72b3c5b7
--- /dev/null
+++ b/library/std/src/sys/random/fuchsia.rs
@@ -0,0 +1,13 @@
+//! Random data generation using the Zircon kernel.
+//!
+//! Fuchsia, as always, is quite nice and provides exactly the API we need:
+//! <https://fuchsia.dev/reference/syscalls/cprng_draw>.
+
+#[link(name = "zircon")]
+extern "C" {
+    fn zx_cprng_draw(buffer: *mut u8, len: usize);
+}
+
+pub fn fill_bytes(bytes: &mut [u8]) {
+    unsafe { zx_cprng_draw(bytes.as_mut_ptr(), bytes.len()) }
+}
diff --git a/library/std/src/sys/random/getentropy.rs b/library/std/src/sys/random/getentropy.rs
new file mode 100644
index 00000000000..110ac134c1f
--- /dev/null
+++ b/library/std/src/sys/random/getentropy.rs
@@ -0,0 +1,17 @@
+//! Random data generation through `getentropy`.
+//!
+//! Since issue 8 (2024), the POSIX specification mandates the existence of the
+//! `getentropy` function, which fills a slice of up to `GETENTROPY_MAX` bytes
+//! (256 on all known platforms) with random data. Unfortunately, it's only
+//! meant to be used to seed other CPRNGs, which we don't have, so we only use
+//! it where `arc4random_buf` and friends aren't available or secure (currently
+//! that's only the case on Emscripten).
+
+pub fn fill_bytes(bytes: &mut [u8]) {
+    // GETENTROPY_MAX isn't defined yet on most platforms, but it's mandated
+    // to be at least 256, so just use that as limit.
+    for chunk in bytes.chunks_mut(256) {
+        let r = unsafe { libc::getentropy(chunk.as_mut_ptr().cast(), chunk.len()) };
+        assert_ne!(r, -1, "failed to generate random data");
+    }
+}
diff --git a/library/std/src/sys/random/hermit.rs b/library/std/src/sys/random/hermit.rs
new file mode 100644
index 00000000000..92c0550d2d5
--- /dev/null
+++ b/library/std/src/sys/random/hermit.rs
@@ -0,0 +1,7 @@
+pub fn fill_bytes(mut bytes: &mut [u8]) {
+    while !bytes.is_empty() {
+        let res = unsafe { hermit_abi::read_entropy(bytes.as_mut_ptr(), bytes.len(), 0) };
+        assert_ne!(res, -1, "failed to generate random data");
+        bytes = &mut bytes[res as usize..];
+    }
+}
diff --git a/library/std/src/sys/random/horizon.rs b/library/std/src/sys/random/horizon.rs
new file mode 100644
index 00000000000..0be2eae20a7
--- /dev/null
+++ b/library/std/src/sys/random/horizon.rs
@@ -0,0 +1,7 @@
+pub fn fill_bytes(mut bytes: &mut [u8]) {
+    while !bytes.is_empty() {
+        let r = unsafe { libc::getrandom(bytes.as_mut_ptr().cast(), bytes.len(), 0) };
+        assert_ne!(r, -1, "failed to generate random data");
+        bytes = &mut bytes[r as usize..];
+    }
+}
diff --git a/library/std/src/sys/random/linux.rs b/library/std/src/sys/random/linux.rs
new file mode 100644
index 00000000000..073fdc45e61
--- /dev/null
+++ b/library/std/src/sys/random/linux.rs
@@ -0,0 +1,170 @@
+//! Random data generation with the Linux kernel.
+//!
+//! The first interface random data interface to be introduced on Linux were
+//! the `/dev/random` and `/dev/urandom` special files. As paths can become
+//! unreachable when inside a chroot and when the file descriptors are exhausted,
+//! this was not enough to provide userspace with a reliable source of randomness,
+//! so when the OpenBSD 5.6 introduced the `getentropy` syscall, Linux 3.17 got
+//! its very own `getrandom`  syscall to match.[^1] Unfortunately, even if our
+//! minimum supported version were high enough, we still couldn't rely on the
+//! syscall being available, as it is blocked in `seccomp` by default.
+//!
+//! The question is therefore which of the random sources to use. Historically,
+//! the kernel contained two pools: the blocking and non-blocking pool. The
+//! blocking pool used entropy estimation to limit the amount of available
+//! bytes, while the non-blocking pool, once initialized using the blocking
+//! pool, uses a CPRNG to return an unlimited number of random bytes. With a
+//! strong enough CPRNG however, the entropy estimation didn't contribute that
+//! much towards security while being an excellent vector for DoS attacs. Thus,
+//! the blocking pool was removed in kernel version 5.6.[^2] That patch did not
+//! magically increase the quality of the non-blocking pool, however, so we can
+//! safely consider it strong enough even in older kernel versions and use it
+//! unconditionally.
+//!
+//! One additional consideration to make is that the non-blocking pool is not
+//! always initialized during early boot. We want the best quality of randomness
+//! for the output of `DefaultRandomSource` so we simply wait until it is
+//! initialized. When `HashMap` keys however, this represents a potential source
+//! of deadlocks, as the additional entropy may only be generated once the
+//! program makes forward progress. In that case, we just use the best random
+//! data the system has available at the time.
+//!
+//! So in conclusion, we always want the output of the non-blocking pool, but
+//! may need to wait until it is initalized. The default behaviour of `getrandom`
+//! is to wait until the non-blocking pool is initialized and then draw from there,
+//! so if `getrandom` is available, we use its default to generate the bytes. For
+//! `HashMap`, however, we need to specify the `GRND_INSECURE` flags, but that
+//! is only available starting with kernel version 5.6. Thus, if we detect that
+//! the flag is unsupported, we try `GRND_NONBLOCK` instead, which will only
+//! succeed if the pool is initialized. If it isn't, we fall back to the file
+//! access method.
+//!
+//! The behaviour of `/dev/urandom` is inverse to that of `getrandom`: it always
+//! yields data, even when the pool is not initialized. For generating `HashMap`
+//! keys, this is not important, so we can use it directly. For secure data
+//! however, we need to wait until initialization, which we can do by `poll`ing
+//! `/dev/random`.
+//!
+//! TLDR: our fallback strategies are:
+//!
+//! Secure data                                 | `HashMap` keys
+//! --------------------------------------------|------------------
+//! getrandom(0)                                | getrandom(GRND_INSECURE)
+//! poll("/dev/random") && read("/dev/urandom") | getrandom(GRND_NONBLOCK)
+//!                                             | read("/dev/urandom")
+//!
+//! [^1]: <https://lwn.net/Articles/606141/>
+//! [^2]: <https://lwn.net/Articles/808575/>
+//!
+// FIXME(in 2040 or so): once the minimum kernel version is 5.6, remove the
+// `GRND_NONBLOCK` fallback and use `/dev/random` instead of `/dev/urandom`
+// when secure data is required.
+
+use crate::fs::File;
+use crate::io::Read;
+use crate::os::fd::AsRawFd;
+use crate::sync::OnceLock;
+use crate::sync::atomic::AtomicBool;
+use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
+use crate::sys::pal::os::errno;
+use crate::sys::pal::weak::syscall;
+
+fn getrandom(mut bytes: &mut [u8], insecure: bool) {
+    // A weak symbol allows interposition, e.g. for perf measurements that want to
+    // disable randomness for consistency. Otherwise, we'll try a raw syscall.
+    // (`getrandom` was added in glibc 2.25, musl 1.1.20, android API level 28)
+    syscall! {
+        fn getrandom(
+            buffer: *mut libc::c_void,
+            length: libc::size_t,
+            flags: libc::c_uint
+        ) -> libc::ssize_t
+    }
+
+    static GETRANDOM_AVAILABLE: AtomicBool = AtomicBool::new(true);
+    static GRND_INSECURE_AVAILABLE: AtomicBool = AtomicBool::new(true);
+    static URANDOM_READY: AtomicBool = AtomicBool::new(false);
+    static DEVICE: OnceLock<File> = OnceLock::new();
+
+    if GETRANDOM_AVAILABLE.load(Relaxed) {
+        loop {
+            if bytes.is_empty() {
+                return;
+            }
+
+            let flags = if insecure {
+                if GRND_INSECURE_AVAILABLE.load(Relaxed) {
+                    libc::GRND_INSECURE
+                } else {
+                    libc::GRND_NONBLOCK
+                }
+            } else {
+                0
+            };
+
+            let ret = unsafe { getrandom(bytes.as_mut_ptr().cast(), bytes.len(), flags) };
+            if ret != -1 {
+                bytes = &mut bytes[ret as usize..];
+            } else {
+                match errno() {
+                    libc::EINTR => continue,
+                    // `GRND_INSECURE` is not available, try
+                    // `GRND_NONBLOCK`.
+                    libc::EINVAL if flags == libc::GRND_INSECURE => {
+                        GRND_INSECURE_AVAILABLE.store(false, Relaxed);
+                        continue;
+                    }
+                    // The pool is not initialized yet, fall back to
+                    // /dev/urandom for now.
+                    libc::EAGAIN if flags == libc::GRND_NONBLOCK => break,
+                    // `getrandom` is unavailable or blocked by seccomp.
+                    // Don't try it again and fall back to /dev/urandom.
+                    libc::ENOSYS | libc::EPERM => {
+                        GETRANDOM_AVAILABLE.store(false, Relaxed);
+                        break;
+                    }
+                    _ => panic!("failed to generate random data"),
+                }
+            }
+        }
+    }
+
+    // When we want cryptographic strength, we need to wait for the CPRNG-pool
+    // to become initialized. Do this by polling `/dev/random` until it is ready.
+    if !insecure {
+        if !URANDOM_READY.load(Acquire) {
+            let random = File::open("/dev/random").expect("failed to open /dev/random");
+            let mut fd = libc::pollfd { fd: random.as_raw_fd(), events: libc::POLLIN, revents: 0 };
+
+            while !URANDOM_READY.load(Acquire) {
+                let ret = unsafe { libc::poll(&mut fd, 1, -1) };
+                match ret {
+                    1 => {
+                        assert_eq!(fd.revents, libc::POLLIN);
+                        URANDOM_READY.store(true, Release);
+                        break;
+                    }
+                    -1 if errno() == libc::EINTR => continue,
+                    _ => panic!("poll(\"/dev/random\") failed"),
+                }
+            }
+        }
+    }
+
+    DEVICE
+        .get_or_try_init(|| File::open("/dev/urandom"))
+        .and_then(|mut dev| dev.read_exact(bytes))
+        .expect("failed to generate random data");
+}
+
+pub fn fill_bytes(bytes: &mut [u8]) {
+    getrandom(bytes, false);
+}
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+    let mut bytes = [0; 16];
+    getrandom(&mut bytes, true);
+    let k1 = u64::from_ne_bytes(bytes[..8].try_into().unwrap());
+    let k2 = u64::from_ne_bytes(bytes[8..].try_into().unwrap());
+    (k1, k2)
+}
diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs
new file mode 100644
index 00000000000..d625814d15b
--- /dev/null
+++ b/library/std/src/sys/random/mod.rs
@@ -0,0 +1,96 @@
+cfg_if::cfg_if! {
+    // Tier 1
+    if #[cfg(any(target_os = "linux", target_os = "android"))] {
+        mod linux;
+        pub use linux::{fill_bytes, hashmap_random_keys};
+    } else if #[cfg(target_os = "windows")] {
+        mod windows;
+        pub use windows::fill_bytes;
+    } else if #[cfg(target_vendor = "apple")] {
+        mod apple;
+        pub use apple::fill_bytes;
+    // Others, in alphabetical ordering.
+    } else if #[cfg(any(
+        target_os = "dragonfly",
+        target_os = "freebsd",
+        target_os = "haiku",
+        target_os = "illumos",
+        target_os = "netbsd",
+        target_os = "openbsd",
+        target_os = "solaris",
+        target_os = "vita",
+    ))] {
+        mod arc4random;
+        pub use arc4random::fill_bytes;
+    } else if #[cfg(target_os = "emscripten")] {
+        mod getentropy;
+        pub use getentropy::fill_bytes;
+    } else if #[cfg(target_os = "espidf")] {
+        mod espidf;
+        pub use espidf::fill_bytes;
+    } else if #[cfg(target_os = "fuchsia")] {
+        mod fuchsia;
+        pub use fuchsia::fill_bytes;
+    } else if #[cfg(target_os = "hermit")] {
+        mod hermit;
+        pub use hermit::fill_bytes;
+    } else if #[cfg(target_os = "horizon")] {
+        // FIXME: add arc4random_buf to shim-3ds
+        mod horizon;
+        pub use horizon::fill_bytes;
+    } else if #[cfg(any(
+        target_os = "hurd",
+        target_os = "l4re",
+        target_os = "nto",
+        target_os = "nuttx",
+    ))] {
+        mod unix_legacy;
+        pub use unix_legacy::fill_bytes;
+    } else if #[cfg(target_os = "redox")] {
+        mod redox;
+        pub use redox::fill_bytes;
+    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+        mod sgx;
+        pub use sgx::fill_bytes;
+    } else if #[cfg(target_os = "solid_asp3")] {
+        mod solid;
+        pub use solid::fill_bytes;
+    } else if #[cfg(target_os = "teeos")] {
+        mod teeos;
+        pub use teeos::fill_bytes;
+    } else if #[cfg(target_os = "uefi")] {
+        mod uefi;
+        pub use uefi::fill_bytes;
+    } else if #[cfg(target_os = "vxworks")] {
+        mod vxworks;
+        pub use vxworks::fill_bytes;
+    } else if #[cfg(target_os = "wasi")] {
+        mod wasi;
+        pub use wasi::fill_bytes;
+    } else if #[cfg(target_os = "zkvm")] {
+        mod zkvm;
+        pub use zkvm::fill_bytes;
+    } else if #[cfg(any(
+        all(target_family = "wasm", target_os = "unknown"),
+        target_os = "xous",
+    ))] {
+        // FIXME: finally remove std support for wasm32-unknown-unknown
+        // FIXME: add random data generation to xous
+        mod unsupported;
+        pub use unsupported::{fill_bytes, hashmap_random_keys};
+    }
+}
+
+#[cfg(not(any(
+    target_os = "linux",
+    target_os = "android",
+    all(target_family = "wasm", target_os = "unknown"),
+    target_os = "xous",
+)))]
+pub fn hashmap_random_keys() -> (u64, u64) {
+    let mut buf = [0; 16];
+    fill_bytes(&mut buf);
+    let k1 = u64::from_ne_bytes(buf[..8].try_into().unwrap());
+    let k2 = u64::from_ne_bytes(buf[8..].try_into().unwrap());
+    (k1, k2)
+}
diff --git a/library/std/src/sys/random/redox.rs b/library/std/src/sys/random/redox.rs
new file mode 100644
index 00000000000..b004335a351
--- /dev/null
+++ b/library/std/src/sys/random/redox.rs
@@ -0,0 +1,12 @@
+use crate::fs::File;
+use crate::io::Read;
+use crate::sync::OnceLock;
+
+static SCHEME: OnceLock<File> = OnceLock::new();
+
+pub fn fill_bytes(bytes: &mut [u8]) {
+    SCHEME
+        .get_or_try_init(|| File::open("/scheme/rand"))
+        .and_then(|mut scheme| scheme.read_exact(bytes))
+        .expect("failed to generate random data");
+}
diff --git a/library/std/src/sys/random/sgx.rs b/library/std/src/sys/random/sgx.rs
new file mode 100644
index 00000000000..c3647a8df22
--- /dev/null
+++ b/library/std/src/sys/random/sgx.rs
@@ -0,0 +1,67 @@
+use crate::arch::x86_64::{_rdrand16_step, _rdrand32_step, _rdrand64_step};
+
+const RETRIES: u32 = 10;
+
+fn fail() -> ! {
+    panic!("failed to generate random data");
+}
+
+fn rdrand64() -> u64 {
+    unsafe {
+        let mut ret: u64 = 0;
+        for _ in 0..RETRIES {
+            if _rdrand64_step(&mut ret) == 1 {
+                return ret;
+            }
+        }
+
+        fail();
+    }
+}
+
+fn rdrand32() -> u32 {
+    unsafe {
+        let mut ret: u32 = 0;
+        for _ in 0..RETRIES {
+            if _rdrand32_step(&mut ret) == 1 {
+                return ret;
+            }
+        }
+
+        fail();
+    }
+}
+
+fn rdrand16() -> u16 {
+    unsafe {
+        let mut ret: u16 = 0;
+        for _ in 0..RETRIES {
+            if _rdrand16_step(&mut ret) == 1 {
+                return ret;
+            }
+        }
+
+        fail();
+    }
+}
+
+pub fn fill_bytes(bytes: &mut [u8]) {
+    let mut chunks = bytes.array_chunks_mut();
+    for chunk in &mut chunks {
+        *chunk = rdrand64().to_ne_bytes();
+    }
+
+    let mut chunks = chunks.into_remainder().array_chunks_mut();
+    for chunk in &mut chunks {
+        *chunk = rdrand32().to_ne_bytes();
+    }
+
+    let mut chunks = chunks.into_remainder().array_chunks_mut();
+    for chunk in &mut chunks {
+        *chunk = rdrand16().to_ne_bytes();
+    }
+
+    if let [byte] = chunks.into_remainder() {
+        *byte = rdrand16() as u8;
+    }
+}
diff --git a/library/std/src/sys/random/solid.rs b/library/std/src/sys/random/solid.rs
new file mode 100644
index 00000000000..545771150e2
--- /dev/null
+++ b/library/std/src/sys/random/solid.rs
@@ -0,0 +1,8 @@
+use crate::sys::pal::abi;
+
+pub fn fill_bytes(bytes: &mut [u8]) {
+    unsafe {
+        let result = abi::SOLID_RNG_SampleRandomBytes(bytes.as_mut_ptr(), bytes.len());
+        assert_eq!(result, 0, "failed to generate random data");
+    }
+}
diff --git a/library/std/src/sys/random/teeos.rs b/library/std/src/sys/random/teeos.rs
new file mode 100644
index 00000000000..fd6b24e19e9
--- /dev/null
+++ b/library/std/src/sys/random/teeos.rs
@@ -0,0 +1,7 @@
+extern "C" {
+    fn TEE_GenerateRandom(randomBuffer: *mut core::ffi::c_void, randomBufferLen: libc::size_t);
+}
+
+pub fn fill_bytes(bytes: &mut [u8]) {
+    unsafe { TEE_GenerateRandom(bytes.as_mut_ptr().cast(), bytes.len()) }
+}
diff --git a/library/std/src/sys/random/uefi.rs b/library/std/src/sys/random/uefi.rs
new file mode 100644
index 00000000000..a4d29e66f38
--- /dev/null
+++ b/library/std/src/sys/random/uefi.rs
@@ -0,0 +1,27 @@
+use r_efi::protocols::rng;
+
+use crate::sys::pal::helpers;
+
+pub fn fill_bytes(bytes: &mut [u8]) {
+    let handles =
+        helpers::locate_handles(rng::PROTOCOL_GUID).expect("failed to generate random data");
+    for handle in handles {
+        if let Ok(protocol) = helpers::open_protocol::<rng::Protocol>(handle, rng::PROTOCOL_GUID) {
+            let r = unsafe {
+                ((*protocol.as_ptr()).get_rng)(
+                    protocol.as_ptr(),
+                    crate::ptr::null_mut(),
+                    bytes.len(),
+                    bytes.as_mut_ptr(),
+                )
+            };
+            if r.is_error() {
+                continue;
+            } else {
+                return;
+            }
+        }
+    }
+
+    panic!("failed to generate random data");
+}
diff --git a/library/std/src/sys/random/unix_legacy.rs b/library/std/src/sys/random/unix_legacy.rs
new file mode 100644
index 00000000000..587068b0d66
--- /dev/null
+++ b/library/std/src/sys/random/unix_legacy.rs
@@ -0,0 +1,20 @@
+//! Random data from `/dev/urandom`
+//!
+//! Before `getentropy` was standardized in 2024, UNIX didn't have a standardized
+//! way of getting random data, so systems just followed the precedent set by
+//! Linux and exposed random devices at `/dev/random` and `/dev/urandom`. Thus,
+//! for the few systems that support neither `arc4random_buf` nor `getentropy`
+//! yet, we just read from the file.
+
+use crate::fs::File;
+use crate::io::Read;
+use crate::sync::OnceLock;
+
+static DEVICE: OnceLock<File> = OnceLock::new();
+
+pub fn fill_bytes(bytes: &mut [u8]) {
+    DEVICE
+        .get_or_try_init(|| File::open("/dev/urandom"))
+        .and_then(|mut dev| dev.read_exact(bytes))
+        .expect("failed to generate random data");
+}
diff --git a/library/std/src/sys/random/unsupported.rs b/library/std/src/sys/random/unsupported.rs
new file mode 100644
index 00000000000..d68ce4a9e87
--- /dev/null
+++ b/library/std/src/sys/random/unsupported.rs
@@ -0,0 +1,15 @@
+use crate::ptr;
+
+pub fn fill_bytes(_: &mut [u8]) {
+    panic!("this target does not support random data generation");
+}
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+    // Use allocation addresses for a bit of randomness. This isn't
+    // particularily secure, but there isn't really an alternative.
+    let stack = 0u8;
+    let heap = Box::new(0u8);
+    let k1 = ptr::from_ref(&stack).addr() as u64;
+    let k2 = ptr::from_ref(&*heap).addr() as u64;
+    (k1, k2)
+}
diff --git a/library/std/src/sys/random/vxworks.rs b/library/std/src/sys/random/vxworks.rs
new file mode 100644
index 00000000000..d549ccebdb2
--- /dev/null
+++ b/library/std/src/sys/random/vxworks.rs
@@ -0,0 +1,25 @@
+use crate::sync::atomic::AtomicBool;
+use crate::sync::atomic::Ordering::Relaxed;
+
+static RNG_INIT: AtomicBool = AtomicBool::new(false);
+
+pub fn fill_bytes(mut bytes: &mut [u8]) {
+    while !RNG_INIT.load(Relaxed) {
+        let ret = unsafe { libc::randSecure() };
+        if ret < 0 {
+            panic!("failed to generate random data");
+        } else if ret > 0 {
+            RNG_INIT.store(true, Relaxed);
+            break;
+        }
+
+        unsafe { libc::usleep(10) };
+    }
+
+    while !bytes.is_empty() {
+        let len = bytes.len().try_into().unwrap_or(libc::c_int::MAX);
+        let ret = unsafe { libc::randABytes(bytes.as_mut_ptr(), len) };
+        assert!(ret >= 0, "failed to generate random data");
+        bytes = &mut bytes[len as usize..];
+    }
+}
diff --git a/library/std/src/sys/random/wasi.rs b/library/std/src/sys/random/wasi.rs
new file mode 100644
index 00000000000..d41da3751fc
--- /dev/null
+++ b/library/std/src/sys/random/wasi.rs
@@ -0,0 +1,5 @@
+pub fn fill_bytes(bytes: &mut [u8]) {
+    unsafe {
+        wasi::random_get(bytes.as_mut_ptr(), bytes.len()).expect("failed to generate random data")
+    }
+}
diff --git a/library/std/src/sys/random/windows.rs b/library/std/src/sys/random/windows.rs
new file mode 100644
index 00000000000..7566000f9e6
--- /dev/null
+++ b/library/std/src/sys/random/windows.rs
@@ -0,0 +1,20 @@
+use crate::sys::c;
+
+#[cfg(not(target_vendor = "win7"))]
+#[inline]
+pub fn fill_bytes(bytes: &mut [u8]) {
+    let ret = unsafe { c::ProcessPrng(bytes.as_mut_ptr(), bytes.len()) };
+    // ProcessPrng is documented as always returning `TRUE`.
+    // https://learn.microsoft.com/en-us/windows/win32/seccng/processprng#return-value
+    debug_assert_eq!(ret, c::TRUE);
+}
+
+#[cfg(target_vendor = "win7")]
+pub fn fill_bytes(mut bytes: &mut [u8]) {
+    while !bytes.is_empty() {
+        let len = bytes.len().try_into().unwrap_or(u32::MAX);
+        let ret = unsafe { c::RtlGenRandom(bytes.as_mut_ptr().cast(), len) };
+        assert_ne!(ret, 0, "failed to generate random data");
+        bytes = &mut bytes[len as usize..];
+    }
+}
diff --git a/library/std/src/sys/random/zkvm.rs b/library/std/src/sys/random/zkvm.rs
new file mode 100644
index 00000000000..3011942f6b2
--- /dev/null
+++ b/library/std/src/sys/random/zkvm.rs
@@ -0,0 +1,21 @@
+use crate::sys::pal::abi;
+
+pub fn fill_bytes(bytes: &mut [u8]) {
+    let (pre, words, post) = unsafe { bytes.align_to_mut::<u32>() };
+    if !words.is_empty() {
+        unsafe {
+            abi::sys_rand(words.as_mut_ptr(), words.len());
+        }
+    }
+
+    let mut buf = [0u32; 2];
+    let len = (pre.len() + post.len() + size_of::<u32>() - 1) / size_of::<u32>();
+    if len != 0 {
+        unsafe { abi::sys_rand(buf.as_mut_ptr(), len) };
+    }
+
+    let buf = buf.map(u32::to_ne_bytes);
+    let buf = buf.as_flattened();
+    pre.copy_from_slice(&buf[..pre.len()]);
+    post.copy_from_slice(&buf[pre.len()..pre.len() + post.len()]);
+}
diff --git a/library/std/src/sys/sync/condvar/mod.rs b/library/std/src/sys/sync/condvar/mod.rs
index 6849cacf88e..d0c998a5597 100644
--- a/library/std/src/sys/sync/condvar/mod.rs
+++ b/library/std/src/sys/sync/condvar/mod.rs
@@ -12,7 +12,10 @@ cfg_if::cfg_if! {
     ))] {
         mod futex;
         pub use futex::Condvar;
-    } else if #[cfg(target_family = "unix")] {
+    } else if #[cfg(any(
+        target_family = "unix",
+        target_os = "teeos",
+    ))] {
         mod pthread;
         pub use pthread::Condvar;
     } else if #[cfg(all(target_os = "windows", target_vendor = "win7"))] {
@@ -24,9 +27,6 @@ cfg_if::cfg_if! {
     } else if #[cfg(target_os = "solid_asp3")] {
         mod itron;
         pub use itron::Condvar;
-    } else if #[cfg(target_os = "teeos")] {
-        mod teeos;
-        pub use teeos::Condvar;
     } else if #[cfg(target_os = "xous")] {
         mod xous;
         pub use xous::Condvar;
diff --git a/library/std/src/sys/sync/condvar/pthread.rs b/library/std/src/sys/sync/condvar/pthread.rs
index 2b4bdfe415c..986cd0cb7d1 100644
--- a/library/std/src/sys/sync/condvar/pthread.rs
+++ b/library/std/src/sys/sync/condvar/pthread.rs
@@ -2,31 +2,25 @@ use crate::cell::UnsafeCell;
 use crate::ptr;
 use crate::sync::atomic::AtomicPtr;
 use crate::sync::atomic::Ordering::Relaxed;
-use crate::sys::sync::{mutex, Mutex};
+use crate::sys::sync::{Mutex, OnceBox};
 #[cfg(not(target_os = "nto"))]
 use crate::sys::time::TIMESPEC_MAX;
 #[cfg(target_os = "nto")]
 use crate::sys::time::TIMESPEC_MAX_CAPPED;
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 use crate::time::Duration;
 
 struct AllocatedCondvar(UnsafeCell<libc::pthread_cond_t>);
 
 pub struct Condvar {
-    inner: LazyBox<AllocatedCondvar>,
+    inner: OnceBox<AllocatedCondvar>,
     mutex: AtomicPtr<libc::pthread_mutex_t>,
 }
 
-#[inline]
-fn raw(c: &Condvar) -> *mut libc::pthread_cond_t {
-    c.inner.0.get()
-}
-
 unsafe impl Send for AllocatedCondvar {}
 unsafe impl Sync for AllocatedCondvar {}
 
-impl LazyInit for AllocatedCondvar {
-    fn init() -> Box<Self> {
+impl AllocatedCondvar {
+    fn new() -> Box<Self> {
         let condvar = Box::new(AllocatedCondvar(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)));
 
         cfg_if::cfg_if! {
@@ -37,7 +31,7 @@ impl LazyInit for AllocatedCondvar {
                 target_vendor = "apple",
             ))] {
                 // `pthread_condattr_setclock` is unfortunately not supported on these platforms.
-            } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] {
+            } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "teeos"))] {
                 // NOTE: ESP-IDF's PTHREAD_COND_INITIALIZER support is not released yet
                 // So on that platform, init() should always be called
                 // Moreover, that platform does not have pthread_condattr_setclock support,
@@ -82,7 +76,11 @@ impl Drop for AllocatedCondvar {
 
 impl Condvar {
     pub const fn new() -> Condvar {
-        Condvar { inner: LazyBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) }
+        Condvar { inner: OnceBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) }
+    }
+
+    fn get(&self) -> *mut libc::pthread_cond_t {
+        self.inner.get_or_init(AllocatedCondvar::new).0.get()
     }
 
     #[inline]
@@ -98,21 +96,21 @@ impl Condvar {
 
     #[inline]
     pub fn notify_one(&self) {
-        let r = unsafe { libc::pthread_cond_signal(raw(self)) };
+        let r = unsafe { libc::pthread_cond_signal(self.get()) };
         debug_assert_eq!(r, 0);
     }
 
     #[inline]
     pub fn notify_all(&self) {
-        let r = unsafe { libc::pthread_cond_broadcast(raw(self)) };
+        let r = unsafe { libc::pthread_cond_broadcast(self.get()) };
         debug_assert_eq!(r, 0);
     }
 
     #[inline]
     pub unsafe fn wait(&self, mutex: &Mutex) {
-        let mutex = mutex::raw(mutex);
+        let mutex = mutex.get_assert_locked();
         self.verify(mutex);
-        let r = libc::pthread_cond_wait(raw(self), mutex);
+        let r = libc::pthread_cond_wait(self.get(), mutex);
         debug_assert_eq!(r, 0);
     }
 
@@ -129,7 +127,7 @@ impl Condvar {
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
         use crate::sys::time::Timespec;
 
-        let mutex = mutex::raw(mutex);
+        let mutex = mutex.get_assert_locked();
         self.verify(mutex);
 
         #[cfg(not(target_os = "nto"))]
@@ -144,7 +142,7 @@ impl Condvar {
             .and_then(|t| t.to_timespec_capped())
             .unwrap_or(TIMESPEC_MAX_CAPPED);
 
-        let r = libc::pthread_cond_timedwait(raw(self), mutex, &timeout);
+        let r = libc::pthread_cond_timedwait(self.get(), mutex, &timeout);
         assert!(r == libc::ETIMEDOUT || r == 0);
         r == 0
     }
@@ -162,7 +160,7 @@ impl Condvar {
         use crate::sys::time::SystemTime;
         use crate::time::Instant;
 
-        let mutex = mutex::raw(mutex);
+        let mutex = mutex.get_assert_locked();
         self.verify(mutex);
 
         // OSX implementation of `pthread_cond_timedwait` is buggy
@@ -188,7 +186,7 @@ impl Condvar {
             .and_then(|t| t.to_timespec())
             .unwrap_or(TIMESPEC_MAX);
 
-        let r = libc::pthread_cond_timedwait(raw(self), mutex, &timeout);
+        let r = libc::pthread_cond_timedwait(self.get(), mutex, &timeout);
         debug_assert!(r == libc::ETIMEDOUT || r == 0);
 
         // ETIMEDOUT is not a totally reliable method of determining timeout due
diff --git a/library/std/src/sys/sync/condvar/sgx.rs b/library/std/src/sys/sync/condvar/sgx.rs
index ecb5872f60d..e60715e4b59 100644
--- a/library/std/src/sys/sync/condvar/sgx.rs
+++ b/library/std/src/sys/sync/condvar/sgx.rs
@@ -1,44 +1,39 @@
 use crate::sys::pal::waitqueue::{SpinMutex, WaitQueue, WaitVariable};
-use crate::sys::sync::Mutex;
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
+use crate::sys::sync::{Mutex, OnceBox};
 use crate::time::Duration;
 
-/// FIXME: `UnsafeList` is not movable.
-struct AllocatedCondvar(SpinMutex<WaitVariable<()>>);
-
 pub struct Condvar {
-    inner: LazyBox<AllocatedCondvar>,
-}
-
-impl LazyInit for AllocatedCondvar {
-    fn init() -> Box<Self> {
-        Box::new(AllocatedCondvar(SpinMutex::new(WaitVariable::new(()))))
-    }
+    // FIXME: `UnsafeList` is not movable.
+    inner: OnceBox<SpinMutex<WaitVariable<()>>>,
 }
 
 impl Condvar {
     pub const fn new() -> Condvar {
-        Condvar { inner: LazyBox::new() }
+        Condvar { inner: OnceBox::new() }
+    }
+
+    fn get(&self) -> &SpinMutex<WaitVariable<()>> {
+        self.inner.get_or_init(|| Box::new(SpinMutex::new(WaitVariable::new(()))))
     }
 
     #[inline]
     pub fn notify_one(&self) {
-        let _ = WaitQueue::notify_one(self.inner.0.lock());
+        let _ = WaitQueue::notify_one(self.get().lock());
     }
 
     #[inline]
     pub fn notify_all(&self) {
-        let _ = WaitQueue::notify_all(self.inner.0.lock());
+        let _ = WaitQueue::notify_all(self.get().lock());
     }
 
     pub unsafe fn wait(&self, mutex: &Mutex) {
-        let guard = self.inner.0.lock();
+        let guard = self.get().lock();
         WaitQueue::wait(guard, || unsafe { mutex.unlock() });
         mutex.lock()
     }
 
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        let success = WaitQueue::wait_timeout(&self.inner.0, dur, || unsafe { mutex.unlock() });
+        let success = WaitQueue::wait_timeout(self.get(), dur, || unsafe { mutex.unlock() });
         mutex.lock();
         success
     }
diff --git a/library/std/src/sys/sync/condvar/teeos.rs b/library/std/src/sys/sync/condvar/teeos.rs
deleted file mode 100644
index 943867cd761..00000000000
--- a/library/std/src/sys/sync/condvar/teeos.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-use crate::cell::UnsafeCell;
-use crate::ptr;
-use crate::sync::atomic::AtomicPtr;
-use crate::sync::atomic::Ordering::Relaxed;
-use crate::sys::sync::mutex::{self, Mutex};
-use crate::sys::time::TIMESPEC_MAX;
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
-use crate::time::Duration;
-
-extern "C" {
-    pub fn pthread_cond_timedwait(
-        cond: *mut libc::pthread_cond_t,
-        lock: *mut libc::pthread_mutex_t,
-        adstime: *const libc::timespec,
-    ) -> libc::c_int;
-}
-
-struct AllocatedCondvar(UnsafeCell<libc::pthread_cond_t>);
-
-pub struct Condvar {
-    inner: LazyBox<AllocatedCondvar>,
-    mutex: AtomicPtr<libc::pthread_mutex_t>,
-}
-
-#[inline]
-fn raw(c: &Condvar) -> *mut libc::pthread_cond_t {
-    c.inner.0.get()
-}
-
-unsafe impl Send for AllocatedCondvar {}
-unsafe impl Sync for AllocatedCondvar {}
-
-impl LazyInit for AllocatedCondvar {
-    fn init() -> Box<Self> {
-        let condvar = Box::new(AllocatedCondvar(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)));
-
-        let r = unsafe { libc::pthread_cond_init(condvar.0.get(), crate::ptr::null()) };
-        assert_eq!(r, 0);
-
-        condvar
-    }
-}
-
-impl Drop for AllocatedCondvar {
-    #[inline]
-    fn drop(&mut self) {
-        let r = unsafe { libc::pthread_cond_destroy(self.0.get()) };
-        debug_assert_eq!(r, 0);
-    }
-}
-
-impl Condvar {
-    pub const fn new() -> Condvar {
-        Condvar { inner: LazyBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) }
-    }
-
-    #[inline]
-    fn verify(&self, mutex: *mut libc::pthread_mutex_t) {
-        match self.mutex.compare_exchange(ptr::null_mut(), mutex, Relaxed, Relaxed) {
-            Ok(_) => {}                // Stored the address
-            Err(n) if n == mutex => {} // Lost a race to store the same address
-            _ => panic!("attempted to use a condition variable with two mutexes"),
-        }
-    }
-
-    #[inline]
-    pub fn notify_one(&self) {
-        let r = unsafe { libc::pthread_cond_signal(raw(self)) };
-        debug_assert_eq!(r, 0);
-    }
-
-    #[inline]
-    pub fn notify_all(&self) {
-        let r = unsafe { libc::pthread_cond_broadcast(raw(self)) };
-        debug_assert_eq!(r, 0);
-    }
-
-    #[inline]
-    pub unsafe fn wait(&self, mutex: &Mutex) {
-        let mutex = unsafe { mutex::raw(mutex) };
-        self.verify(mutex);
-        let r = unsafe { libc::pthread_cond_wait(raw(self), mutex) };
-        debug_assert_eq!(r, 0);
-    }
-
-    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        use crate::sys::time::Timespec;
-
-        let mutex = unsafe { mutex::raw(mutex) };
-        self.verify(mutex);
-
-        let timeout = Timespec::now(libc::CLOCK_MONOTONIC)
-            .checked_add_duration(&dur)
-            .and_then(|t| t.to_timespec())
-            .unwrap_or(TIMESPEC_MAX);
-
-        let r = unsafe { pthread_cond_timedwait(raw(self), mutex, &timeout) };
-        assert!(r == libc::ETIMEDOUT || r == 0);
-        r == 0
-    }
-}
diff --git a/library/std/src/sys/sync/condvar/windows7.rs b/library/std/src/sys/sync/condvar/windows7.rs
index 56eeeda551e..f03feef2221 100644
--- a/library/std/src/sys/sync/condvar/windows7.rs
+++ b/library/std/src/sys/sync/condvar/windows7.rs
@@ -1,5 +1,5 @@
 use crate::cell::UnsafeCell;
-use crate::sys::sync::{mutex, Mutex};
+use crate::sys::sync::{Mutex, mutex};
 use crate::sys::{c, os};
 use crate::time::Duration;
 
diff --git a/library/std/src/sys/sync/condvar/xous.rs b/library/std/src/sys/sync/condvar/xous.rs
index 007383479a1..cb55a3e3369 100644
--- a/library/std/src/sys/sync/condvar/xous.rs
+++ b/library/std/src/sys/sync/condvar/xous.rs
@@ -1,7 +1,7 @@
 use core::sync::atomic::{AtomicUsize, Ordering};
 
 use crate::os::xous::ffi::{blocking_scalar, scalar};
-use crate::os::xous::services::{ticktimer_server, TicktimerScalar};
+use crate::os::xous::services::{TicktimerScalar, ticktimer_server};
 use crate::sys::sync::Mutex;
 use crate::time::Duration;
 
diff --git a/library/std/src/sys/sync/mod.rs b/library/std/src/sys/sync/mod.rs
index 52fac5902a2..0691e967851 100644
--- a/library/std/src/sys/sync/mod.rs
+++ b/library/std/src/sys/sync/mod.rs
@@ -1,11 +1,14 @@
 mod condvar;
 mod mutex;
 mod once;
+mod once_box;
 mod rwlock;
 mod thread_parking;
 
 pub use condvar::Condvar;
 pub use mutex::Mutex;
 pub use once::{Once, OnceState};
+#[allow(unused)] // Only used on some platforms.
+use once_box::OnceBox;
 pub use rwlock::RwLock;
 pub use thread_parking::Parker;
diff --git a/library/std/src/sys/sync/mutex/fuchsia.rs b/library/std/src/sys/sync/mutex/fuchsia.rs
index 81a6361a83a..3e871285bea 100644
--- a/library/std/src/sys/sync/mutex/fuchsia.rs
+++ b/library/std/src/sys/sync/mutex/fuchsia.rs
@@ -40,9 +40,9 @@
 use crate::sync::atomic::AtomicU32;
 use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
 use crate::sys::futex::zircon::{
-    zx_futex_wait, zx_futex_wake_single_owner, zx_handle_t, zx_thread_self, ZX_ERR_BAD_HANDLE,
-    ZX_ERR_BAD_STATE, ZX_ERR_INVALID_ARGS, ZX_ERR_TIMED_OUT, ZX_ERR_WRONG_TYPE, ZX_OK,
-    ZX_TIME_INFINITE,
+    ZX_ERR_BAD_HANDLE, ZX_ERR_BAD_STATE, ZX_ERR_INVALID_ARGS, ZX_ERR_TIMED_OUT, ZX_ERR_WRONG_TYPE,
+    ZX_OK, ZX_TIME_INFINITE, zx_futex_wait, zx_futex_wake_single_owner, zx_handle_t,
+    zx_thread_self,
 };
 
 // The lowest two bits of a `zx_handle_t` are always set, so the lowest bit is used to mark the
diff --git a/library/std/src/sys/sync/mutex/itron.rs b/library/std/src/sys/sync/mutex/itron.rs
index 8440ffdd337..dcdfff0c81c 100644
--- a/library/std/src/sys/sync/mutex/itron.rs
+++ b/library/std/src/sys/sync/mutex/itron.rs
@@ -3,7 +3,7 @@
 #![forbid(unsafe_op_in_unsafe_fn)]
 
 use crate::sys::pal::itron::abi;
-use crate::sys::pal::itron::error::{expect_success, expect_success_aborting, fail, ItronError};
+use crate::sys::pal::itron::error::{ItronError, expect_success, expect_success_aborting, fail};
 use crate::sys::pal::itron::spin::SpinIdOnceCell;
 
 pub struct Mutex {
diff --git a/library/std/src/sys/sync/mutex/mod.rs b/library/std/src/sys/sync/mutex/mod.rs
index 73d9bd273de..360df3fc4b5 100644
--- a/library/std/src/sys/sync/mutex/mod.rs
+++ b/library/std/src/sys/sync/mutex/mod.rs
@@ -19,7 +19,7 @@ cfg_if::cfg_if! {
         target_os = "teeos",
     ))] {
         mod pthread;
-        pub use pthread::{Mutex, raw};
+        pub use pthread::Mutex;
     } else if #[cfg(all(target_os = "windows", target_vendor = "win7"))] {
         mod windows7;
         pub use windows7::{Mutex, raw};
diff --git a/library/std/src/sys/sync/mutex/pthread.rs b/library/std/src/sys/sync/mutex/pthread.rs
index ee0794334fb..87c95f45f96 100644
--- a/library/std/src/sys/sync/mutex/pthread.rs
+++ b/library/std/src/sys/sync/mutex/pthread.rs
@@ -1,25 +1,20 @@
 use crate::cell::UnsafeCell;
 use crate::io::Error;
-use crate::mem::{forget, MaybeUninit};
+use crate::mem::{MaybeUninit, forget};
 use crate::sys::cvt_nz;
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
+use crate::sys::sync::OnceBox;
 
 struct AllocatedMutex(UnsafeCell<libc::pthread_mutex_t>);
 
 pub struct Mutex {
-    inner: LazyBox<AllocatedMutex>,
-}
-
-#[inline]
-pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t {
-    m.inner.0.get()
+    inner: OnceBox<AllocatedMutex>,
 }
 
 unsafe impl Send for AllocatedMutex {}
 unsafe impl Sync for AllocatedMutex {}
 
-impl LazyInit for AllocatedMutex {
-    fn init() -> Box<Self> {
+impl AllocatedMutex {
+    fn new() -> Box<Self> {
         let mutex = Box::new(AllocatedMutex(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER)));
 
         // Issue #33770
@@ -60,24 +55,6 @@ impl LazyInit for AllocatedMutex {
 
         mutex
     }
-
-    fn destroy(mutex: Box<Self>) {
-        // We're not allowed to pthread_mutex_destroy a locked mutex,
-        // so check first if it's unlocked.
-        if unsafe { libc::pthread_mutex_trylock(mutex.0.get()) == 0 } {
-            unsafe { libc::pthread_mutex_unlock(mutex.0.get()) };
-            drop(mutex);
-        } else {
-            // The mutex is locked. This happens if a MutexGuard is leaked.
-            // In this case, we just leak the Mutex too.
-            forget(mutex);
-        }
-    }
-
-    fn cancel_init(_: Box<Self>) {
-        // In this case, we can just drop it without any checks,
-        // since it cannot have been locked yet.
-    }
 }
 
 impl Drop for AllocatedMutex {
@@ -99,11 +76,33 @@ impl Drop for AllocatedMutex {
 impl Mutex {
     #[inline]
     pub const fn new() -> Mutex {
-        Mutex { inner: LazyBox::new() }
+        Mutex { inner: OnceBox::new() }
+    }
+
+    /// Gets access to the pthread mutex under the assumption that the mutex is
+    /// locked.
+    ///
+    /// This allows skipping the initialization check, as the mutex can only be
+    /// locked if it is already initialized, and allows relaxing the ordering
+    /// on the pointer load, since the allocation cannot have been modified
+    /// since the `lock` and the lock must have occurred on the current thread.
+    ///
+    /// # Safety
+    /// Causes undefined behaviour if the mutex is not locked.
+    #[inline]
+    pub(crate) unsafe fn get_assert_locked(&self) -> *mut libc::pthread_mutex_t {
+        unsafe { self.inner.get_unchecked().0.get() }
     }
 
     #[inline]
-    pub unsafe fn lock(&self) {
+    fn get(&self) -> *mut libc::pthread_mutex_t {
+        // If initialization fails, the mutex is destroyed. This is always sound,
+        // however, as the mutex cannot have been locked yet.
+        self.inner.get_or_init(AllocatedMutex::new).0.get()
+    }
+
+    #[inline]
+    pub fn lock(&self) {
         #[cold]
         #[inline(never)]
         fn fail(r: i32) -> ! {
@@ -111,7 +110,7 @@ impl Mutex {
             panic!("failed to lock mutex: {error}");
         }
 
-        let r = libc::pthread_mutex_lock(raw(self));
+        let r = unsafe { libc::pthread_mutex_lock(self.get()) };
         // As we set the mutex type to `PTHREAD_MUTEX_NORMAL` above, we expect
         // the lock call to never fail. Unfortunately however, some platforms
         // (Solaris) do not conform to the standard, and instead always provide
@@ -126,13 +125,29 @@ impl Mutex {
 
     #[inline]
     pub unsafe fn unlock(&self) {
-        let r = libc::pthread_mutex_unlock(raw(self));
+        let r = libc::pthread_mutex_unlock(self.get_assert_locked());
         debug_assert_eq!(r, 0);
     }
 
     #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        libc::pthread_mutex_trylock(raw(self)) == 0
+    pub fn try_lock(&self) -> bool {
+        unsafe { libc::pthread_mutex_trylock(self.get()) == 0 }
+    }
+}
+
+impl Drop for Mutex {
+    fn drop(&mut self) {
+        let Some(mutex) = self.inner.take() else { return };
+        // We're not allowed to pthread_mutex_destroy a locked mutex,
+        // so check first if it's unlocked.
+        if unsafe { libc::pthread_mutex_trylock(mutex.0.get()) == 0 } {
+            unsafe { libc::pthread_mutex_unlock(mutex.0.get()) };
+            drop(mutex);
+        } else {
+            // The mutex is locked. This happens if a MutexGuard is leaked.
+            // In this case, we just leak the Mutex too.
+            forget(mutex);
+        }
     }
 }
 
diff --git a/library/std/src/sys/sync/mutex/sgx.rs b/library/std/src/sys/sync/mutex/sgx.rs
index d37bd02adf8..8529e857970 100644
--- a/library/std/src/sys/sync/mutex/sgx.rs
+++ b/library/std/src/sys/sync/mutex/sgx.rs
@@ -1,28 +1,24 @@
-use crate::sys::pal::waitqueue::{try_lock_or_false, SpinMutex, WaitQueue, WaitVariable};
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
-
-/// FIXME: `UnsafeList` is not movable.
-struct AllocatedMutex(SpinMutex<WaitVariable<bool>>);
+use crate::sys::pal::waitqueue::{SpinMutex, WaitQueue, WaitVariable, try_lock_or_false};
+use crate::sys::sync::OnceBox;
 
 pub struct Mutex {
-    inner: LazyBox<AllocatedMutex>,
-}
-
-impl LazyInit for AllocatedMutex {
-    fn init() -> Box<Self> {
-        Box::new(AllocatedMutex(SpinMutex::new(WaitVariable::new(false))))
-    }
+    // FIXME: `UnsafeList` is not movable.
+    inner: OnceBox<SpinMutex<WaitVariable<bool>>>,
 }
 
 // Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28
 impl Mutex {
     pub const fn new() -> Mutex {
-        Mutex { inner: LazyBox::new() }
+        Mutex { inner: OnceBox::new() }
+    }
+
+    fn get(&self) -> &SpinMutex<WaitVariable<bool>> {
+        self.inner.get_or_init(|| Box::new(SpinMutex::new(WaitVariable::new(false))))
     }
 
     #[inline]
     pub fn lock(&self) {
-        let mut guard = self.inner.0.lock();
+        let mut guard = self.get().lock();
         if *guard.lock_var() {
             // Another thread has the lock, wait
             WaitQueue::wait(guard, || {})
@@ -35,7 +31,9 @@ impl Mutex {
 
     #[inline]
     pub unsafe fn unlock(&self) {
-        let guard = self.inner.0.lock();
+        // SAFETY: the mutex was locked by the current thread, so it has been
+        // initialized already.
+        let guard = unsafe { self.inner.get_unchecked().lock() };
         if let Err(mut guard) = WaitQueue::notify_one(guard) {
             // No other waiters, unlock
             *guard.lock_var_mut() = false;
@@ -46,7 +44,7 @@ impl Mutex {
 
     #[inline]
     pub fn try_lock(&self) -> bool {
-        let mut guard = try_lock_or_false!(self.inner.0);
+        let mut guard = try_lock_or_false!(self.get());
         if *guard.lock_var() {
             // Another thread has the lock
             false
diff --git a/library/std/src/sys/sync/mutex/xous.rs b/library/std/src/sys/sync/mutex/xous.rs
index 63efa5a0210..233e638f913 100644
--- a/library/std/src/sys/sync/mutex/xous.rs
+++ b/library/std/src/sys/sync/mutex/xous.rs
@@ -1,5 +1,5 @@
 use crate::os::xous::ffi::{blocking_scalar, do_yield};
-use crate::os::xous::services::{ticktimer_server, TicktimerScalar};
+use crate::os::xous::services::{TicktimerScalar, ticktimer_server};
 use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
 use crate::sync::atomic::{AtomicBool, AtomicUsize};
 
diff --git a/library/std/src/sys/sync/once_box.rs b/library/std/src/sys/sync/once_box.rs
new file mode 100644
index 00000000000..1422b5a1721
--- /dev/null
+++ b/library/std/src/sys/sync/once_box.rs
@@ -0,0 +1,82 @@
+//! A racily-initialized alternative to `OnceLock<Box<T>>`.
+//!
+//! This is used to implement synchronization primitives that need allocation,
+//! like the pthread versions.
+
+#![allow(dead_code)] // Only used on some platforms.
+
+use crate::mem::replace;
+use crate::ptr::null_mut;
+use crate::sync::atomic::AtomicPtr;
+use crate::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed};
+
+pub(crate) struct OnceBox<T> {
+    ptr: AtomicPtr<T>,
+}
+
+impl<T> OnceBox<T> {
+    #[inline]
+    pub const fn new() -> Self {
+        Self { ptr: AtomicPtr::new(null_mut()) }
+    }
+
+    /// Gets access to the value, assuming it is already initialized and this
+    /// initialization has been observed by the current thread.
+    ///
+    /// Since all modifications to the pointer have already been observed, the
+    /// pointer load in this function can be performed with relaxed ordering,
+    /// potentially allowing the optimizer to turn code like this:
+    /// ```rust, ignore
+    /// once_box.get_or_init(|| Box::new(42));
+    /// unsafe { once_box.get_unchecked() }
+    /// ```
+    /// into
+    /// ```rust, ignore
+    /// once_box.get_or_init(|| Box::new(42))
+    /// ```
+    ///
+    /// # Safety
+    /// This causes undefined behaviour if the assumption above is violated.
+    #[inline]
+    pub unsafe fn get_unchecked(&self) -> &T {
+        unsafe { &*self.ptr.load(Relaxed) }
+    }
+
+    #[inline]
+    pub fn get_or_init(&self, f: impl FnOnce() -> Box<T>) -> &T {
+        let ptr = self.ptr.load(Acquire);
+        match unsafe { ptr.as_ref() } {
+            Some(val) => val,
+            None => self.initialize(f),
+        }
+    }
+
+    #[inline]
+    pub fn take(&mut self) -> Option<Box<T>> {
+        let ptr = replace(self.ptr.get_mut(), null_mut());
+        if !ptr.is_null() { Some(unsafe { Box::from_raw(ptr) }) } else { None }
+    }
+
+    #[cold]
+    fn initialize(&self, f: impl FnOnce() -> Box<T>) -> &T {
+        let new_ptr = Box::into_raw(f());
+        match self.ptr.compare_exchange(null_mut(), new_ptr, AcqRel, Acquire) {
+            Ok(_) => unsafe { &*new_ptr },
+            Err(ptr) => {
+                // Lost the race to another thread.
+                // Drop the value we created, and use the one from the other thread instead.
+                drop(unsafe { Box::from_raw(new_ptr) });
+                unsafe { &*ptr }
+            }
+        }
+    }
+}
+
+unsafe impl<T: Send> Send for OnceBox<T> {}
+unsafe impl<T: Send + Sync> Sync for OnceBox<T> {}
+
+impl<T> Drop for OnceBox<T> {
+    fn drop(&mut self) {
+        self.take();
+    }
+}
diff --git a/library/std/src/sys/sync/rwlock/queue.rs b/library/std/src/sys/sync/rwlock/queue.rs
index 458c16516bb..733f51cae8c 100644
--- a/library/std/src/sys/sync/rwlock/queue.rs
+++ b/library/std/src/sys/sync/rwlock/queue.rs
@@ -110,10 +110,10 @@
 use crate::cell::OnceCell;
 use crate::hint::spin_loop;
 use crate::mem;
-use crate::ptr::{self, null_mut, without_provenance_mut, NonNull};
+use crate::ptr::{self, NonNull, null_mut, without_provenance_mut};
 use crate::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release};
 use crate::sync::atomic::{AtomicBool, AtomicPtr};
-use crate::thread::{self, Thread};
+use crate::thread::{self, Thread, ThreadId};
 
 // Locking uses exponential backoff. `SPIN_COUNT` indicates how many times the
 // locking operation will be retried.
@@ -200,7 +200,9 @@ impl Node {
     fn prepare(&mut self) {
         // Fall back to creating an unnamed `Thread` handle to allow locking in
         // TLS destructors.
-        self.thread.get_or_init(|| thread::try_current().unwrap_or_else(Thread::new_unnamed));
+        self.thread.get_or_init(|| {
+            thread::try_current().unwrap_or_else(|| Thread::new_unnamed(ThreadId::new()))
+        });
         self.completed = AtomicBool::new(false);
     }
 
diff --git a/library/std/src/sys/sync/rwlock/solid.rs b/library/std/src/sys/sync/rwlock/solid.rs
index 05371402020..7703082f951 100644
--- a/library/std/src/sys/sync/rwlock/solid.rs
+++ b/library/std/src/sys/sync/rwlock/solid.rs
@@ -2,7 +2,7 @@
 #![forbid(unsafe_op_in_unsafe_fn)]
 
 use crate::sys::pal::abi;
-use crate::sys::pal::itron::error::{expect_success, expect_success_aborting, fail, ItronError};
+use crate::sys::pal::itron::error::{ItronError, expect_success, expect_success_aborting, fail};
 use crate::sys::pal::itron::spin::SpinIdOnceCell;
 
 pub struct RwLock {
diff --git a/library/std/src/sys/sync/rwlock/teeos.rs b/library/std/src/sys/sync/rwlock/teeos.rs
index ef9b1ab5154..76343022383 100644
--- a/library/std/src/sys/sync/rwlock/teeos.rs
+++ b/library/std/src/sys/sync/rwlock/teeos.rs
@@ -14,22 +14,22 @@ impl RwLock {
 
     #[inline]
     pub fn read(&self) {
-        unsafe { self.inner.lock() };
+        self.inner.lock()
     }
 
     #[inline]
     pub fn try_read(&self) -> bool {
-        unsafe { self.inner.try_lock() }
+        self.inner.try_lock()
     }
 
     #[inline]
     pub fn write(&self) {
-        unsafe { self.inner.lock() };
+        self.inner.lock()
     }
 
     #[inline]
     pub unsafe fn try_write(&self) -> bool {
-        unsafe { self.inner.try_lock() }
+        self.inner.try_lock()
     }
 
     #[inline]
diff --git a/library/std/src/sys/sync/thread_parking/id.rs b/library/std/src/sys/sync/thread_parking/id.rs
index a7b07b509df..64964351837 100644
--- a/library/std/src/sys/sync/thread_parking/id.rs
+++ b/library/std/src/sys/sync/thread_parking/id.rs
@@ -10,8 +10,8 @@
 use crate::cell::UnsafeCell;
 use crate::pin::Pin;
 use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
-use crate::sync::atomic::{fence, AtomicI8};
-use crate::sys::thread_parking::{current, park, park_timeout, unpark, ThreadId};
+use crate::sync::atomic::{AtomicI8, fence};
+use crate::sys::thread_parking::{ThreadId, current, park, park_timeout, unpark};
 use crate::time::Duration;
 
 pub struct Parker {
diff --git a/library/std/src/sys/sync/thread_parking/mod.rs b/library/std/src/sys/sync/thread_parking/mod.rs
index 0ebc5e093ee..f4d8fa0a58c 100644
--- a/library/std/src/sys/sync/thread_parking/mod.rs
+++ b/library/std/src/sys/sync/thread_parking/mod.rs
@@ -23,6 +23,7 @@ cfg_if::cfg_if! {
         mod windows7;
         pub use windows7::Parker;
     } else if #[cfg(all(target_vendor = "apple", not(miri)))] {
+        // Doesn't work in Miri, see <https://github.com/rust-lang/miri/issues/2589>.
         mod darwin;
         pub use darwin::Parker;
     } else if #[cfg(target_os = "xous")] {
diff --git a/library/std/src/sys/sync/thread_parking/pthread.rs b/library/std/src/sys/sync/thread_parking/pthread.rs
index c64600e9e29..5f195d0bb0c 100644
--- a/library/std/src/sys/sync/thread_parking/pthread.rs
+++ b/library/std/src/sys/sync/thread_parking/pthread.rs
@@ -3,7 +3,6 @@
 use crate::cell::UnsafeCell;
 use crate::marker::PhantomPinned;
 use crate::pin::Pin;
-use crate::ptr::addr_of_mut;
 use crate::sync::atomic::AtomicUsize;
 use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
 #[cfg(not(target_os = "nto"))]
@@ -101,8 +100,8 @@ impl Parker {
         // This could lead to undefined behaviour when deadlocking. This is avoided
         // by not deadlocking. Note in particular the unlocking operation before any
         // panic, as code after the panic could try to park again.
-        addr_of_mut!((*parker).state).write(AtomicUsize::new(EMPTY));
-        addr_of_mut!((*parker).lock).write(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER));
+        (&raw mut (*parker).state).write(AtomicUsize::new(EMPTY));
+        (&raw mut (*parker).lock).write(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER));
 
         cfg_if::cfg_if! {
             if #[cfg(any(
@@ -112,9 +111,9 @@ impl Parker {
                 target_os = "vita",
                 target_vendor = "apple",
             ))] {
-                addr_of_mut!((*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER));
+                (&raw mut (*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER));
             } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] {
-                let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), crate::ptr::null());
+                let r = libc::pthread_cond_init((&raw mut (*parker).cvar).cast(), crate::ptr::null());
                 assert_eq!(r, 0);
             } else {
                 use crate::mem::MaybeUninit;
@@ -123,7 +122,7 @@ impl Parker {
                 assert_eq!(r, 0);
                 let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC);
                 assert_eq!(r, 0);
-                let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), attr.as_ptr());
+                let r = libc::pthread_cond_init((&raw mut (*parker).cvar).cast(), attr.as_ptr());
                 assert_eq!(r, 0);
                 let r = libc::pthread_condattr_destroy(attr.as_mut_ptr());
                 assert_eq!(r, 0);
diff --git a/library/std/src/sys/sync/thread_parking/windows7.rs b/library/std/src/sys/sync/thread_parking/windows7.rs
index 1000b63b6d0..8f7e66c46ef 100644
--- a/library/std/src/sys/sync/thread_parking/windows7.rs
+++ b/library/std/src/sys/sync/thread_parking/windows7.rs
@@ -178,7 +178,7 @@ impl Parker {
     }
 
     fn ptr(&self) -> *const c_void {
-        core::ptr::addr_of!(self.state).cast::<c_void>()
+        (&raw const self.state).cast::<c_void>()
     }
 }
 
@@ -190,7 +190,7 @@ mod keyed_events {
     use core::sync::atomic::Ordering::{Acquire, Relaxed};
     use core::time::Duration;
 
-    use super::{Parker, EMPTY, NOTIFIED};
+    use super::{EMPTY, NOTIFIED, Parker};
     use crate::sys::c;
 
     pub unsafe fn park(parker: Pin<&Parker>) {
diff --git a/library/std/src/sys/sync/thread_parking/xous.rs b/library/std/src/sys/sync/thread_parking/xous.rs
index 64b6f731f23..28c90249dc2 100644
--- a/library/std/src/sys/sync/thread_parking/xous.rs
+++ b/library/std/src/sys/sync/thread_parking/xous.rs
@@ -1,5 +1,5 @@
 use crate::os::xous::ffi::{blocking_scalar, scalar};
-use crate::os::xous::services::{ticktimer_server, TicktimerScalar};
+use crate::os::xous::services::{TicktimerScalar, ticktimer_server};
 use crate::pin::Pin;
 use crate::ptr;
 use crate::sync::atomic::AtomicI8;
diff --git a/library/std/src/sys/thread_local/destructors/linux_like.rs b/library/std/src/sys/thread_local/destructors/linux_like.rs
index c381be0bf8c..f473dc4d79d 100644
--- a/library/std/src/sys/thread_local/destructors/linux_like.rs
+++ b/library/std/src/sys/thread_local/destructors/linux_like.rs
@@ -47,7 +47,7 @@ pub unsafe fn register(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
                     dtor,
                 ),
                 t.cast(),
-                core::ptr::addr_of!(__dso_handle) as *mut _,
+                (&raw const __dso_handle) as *mut _,
             );
         }
     } else {
diff --git a/library/std/src/sys/thread_local/guard/apple.rs b/library/std/src/sys/thread_local/guard/apple.rs
index 6c27f7ae35c..fa25b116622 100644
--- a/library/std/src/sys/thread_local/guard/apple.rs
+++ b/library/std/src/sys/thread_local/guard/apple.rs
@@ -26,6 +26,7 @@ pub fn enable() {
     unsafe extern "C" fn run_dtors(_: *mut u8) {
         unsafe {
             destructors::run();
+            crate::rt::thread_cleanup();
         }
     }
 }
diff --git a/library/std/src/sys/thread_local/guard/key.rs b/library/std/src/sys/thread_local/guard/key.rs
index 67c3ca88627..59581e6f281 100644
--- a/library/std/src/sys/thread_local/guard/key.rs
+++ b/library/std/src/sys/thread_local/guard/key.rs
@@ -3,10 +3,12 @@
 //! that will run all native TLS destructors in the destructor list.
 
 use crate::ptr;
-use crate::sys::thread_local::destructors;
-use crate::sys::thread_local::key::{set, LazyKey};
+use crate::sys::thread_local::key::{LazyKey, set};
 
+#[cfg(target_thread_local)]
 pub fn enable() {
+    use crate::sys::thread_local::destructors;
+
     static DTORS: LazyKey = LazyKey::new(Some(run));
 
     // Setting the key value to something other than NULL will result in the
@@ -18,6 +20,41 @@ pub fn enable() {
     unsafe extern "C" fn run(_: *mut u8) {
         unsafe {
             destructors::run();
+            // On platforms with `__cxa_thread_atexit_impl`, `destructors::run`
+            // does nothing on newer systems as the TLS destructors are
+            // registered with the system. But because all of those platforms
+            // call the destructors of TLS keys after the registered ones, this
+            // function will still be run last (at the time of writing).
+            crate::rt::thread_cleanup();
+        }
+    }
+}
+
+/// On platforms with key-based TLS, the system runs the destructors for us.
+/// We still have to make sure that [`crate::rt::thread_cleanup`] is called,
+/// however. This is done by defering the execution of a TLS destructor to
+/// the next round of destruction inside the TLS destructors.
+#[cfg(not(target_thread_local))]
+pub fn enable() {
+    const DEFER: *mut u8 = ptr::without_provenance_mut(1);
+    const RUN: *mut u8 = ptr::without_provenance_mut(2);
+
+    static CLEANUP: LazyKey = LazyKey::new(Some(run));
+
+    unsafe { set(CLEANUP.force(), DEFER) }
+
+    unsafe extern "C" fn run(state: *mut u8) {
+        if state == DEFER {
+            // Make sure that this function is run again in the next round of
+            // TLS destruction. If there is no futher round, there will be leaks,
+            // but that's okay, `thread_cleanup` is not guaranteed to be called.
+            unsafe { set(CLEANUP.force(), RUN) }
+        } else {
+            debug_assert_eq!(state, RUN);
+            // If the state is still RUN in the next round of TLS destruction,
+            // it means that no other TLS destructors defined by this runtime
+            // have been run, as they would have set the state to DEFER.
+            crate::rt::thread_cleanup();
         }
     }
 }
diff --git a/library/std/src/sys/thread_local/guard/solid.rs b/library/std/src/sys/thread_local/guard/solid.rs
index 054b2d561c8..3bcd46c481d 100644
--- a/library/std/src/sys/thread_local/guard/solid.rs
+++ b/library/std/src/sys/thread_local/guard/solid.rs
@@ -19,6 +19,9 @@ pub fn enable() {
     }
 
     unsafe extern "C" fn tls_dtor(_unused: *mut u8) {
-        unsafe { destructors::run() };
+        unsafe {
+            destructors::run();
+            crate::rt::thread_cleanup();
+        }
     }
 }
diff --git a/library/std/src/sys/thread_local/guard/windows.rs b/library/std/src/sys/thread_local/guard/windows.rs
index bf94f7d6e3d..7ee8e695c75 100644
--- a/library/std/src/sys/thread_local/guard/windows.rs
+++ b/library/std/src/sys/thread_local/guard/windows.rs
@@ -80,13 +80,13 @@ pub static CALLBACK: unsafe extern "system" fn(*mut c_void, u32, *mut c_void) =
 
 unsafe extern "system" fn tls_callback(_h: *mut c_void, dw_reason: u32, _pv: *mut c_void) {
     if dw_reason == c::DLL_THREAD_DETACH || dw_reason == c::DLL_PROCESS_DETACH {
-        #[cfg(target_thread_local)]
         unsafe {
+            #[cfg(target_thread_local)]
             super::super::destructors::run();
-        }
-        #[cfg(not(target_thread_local))]
-        unsafe {
+            #[cfg(not(target_thread_local))]
             super::super::key::run_dtors();
+
+            crate::rt::thread_cleanup();
         }
     }
 }
diff --git a/library/std/src/sys/thread_local/key/tests.rs b/library/std/src/sys/thread_local/key/tests.rs
index d82b34e71f0..c7d2c8e6301 100644
--- a/library/std/src/sys/thread_local/key/tests.rs
+++ b/library/std/src/sys/thread_local/key/tests.rs
@@ -1,4 +1,4 @@
-use super::{get, set, LazyKey};
+use super::{LazyKey, get, set};
 use crate::ptr;
 
 #[test]
diff --git a/library/std/src/sys/thread_local/key/xous.rs b/library/std/src/sys/thread_local/key/xous.rs
index 4fb2fdcc619..2ab4bba7d8e 100644
--- a/library/std/src/sys/thread_local/key/xous.rs
+++ b/library/std/src/sys/thread_local/key/xous.rs
@@ -39,7 +39,7 @@
 use core::arch::asm;
 
 use crate::mem::ManuallyDrop;
-use crate::os::xous::ffi::{map_memory, unmap_memory, MemoryFlags};
+use crate::os::xous::ffi::{MemoryFlags, map_memory, unmap_memory};
 use crate::ptr;
 use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
 use crate::sync::atomic::{AtomicPtr, AtomicUsize};
@@ -212,4 +212,6 @@ unsafe fn run_dtors() {
             unsafe { cur = (*cur).next };
         }
     }
+
+    crate::rt::thread_cleanup();
 }
diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs
index 3d1b91a7ea0..31d3b439060 100644
--- a/library/std/src/sys/thread_local/mod.rs
+++ b/library/std/src/sys/thread_local/mod.rs
@@ -31,12 +31,15 @@ cfg_if::cfg_if! {
     ))] {
         mod statik;
         pub use statik::{EagerStorage, LazyStorage, thread_local_inner};
+        pub(crate) use statik::{LocalPointer, local_pointer};
     } else if #[cfg(target_thread_local)] {
         mod native;
         pub use native::{EagerStorage, LazyStorage, thread_local_inner};
+        pub(crate) use native::{LocalPointer, local_pointer};
     } else {
         mod os;
         pub use os::{Storage, thread_local_inner};
+        pub(crate) use os::{LocalPointer, local_pointer};
     }
 }
 
@@ -72,36 +75,47 @@ pub(crate) mod destructors {
 }
 
 /// This module provides a way to schedule the execution of the destructor list
-/// on systems without a per-variable destructor system.
-mod guard {
+/// and the [runtime cleanup](crate::rt::thread_cleanup) function. Calling `enable`
+/// should ensure that these functions are called at the right times.
+pub(crate) mod guard {
     cfg_if::cfg_if! {
         if #[cfg(all(target_thread_local, target_vendor = "apple"))] {
             mod apple;
-            pub(super) use apple::enable;
+            pub(crate) use apple::enable;
         } else if #[cfg(target_os = "windows")] {
             mod windows;
-            pub(super) use windows::enable;
+            pub(crate) use windows::enable;
         } else if #[cfg(any(
-            all(target_family = "wasm", target_feature = "atomics"),
+            target_family = "wasm",
+            target_os = "uefi",
+            target_os = "zkvm",
         ))] {
-            pub(super) fn enable() {
-                // FIXME: Right now there is no concept of "thread exit", but
-                // this is likely going to show up at some point in the form of
-                // an exported symbol that the wasm runtime is going to be
-                // expected to call. For now we just leak everything, but if
-                // such a function starts to exist it will probably need to
-                // iterate the destructor list with this function:
+            pub(crate) fn enable() {
+                // FIXME: Right now there is no concept of "thread exit" on
+                // wasm, but this is likely going to show up at some point in
+                // the form of an exported symbol that the wasm runtime is going
+                // to be expected to call. For now we just leak everything, but
+                // if such a function starts to exist it will probably need to
+                // iterate the destructor list with these functions:
+                #[cfg(all(target_family = "wasm", target_feature = "atomics"))]
                 #[allow(unused)]
                 use super::destructors::run;
+                #[allow(unused)]
+                use crate::rt::thread_cleanup;
             }
-        } else if #[cfg(target_os = "hermit")] {
-            pub(super) fn enable() {}
+        } else if #[cfg(any(
+            target_os = "hermit",
+            target_os = "xous",
+        ))] {
+            // `std` is the only runtime, so it just calls the destructor functions
+            // itself when the time comes.
+            pub(crate) fn enable() {}
         } else if #[cfg(target_os = "solid_asp3")] {
             mod solid;
-            pub(super) use solid::enable;
-        } else if #[cfg(all(target_thread_local, not(target_family = "wasm")))] {
+            pub(crate) use solid::enable;
+        } else {
             mod key;
-            pub(super) use key::enable;
+            pub(crate) use key::enable;
         }
     }
 }
diff --git a/library/std/src/sys/thread_local/native/mod.rs b/library/std/src/sys/thread_local/native/mod.rs
index 1cc45fe892d..f498dee0899 100644
--- a/library/std/src/sys/thread_local/native/mod.rs
+++ b/library/std/src/sys/thread_local/native/mod.rs
@@ -29,6 +29,9 @@
 //! eliminates the `Destroyed` state for these values, which can allow more niche
 //! optimizations to occur for the `State` enum. For `Drop` types, `()` is used.
 
+use crate::cell::Cell;
+use crate::ptr;
+
 mod eager;
 mod lazy;
 
@@ -107,3 +110,31 @@ pub macro thread_local_inner {
             $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
     },
 }
+
+#[rustc_macro_transparency = "semitransparent"]
+pub(crate) macro local_pointer {
+    () => {},
+    ($vis:vis static $name:ident; $($rest:tt)*) => {
+        #[thread_local]
+        $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
+        $crate::sys::thread_local::local_pointer! { $($rest)* }
+    },
+}
+
+pub(crate) struct LocalPointer {
+    p: Cell<*mut ()>,
+}
+
+impl LocalPointer {
+    pub const fn __new() -> LocalPointer {
+        LocalPointer { p: Cell::new(ptr::null_mut()) }
+    }
+
+    pub fn get(&self) -> *mut () {
+        self.p.get()
+    }
+
+    pub fn set(&self, p: *mut ()) {
+        self.p.set(p)
+    }
+}
diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs
index e27b47c3f45..26ce3322a16 100644
--- a/library/std/src/sys/thread_local/os.rs
+++ b/library/std/src/sys/thread_local/os.rs
@@ -1,8 +1,8 @@
-use super::abort_on_dtor_unwind;
+use super::key::{Key, LazyKey, get, set};
+use super::{abort_on_dtor_unwind, guard};
 use crate::cell::Cell;
 use crate::marker::PhantomData;
 use crate::ptr;
-use crate::sys::thread_local::key::{get, set, Key, LazyKey};
 
 #[doc(hidden)]
 #[allow_internal_unstable(thread_local_internals)]
@@ -138,5 +138,35 @@ unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
         drop(ptr);
         // SAFETY: `key` is the TLS key `ptr` was stored under.
         unsafe { set(key, ptr::null_mut()) };
+        // Make sure that the runtime cleanup will be performed
+        // after the next round of TLS destruction.
+        guard::enable();
     });
 }
+
+#[rustc_macro_transparency = "semitransparent"]
+pub(crate) macro local_pointer {
+    () => {},
+    ($vis:vis static $name:ident; $($rest:tt)*) => {
+        $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
+        $crate::sys::thread_local::local_pointer! { $($rest)* }
+    },
+}
+
+pub(crate) struct LocalPointer {
+    key: LazyKey,
+}
+
+impl LocalPointer {
+    pub const fn __new() -> LocalPointer {
+        LocalPointer { key: LazyKey::new(None) }
+    }
+
+    pub fn get(&'static self) -> *mut () {
+        unsafe { get(self.key.force()) as *mut () }
+    }
+
+    pub fn set(&'static self, p: *mut ()) {
+        unsafe { set(self.key.force(), p as *mut u8) }
+    }
+}
diff --git a/library/std/src/sys/thread_local/statik.rs b/library/std/src/sys/thread_local/statik.rs
index a3451ab74e0..ba94caa6690 100644
--- a/library/std/src/sys/thread_local/statik.rs
+++ b/library/std/src/sys/thread_local/statik.rs
@@ -1,7 +1,8 @@
 //! On some targets like wasm there's no threads, so no need to generate
 //! thread locals and we can instead just use plain statics!
 
-use crate::cell::UnsafeCell;
+use crate::cell::{Cell, UnsafeCell};
+use crate::ptr;
 
 #[doc(hidden)]
 #[allow_internal_unstable(thread_local_internals)]
@@ -93,3 +94,33 @@ impl<T> LazyStorage<T> {
 
 // SAFETY: the target doesn't have threads.
 unsafe impl<T> Sync for LazyStorage<T> {}
+
+#[rustc_macro_transparency = "semitransparent"]
+pub(crate) macro local_pointer {
+    () => {},
+    ($vis:vis static $name:ident; $($rest:tt)*) => {
+        $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
+        $crate::sys::thread_local::local_pointer! { $($rest)* }
+    },
+}
+
+pub(crate) struct LocalPointer {
+    p: Cell<*mut ()>,
+}
+
+impl LocalPointer {
+    pub const fn __new() -> LocalPointer {
+        LocalPointer { p: Cell::new(ptr::null_mut()) }
+    }
+
+    pub fn get(&self) -> *mut () {
+        self.p.get()
+    }
+
+    pub fn set(&self, p: *mut ()) {
+        self.p.set(p)
+    }
+}
+
+// SAFETY: the target doesn't have threads.
+unsafe impl Sync for LocalPointer {}
diff --git a/library/std/src/sys_common/io.rs b/library/std/src/sys_common/io.rs
index e386c955f37..6f6f282d432 100644
--- a/library/std/src/sys_common/io.rs
+++ b/library/std/src/sys_common/io.rs
@@ -3,7 +3,7 @@
 pub const DEFAULT_BUF_SIZE: usize = if cfg!(target_os = "espidf") { 512 } else { 8 * 1024 };
 
 #[cfg(test)]
-#[allow(dead_code)] // not used on emscripten
+#[allow(dead_code)] // not used on emscripten and wasi
 pub mod test {
     use rand::RngCore;
 
diff --git a/library/std/src/sys_common/lazy_box.rs b/library/std/src/sys_common/lazy_box.rs
deleted file mode 100644
index b45b05f63ba..00000000000
--- a/library/std/src/sys_common/lazy_box.rs
+++ /dev/null
@@ -1,88 +0,0 @@
-#![allow(dead_code)] // Only used on some platforms.
-
-// This is used to wrap pthread {Mutex, Condvar, RwLock} in.
-
-use crate::marker::PhantomData;
-use crate::ops::{Deref, DerefMut};
-use crate::ptr::null_mut;
-use crate::sync::atomic::AtomicPtr;
-use crate::sync::atomic::Ordering::{AcqRel, Acquire};
-
-pub(crate) struct LazyBox<T: LazyInit> {
-    ptr: AtomicPtr<T>,
-    _phantom: PhantomData<T>,
-}
-
-pub(crate) trait LazyInit {
-    /// This is called before the box is allocated, to provide the value to
-    /// move into the new box.
-    ///
-    /// It might be called more than once per LazyBox, as multiple threads
-    /// might race to initialize it concurrently, each constructing and initializing
-    /// their own box. All but one of them will be passed to `cancel_init` right after.
-    fn init() -> Box<Self>;
-
-    /// Any surplus boxes from `init()` that lost the initialization race
-    /// are passed to this function for disposal.
-    ///
-    /// The default implementation calls destroy().
-    fn cancel_init(x: Box<Self>) {
-        Self::destroy(x);
-    }
-
-    /// This is called to destroy a used box.
-    ///
-    /// The default implementation just drops it.
-    fn destroy(_: Box<Self>) {}
-}
-
-impl<T: LazyInit> LazyBox<T> {
-    #[inline]
-    pub const fn new() -> Self {
-        Self { ptr: AtomicPtr::new(null_mut()), _phantom: PhantomData }
-    }
-
-    #[inline]
-    fn get_pointer(&self) -> *mut T {
-        let ptr = self.ptr.load(Acquire);
-        if ptr.is_null() { self.initialize() } else { ptr }
-    }
-
-    #[cold]
-    fn initialize(&self) -> *mut T {
-        let new_ptr = Box::into_raw(T::init());
-        match self.ptr.compare_exchange(null_mut(), new_ptr, AcqRel, Acquire) {
-            Ok(_) => new_ptr,
-            Err(ptr) => {
-                // Lost the race to another thread.
-                // Drop the box we created, and use the one from the other thread instead.
-                T::cancel_init(unsafe { Box::from_raw(new_ptr) });
-                ptr
-            }
-        }
-    }
-}
-
-impl<T: LazyInit> Deref for LazyBox<T> {
-    type Target = T;
-    #[inline]
-    fn deref(&self) -> &T {
-        unsafe { &*self.get_pointer() }
-    }
-}
-
-impl<T: LazyInit> DerefMut for LazyBox<T> {
-    #[inline]
-    fn deref_mut(&mut self) -> &mut T {
-        unsafe { &mut *self.get_pointer() }
-    }
-}
-
-impl<T: LazyInit> Drop for LazyBox<T> {
-    fn drop(&mut self) {
-        let ptr = *self.ptr.get_mut();
-        if !ptr.is_null() {
-            T::destroy(unsafe { Box::from_raw(ptr) });
-        }
-    }
-}
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 1c884f107be..4f7a131f6bb 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -22,7 +22,6 @@ mod tests;
 
 pub mod fs;
 pub mod io;
-pub mod lazy_box;
 pub mod process;
 pub mod wstr;
 pub mod wtf8;
@@ -32,7 +31,8 @@ cfg_if::cfg_if! {
         all(unix, not(target_os = "l4re")),
         windows,
         target_os = "hermit",
-        target_os = "solid_asp3"
+        target_os = "solid_asp3",
+        all(target_os = "wasi", target_env = "p2")
     ))] {
         pub mod net;
     } else {
diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs
index 25ebeb3502d..5a0ad907581 100644
--- a/library/std/src/sys_common/net.rs
+++ b/library/std/src/sys_common/net.rs
@@ -5,7 +5,7 @@ use crate::ffi::{c_int, c_void};
 use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut};
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
 use crate::sys::common::small_c_string::run_with_cstr;
-use crate::sys::net::{cvt, cvt_gai, cvt_r, init, netc as c, wrlen_t, Socket};
+use crate::sys::net::{Socket, cvt, cvt_gai, cvt_r, init, netc as c, wrlen_t};
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::time::Duration;
 use crate::{cmp, fmt, mem, ptr};
@@ -21,6 +21,7 @@ cfg_if::cfg_if! {
         target_os = "haiku",
         target_os = "l4re",
         target_os = "nto",
+        target_os = "nuttx",
         target_vendor = "apple",
     ))] {
         use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
@@ -73,7 +74,7 @@ pub fn setsockopt<T>(
             sock.as_raw(),
             level,
             option_name,
-            core::ptr::addr_of!(option_value) as *const _,
+            (&raw const option_value) as *const _,
             mem::size_of::<T>() as c::socklen_t,
         ))?;
         Ok(())
@@ -88,7 +89,7 @@ pub fn getsockopt<T: Copy>(sock: &Socket, level: c_int, option_name: c_int) -> i
             sock.as_raw(),
             level,
             option_name,
-            core::ptr::addr_of_mut!(option_value) as *mut _,
+            (&raw mut option_value) as *mut _,
             &mut option_len,
         ))?;
         Ok(option_value)
@@ -102,7 +103,7 @@ where
     unsafe {
         let mut storage: c::sockaddr_storage = mem::zeroed();
         let mut len = mem::size_of_val(&storage) as c::socklen_t;
-        cvt(f(core::ptr::addr_of_mut!(storage) as *mut _, &mut len))?;
+        cvt(f((&raw mut storage) as *mut _, &mut len))?;
         sockaddr_to_addr(&storage, len as usize)
     }
 }
@@ -451,7 +452,7 @@ impl TcpListener {
     pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
         let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() };
         let mut len = mem::size_of_val(&storage) as c::socklen_t;
-        let sock = self.inner.accept(core::ptr::addr_of_mut!(storage) as *mut _, &mut len)?;
+        let sock = self.inner.accept((&raw mut storage) as *mut _, &mut len)?;
         let addr = sockaddr_to_addr(&storage, len as usize)?;
         Ok((TcpStream { inner: sock }, addr))
     }
diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs
index 063451ad54e..19d4c94f450 100644
--- a/library/std/src/sys_common/wtf8.rs
+++ b/library/std/src/sys_common/wtf8.rs
@@ -18,7 +18,7 @@
 #[cfg(test)]
 mod tests;
 
-use core::char::{encode_utf16_raw, encode_utf8_raw};
+use core::char::{encode_utf8_raw, encode_utf16_raw};
 use core::clone::CloneToUninit;
 use core::str::next_code_point;
 
@@ -26,7 +26,6 @@ use crate::borrow::Cow;
 use crate::collections::TryReserveError;
 use crate::hash::{Hash, Hasher};
 use crate::iter::FusedIterator;
-use crate::ptr::addr_of_mut;
 use crate::rc::Rc;
 use crate::sync::Arc;
 use crate::sys_common::AsInner;
@@ -1055,6 +1054,6 @@ unsafe impl CloneToUninit for Wtf8 {
     #[cfg_attr(debug_assertions, track_caller)]
     unsafe fn clone_to_uninit(&self, dst: *mut Self) {
         // SAFETY: we're just a wrapper around [u8]
-        unsafe { self.bytes.clone_to_uninit(addr_of_mut!((*dst).bytes)) }
+        unsafe { self.bytes.clone_to_uninit(&raw mut (*dst).bytes) }
     }
 }
diff --git a/library/std/src/sys_common/wtf8/tests.rs b/library/std/src/sys_common/wtf8/tests.rs
index b57c99a8452..bc06eaa2b8f 100644
--- a/library/std/src/sys_common/wtf8/tests.rs
+++ b/library/std/src/sys_common/wtf8/tests.rs
@@ -356,32 +356,32 @@ fn wtf8buf_from_iterator() {
     fn f(values: &[u32]) -> Wtf8Buf {
         values.iter().map(|&c| CodePoint::from_u32(c).unwrap()).collect::<Wtf8Buf>()
     }
-    assert_eq!(
-        f(&[0x61, 0xE9, 0x20, 0x1F4A9]),
-        Wtf8Buf { bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), is_known_utf8: true }
-    );
+    assert_eq!(f(&[0x61, 0xE9, 0x20, 0x1F4A9]), Wtf8Buf {
+        bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(),
+        is_known_utf8: true
+    });
 
     assert_eq!(f(&[0xD83D, 0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic!
-    assert_eq!(
-        f(&[0xD83D, 0x20, 0xDCA9]),
-        Wtf8Buf { bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), is_known_utf8: false }
-    );
-    assert_eq!(
-        f(&[0xD800, 0xDBFF]),
-        Wtf8Buf { bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(), is_known_utf8: false }
-    );
-    assert_eq!(
-        f(&[0xD800, 0xE000]),
-        Wtf8Buf { bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(), is_known_utf8: false }
-    );
-    assert_eq!(
-        f(&[0xD7FF, 0xDC00]),
-        Wtf8Buf { bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(), is_known_utf8: false }
-    );
-    assert_eq!(
-        f(&[0x61, 0xDC00]),
-        Wtf8Buf { bytes: b"\x61\xED\xB0\x80".to_vec(), is_known_utf8: false }
-    );
+    assert_eq!(f(&[0xD83D, 0x20, 0xDCA9]), Wtf8Buf {
+        bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(),
+        is_known_utf8: false
+    });
+    assert_eq!(f(&[0xD800, 0xDBFF]), Wtf8Buf {
+        bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(),
+        is_known_utf8: false
+    });
+    assert_eq!(f(&[0xD800, 0xE000]), Wtf8Buf {
+        bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(),
+        is_known_utf8: false
+    });
+    assert_eq!(f(&[0xD7FF, 0xDC00]), Wtf8Buf {
+        bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(),
+        is_known_utf8: false
+    });
+    assert_eq!(f(&[0x61, 0xDC00]), Wtf8Buf {
+        bytes: b"\x61\xED\xB0\x80".to_vec(),
+        is_known_utf8: false
+    });
     assert_eq!(f(&[0xDC00]), Wtf8Buf { bytes: b"\xED\xB0\x80".to_vec(), is_known_utf8: false });
 }
 
@@ -396,36 +396,36 @@ fn wtf8buf_extend() {
         string
     }
 
-    assert_eq!(
-        e(&[0x61, 0xE9], &[0x20, 0x1F4A9]),
-        Wtf8Buf { bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), is_known_utf8: true }
-    );
+    assert_eq!(e(&[0x61, 0xE9], &[0x20, 0x1F4A9]), Wtf8Buf {
+        bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(),
+        is_known_utf8: true
+    });
 
     assert_eq!(e(&[0xD83D], &[0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic!
-    assert_eq!(
-        e(&[0xD83D, 0x20], &[0xDCA9]),
-        Wtf8Buf { bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), is_known_utf8: false }
-    );
-    assert_eq!(
-        e(&[0xD800], &[0xDBFF]),
-        Wtf8Buf { bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(), is_known_utf8: false }
-    );
-    assert_eq!(
-        e(&[0xD800], &[0xE000]),
-        Wtf8Buf { bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(), is_known_utf8: false }
-    );
-    assert_eq!(
-        e(&[0xD7FF], &[0xDC00]),
-        Wtf8Buf { bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(), is_known_utf8: false }
-    );
-    assert_eq!(
-        e(&[0x61], &[0xDC00]),
-        Wtf8Buf { bytes: b"\x61\xED\xB0\x80".to_vec(), is_known_utf8: false }
-    );
-    assert_eq!(
-        e(&[], &[0xDC00]),
-        Wtf8Buf { bytes: b"\xED\xB0\x80".to_vec(), is_known_utf8: false }
-    );
+    assert_eq!(e(&[0xD83D, 0x20], &[0xDCA9]), Wtf8Buf {
+        bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(),
+        is_known_utf8: false
+    });
+    assert_eq!(e(&[0xD800], &[0xDBFF]), Wtf8Buf {
+        bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(),
+        is_known_utf8: false
+    });
+    assert_eq!(e(&[0xD800], &[0xE000]), Wtf8Buf {
+        bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(),
+        is_known_utf8: false
+    });
+    assert_eq!(e(&[0xD7FF], &[0xDC00]), Wtf8Buf {
+        bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(),
+        is_known_utf8: false
+    });
+    assert_eq!(e(&[0x61], &[0xDC00]), Wtf8Buf {
+        bytes: b"\x61\xED\xB0\x80".to_vec(),
+        is_known_utf8: false
+    });
+    assert_eq!(e(&[], &[0xDC00]), Wtf8Buf {
+        bytes: b"\xED\xB0\x80".to_vec(),
+        is_known_utf8: false
+    });
 }
 
 #[test]
@@ -556,10 +556,9 @@ fn wtf8_encode_wide() {
     let mut string = Wtf8Buf::from_str("aé ");
     string.push(CodePoint::from_u32(0xD83D).unwrap());
     string.push_char('💩');
-    assert_eq!(
-        string.encode_wide().collect::<Vec<_>>(),
-        vec![0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]
-    );
+    assert_eq!(string.encode_wide().collect::<Vec<_>>(), vec![
+        0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9
+    ]);
 }
 
 #[test]
diff --git a/library/std/src/thread/current.rs b/library/std/src/thread/current.rs
new file mode 100644
index 00000000000..e6eb90c4c30
--- /dev/null
+++ b/library/std/src/thread/current.rs
@@ -0,0 +1,254 @@
+use super::{Thread, ThreadId};
+use crate::mem::ManuallyDrop;
+use crate::ptr;
+use crate::sys::thread_local::local_pointer;
+
+const NONE: *mut () = ptr::null_mut();
+const BUSY: *mut () = ptr::without_provenance_mut(1);
+const DESTROYED: *mut () = ptr::without_provenance_mut(2);
+
+local_pointer! {
+    static CURRENT;
+}
+
+/// Persistent storage for the thread ID.
+///
+/// We store the thread ID so that it never gets destroyed during the lifetime
+/// of a thread, either using `#[thread_local]` or multiple `local_pointer!`s.
+mod id {
+    use super::*;
+
+    cfg_if::cfg_if! {
+        if #[cfg(target_thread_local)] {
+            use crate::cell::Cell;
+
+            #[thread_local]
+            static ID: Cell<Option<ThreadId>> = Cell::new(None);
+
+            pub(super) const CHEAP: bool = true;
+
+            pub(super) fn get() -> Option<ThreadId> {
+                ID.get()
+            }
+
+            pub(super) fn set(id: ThreadId) {
+                ID.set(Some(id))
+            }
+        } else if #[cfg(target_pointer_width = "16")] {
+            local_pointer! {
+                static ID0;
+                static ID16;
+                static ID32;
+                static ID48;
+            }
+
+            pub(super) const CHEAP: bool = false;
+
+            pub(super) fn get() -> Option<ThreadId> {
+                let id0 = ID0.get().addr() as u64;
+                let id16 = ID16.get().addr() as u64;
+                let id32 = ID32.get().addr() as u64;
+                let id48 = ID48.get().addr() as u64;
+                ThreadId::from_u64((id48 << 48) + (id32 << 32) + (id16 << 16) + id0)
+            }
+
+            pub(super) fn set(id: ThreadId) {
+                let val = id.as_u64().get();
+                ID0.set(ptr::without_provenance_mut(val as usize));
+                ID16.set(ptr::without_provenance_mut((val >> 16) as usize));
+                ID32.set(ptr::without_provenance_mut((val >> 32) as usize));
+                ID48.set(ptr::without_provenance_mut((val >> 48) as usize));
+            }
+        } else if #[cfg(target_pointer_width = "32")] {
+            local_pointer! {
+                static ID0;
+                static ID32;
+            }
+
+            pub(super) const CHEAP: bool = false;
+
+            pub(super) fn get() -> Option<ThreadId> {
+                let id0 = ID0.get().addr() as u64;
+                let id32 = ID32.get().addr() as u64;
+                ThreadId::from_u64((id32 << 32) + id0)
+            }
+
+            pub(super) fn set(id: ThreadId) {
+                let val = id.as_u64().get();
+                ID0.set(ptr::without_provenance_mut(val as usize));
+                ID32.set(ptr::without_provenance_mut((val >> 32) as usize));
+            }
+        } else {
+            local_pointer! {
+                static ID;
+            }
+
+            pub(super) const CHEAP: bool = true;
+
+            pub(super) fn get() -> Option<ThreadId> {
+                let id = ID.get().addr() as u64;
+                ThreadId::from_u64(id)
+            }
+
+            pub(super) fn set(id: ThreadId) {
+                let val = id.as_u64().get();
+                ID.set(ptr::without_provenance_mut(val as usize));
+            }
+        }
+    }
+
+    #[inline]
+    pub(super) fn get_or_init() -> ThreadId {
+        get().unwrap_or_else(
+            #[cold]
+            || {
+                let id = ThreadId::new();
+                id::set(id);
+                id
+            },
+        )
+    }
+}
+
+/// Tries to set the thread handle for the current thread. Fails if a handle was
+/// already set or if the thread ID of `thread` would change an already-set ID.
+pub(crate) fn set_current(thread: Thread) -> Result<(), Thread> {
+    if CURRENT.get() != NONE {
+        return Err(thread);
+    }
+
+    match id::get() {
+        Some(id) if id == thread.id() => {}
+        None => id::set(thread.id()),
+        _ => return Err(thread),
+    }
+
+    // Make sure that `crate::rt::thread_cleanup` will be run, which will
+    // call `drop_current`.
+    crate::sys::thread_local::guard::enable();
+    CURRENT.set(thread.into_raw().cast_mut());
+    Ok(())
+}
+
+/// Gets the id of the thread that invokes it.
+///
+/// This function will always succeed, will always return the same value for
+/// one thread and is guaranteed not to call the global allocator.
+#[inline]
+pub(crate) fn current_id() -> ThreadId {
+    // If accessing the persistant thread ID takes multiple TLS accesses, try
+    // to retrieve it from the current thread handle, which will only take one
+    // TLS access.
+    if !id::CHEAP {
+        let current = CURRENT.get();
+        if current > DESTROYED {
+            unsafe {
+                let current = ManuallyDrop::new(Thread::from_raw(current));
+                return current.id();
+            }
+        }
+    }
+
+    id::get_or_init()
+}
+
+/// Gets a handle to the thread that invokes it, if the handle has been initialized.
+pub(crate) fn try_current() -> Option<Thread> {
+    let current = CURRENT.get();
+    if current > DESTROYED {
+        unsafe {
+            let current = ManuallyDrop::new(Thread::from_raw(current));
+            Some((*current).clone())
+        }
+    } else {
+        None
+    }
+}
+
+/// Gets a handle to the thread that invokes it.
+///
+/// # Examples
+///
+/// Getting a handle to the current thread with `thread::current()`:
+///
+/// ```
+/// use std::thread;
+///
+/// let handler = thread::Builder::new()
+///     .name("named thread".into())
+///     .spawn(|| {
+///         let handle = thread::current();
+///         assert_eq!(handle.name(), Some("named thread"));
+///     })
+///     .unwrap();
+///
+/// handler.join().unwrap();
+/// ```
+#[must_use]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn current() -> Thread {
+    let current = CURRENT.get();
+    if current > DESTROYED {
+        unsafe {
+            let current = ManuallyDrop::new(Thread::from_raw(current));
+            (*current).clone()
+        }
+    } else {
+        init_current(current)
+    }
+}
+
+#[cold]
+fn init_current(current: *mut ()) -> Thread {
+    if current == NONE {
+        CURRENT.set(BUSY);
+        // If the thread ID was initialized already, use it.
+        let id = id::get_or_init();
+        let thread = Thread::new_unnamed(id);
+
+        // Make sure that `crate::rt::thread_cleanup` will be run, which will
+        // call `drop_current`.
+        crate::sys::thread_local::guard::enable();
+        CURRENT.set(thread.clone().into_raw().cast_mut());
+        thread
+    } else if current == BUSY {
+        // BUSY exists solely for this check, but as it is in the slow path, the
+        // extra TLS write above shouldn't matter. The alternative is nearly always
+        // a stack overflow.
+
+        // If you came across this message, contact the author of your allocator.
+        // If you are said author: A surprising amount of functions inside the
+        // standard library (e.g. `Mutex`, `thread_local!`, `File` when using long
+        // paths, even `panic!` when using unwinding), need memory allocation, so
+        // you'll get circular dependencies all over the place when using them.
+        // I (joboet) highly recommend using only APIs from core in your allocator
+        // and implementing your own system abstractions. Still, if you feel that
+        // a particular API should be entirely allocation-free, feel free to open
+        // an issue on the Rust repository, we'll see what we can do.
+        rtabort!(
+            "\n
+            Attempted to access thread-local data while allocating said data.\n
+            Do not access functions that allocate in the global allocator!\n
+            This is a bug in the global allocator.\n
+        "
+        )
+    } else {
+        debug_assert_eq!(current, DESTROYED);
+        panic!(
+            "use of std::thread::current() is not possible after the thread's
+         local data has been destroyed"
+        )
+    }
+}
+
+/// This should be run in [`crate::rt::thread_cleanup`] to reset the thread
+/// handle.
+pub(crate) fn drop_current() {
+    let current = CURRENT.get();
+    if current > DESTROYED {
+        unsafe {
+            CURRENT.set(DESTROYED);
+            drop(Thread::from_raw(current));
+        }
+    }
+}
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index f147c5fdcd1..88bf186700f 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -2,7 +2,7 @@
 
 #![unstable(feature = "thread_local_internals", issue = "none")]
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 #[cfg(test)]
diff --git a/library/std/src/thread/local/tests.rs b/library/std/src/thread/local/tests.rs
index 25019b554bb..9d4f52a0921 100644
--- a/library/std/src/thread/local/tests.rs
+++ b/library/std/src/thread/local/tests.rs
@@ -1,7 +1,7 @@
 use crate::cell::{Cell, UnsafeCell};
 use crate::sync::atomic::{AtomicU8, Ordering};
 use crate::sync::{Arc, Condvar, Mutex};
-use crate::thread::{self, LocalKey};
+use crate::thread::{self, Builder, LocalKey};
 use crate::thread_local;
 
 #[derive(Clone, Default)]
@@ -103,6 +103,9 @@ fn smoke_dtor() {
 
 #[test]
 fn circular() {
+    // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
+    #![allow(static_mut_refs)]
+
     struct S1(&'static LocalKey<UnsafeCell<Option<S1>>>, &'static LocalKey<UnsafeCell<Option<S2>>>);
     struct S2(&'static LocalKey<UnsafeCell<Option<S1>>>, &'static LocalKey<UnsafeCell<Option<S2>>>);
     thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
@@ -340,3 +343,34 @@ fn join_orders_after_tls_destructors() {
         jh2.join().unwrap();
     }
 }
+
+// Test that thread::current is still available in TLS destructors.
+#[test]
+fn thread_current_in_dtor() {
+    // Go through one round of TLS destruction first.
+    struct Defer;
+    impl Drop for Defer {
+        fn drop(&mut self) {
+            RETRIEVE.with(|_| {});
+        }
+    }
+
+    struct RetrieveName;
+    impl Drop for RetrieveName {
+        fn drop(&mut self) {
+            *NAME.lock().unwrap() = Some(thread::current().name().unwrap().to_owned());
+        }
+    }
+
+    static NAME: Mutex<Option<String>> = Mutex::new(None);
+
+    thread_local! {
+        static DEFER: Defer = const { Defer };
+        static RETRIEVE: RetrieveName = const { RetrieveName };
+    }
+
+    Builder::new().name("test".to_owned()).spawn(|| DEFER.with(|_| {})).unwrap().join().unwrap();
+    let name = NAME.lock().unwrap();
+    let name = name.as_ref().unwrap();
+    assert_eq!(name, "test");
+}
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 33cb7e0bcca..39753888509 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -141,7 +141,7 @@
 //! [`Result`]: crate::result::Result
 //! [`Ok`]: crate::result::Result::Ok
 //! [`Err`]: crate::result::Result::Err
-//! [`thread::current`]: current
+//! [`thread::current`]: current::current
 //! [`thread::Result`]: Result
 //! [`unpark`]: Thread::unpark
 //! [`thread::park_timeout`]: park_timeout
@@ -155,19 +155,18 @@
 // Under `test`, `__FastLocalKeyInner` seems unused.
 #![cfg_attr(test, allow(dead_code))]
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 use crate::any::Any;
-use crate::cell::{Cell, OnceCell, UnsafeCell};
+use crate::cell::UnsafeCell;
 use crate::ffi::CStr;
 use crate::marker::PhantomData;
-use crate::mem::{self, forget, ManuallyDrop};
+use crate::mem::{self, ManuallyDrop, forget};
 use crate::num::NonZero;
 use crate::pin::Pin;
-use crate::ptr::addr_of_mut;
-use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sync::Arc;
+use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sys::sync::Parker;
 use crate::sys::thread as imp;
 use crate::sys_common::{AsInner, IntoInner};
@@ -178,7 +177,13 @@ use crate::{env, fmt, io, panic, panicking, str};
 mod scoped;
 
 #[stable(feature = "scoped_threads", since = "1.63.0")]
-pub use scoped::{scope, Scope, ScopedJoinHandle};
+pub use scoped::{Scope, ScopedJoinHandle, scope};
+
+mod current;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use current::current;
+pub(crate) use current::{current_id, drop_current, set_current, try_current};
 
 ////////////////////////////////////////////////////////////////////////////////
 // Thread-local storage
@@ -472,7 +477,11 @@ impl Builder {
             amt
         });
 
-        let my_thread = name.map_or_else(Thread::new_unnamed, Thread::new);
+        let id = ThreadId::new();
+        let my_thread = match name {
+            Some(name) => Thread::new(id, name.into()),
+            None => Thread::new_unnamed(id),
+        };
         let their_thread = my_thread.clone();
 
         let my_packet: Arc<Packet<'scope, T>> = Arc::new(Packet {
@@ -510,6 +519,14 @@ impl Builder {
 
         let f = MaybeDangling::new(f);
         let main = move || {
+            if let Err(_thread) = set_current(their_thread.clone()) {
+                // Both the current thread handle and the ID should not be
+                // initialized yet. Since only the C runtime and some of our
+                // platform code run before this, this point shouldn't be
+                // reachable. Use an abort to save binary size (see #123356).
+                rtabort!("something here is badly broken!");
+            }
+
             if let Some(name) = their_thread.cname() {
                 imp::Thread::set_name(name);
             }
@@ -517,7 +534,6 @@ impl Builder {
             crate::io::set_output_capture(output_capture);
 
             let f = f.into_inner();
-            set_current(their_thread);
             let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
                 crate::sys::backtrace::__rust_begin_short_backtrace(f)
             }));
@@ -665,6 +681,19 @@ impl Builder {
 /// println!("{result}");
 /// ```
 ///
+/// # Notes
+///
+/// This function has the same minimal guarantee regarding "foreign" unwinding operations (e.g.
+/// an exception thrown from C++ code, or a `panic!` in Rust code compiled or linked with a
+/// different runtime) as [`catch_unwind`]; namely, if the thread created with `thread::spawn`
+/// unwinds all the way to the root with such an exception, one of two behaviors are possible,
+/// and it is unspecified which will occur:
+///
+/// * The process aborts.
+/// * The process does not abort, and [`join`] will return a `Result::Err`
+///   containing an opaque type.
+///
+/// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html
 /// [`channels`]: crate::sync::mpsc
 /// [`join`]: JoinHandle::join
 /// [`Err`]: crate::result::Result::Err
@@ -678,84 +707,6 @@ where
     Builder::new().spawn(f).expect("failed to spawn thread")
 }
 
-thread_local! {
-    // Invariant: `CURRENT` and `CURRENT_ID` will always be initialized together.
-    // If `CURRENT` is initialized, then `CURRENT_ID` will hold the same value
-    // as `CURRENT.id()`.
-    static CURRENT: OnceCell<Thread> = const { OnceCell::new() };
-    static CURRENT_ID: Cell<Option<ThreadId>> = const { Cell::new(None) };
-}
-
-/// Sets the thread handle for the current thread.
-///
-/// Aborts if the handle has been set already to reduce code size.
-pub(crate) fn set_current(thread: Thread) {
-    let tid = thread.id();
-    // Using `unwrap` here can add ~3kB to the binary size. We have complete
-    // control over where this is called, so just abort if there is a bug.
-    CURRENT.with(|current| match current.set(thread) {
-        Ok(()) => CURRENT_ID.set(Some(tid)),
-        Err(_) => rtabort!("thread::set_current should only be called once per thread"),
-    });
-}
-
-/// Gets a handle to the thread that invokes it.
-///
-/// In contrast to the public `current` function, this will not panic if called
-/// from inside a TLS destructor.
-pub(crate) fn try_current() -> Option<Thread> {
-    CURRENT
-        .try_with(|current| {
-            current
-                .get_or_init(|| {
-                    let thread = Thread::new_unnamed();
-                    CURRENT_ID.set(Some(thread.id()));
-                    thread
-                })
-                .clone()
-        })
-        .ok()
-}
-
-/// Gets the id of the thread that invokes it.
-#[inline]
-pub(crate) fn current_id() -> ThreadId {
-    CURRENT_ID.get().unwrap_or_else(|| {
-        // If `CURRENT_ID` isn't initialized yet, then `CURRENT` must also not be initialized.
-        // `current()` will initialize both `CURRENT` and `CURRENT_ID` so subsequent calls to
-        // `current_id()` will succeed immediately.
-        current().id()
-    })
-}
-
-/// Gets a handle to the thread that invokes it.
-///
-/// # Examples
-///
-/// Getting a handle to the current thread with `thread::current()`:
-///
-/// ```
-/// use std::thread;
-///
-/// let handler = thread::Builder::new()
-///     .name("named thread".into())
-///     .spawn(|| {
-///         let handle = thread::current();
-///         assert_eq!(handle.name(), Some("named thread"));
-///     })
-///     .unwrap();
-///
-/// handler.join().unwrap();
-/// ```
-#[must_use]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn current() -> Thread {
-    try_current().expect(
-        "use of std::thread::current() is not possible \
-         after the thread's local data has been destroyed",
-    )
-}
-
 /// Cooperatively gives up a timeslice to the OS scheduler.
 ///
 /// This calls the underlying OS scheduler's yield primitive, signaling
@@ -1214,7 +1165,7 @@ pub struct ThreadId(NonZero<u64>);
 
 impl ThreadId {
     // Generate a new unique thread ID.
-    fn new() -> ThreadId {
+    pub(crate) fn new() -> ThreadId {
         #[cold]
         fn exhausted() -> ! {
             panic!("failed to generate unique thread ID: bitspace exhausted")
@@ -1257,6 +1208,11 @@ impl ThreadId {
         }
     }
 
+    #[cfg(not(target_thread_local))]
+    fn from_u64(v: u64) -> Option<ThreadId> {
+        NonZero::new(v).map(ThreadId)
+    }
+
     /// This returns a numeric identifier for the thread identified by this
     /// `ThreadId`.
     ///
@@ -1357,27 +1313,27 @@ impl Inner {
 /// should instead use a function like `spawn` to create new threads, see the
 /// docs of [`Builder`] and [`spawn`] for more details.
 ///
-/// [`thread::current`]: current
+/// [`thread::current`]: current::current
 pub struct Thread {
     inner: Pin<Arc<Inner>>,
 }
 
 impl Thread {
     /// Used only internally to construct a thread object without spawning.
-    pub(crate) fn new(name: String) -> Thread {
-        Self::new_inner(ThreadName::Other(name.into()))
+    pub(crate) fn new(id: ThreadId, name: String) -> Thread {
+        Self::new_inner(id, ThreadName::Other(name.into()))
     }
 
-    pub(crate) fn new_unnamed() -> Thread {
-        Self::new_inner(ThreadName::Unnamed)
+    pub(crate) fn new_unnamed(id: ThreadId) -> Thread {
+        Self::new_inner(id, ThreadName::Unnamed)
     }
 
-    // Used in runtime to construct main thread
-    pub(crate) fn new_main() -> Thread {
-        Self::new_inner(ThreadName::Main)
+    /// Constructs the thread handle for the main thread.
+    pub(crate) fn new_main(id: ThreadId) -> Thread {
+        Self::new_inner(id, ThreadName::Main)
     }
 
-    fn new_inner(name: ThreadName) -> Thread {
+    fn new_inner(id: ThreadId, name: ThreadName) -> Thread {
         // We have to use `unsafe` here to construct the `Parker` in-place,
         // which is required for the UNIX implementation.
         //
@@ -1386,9 +1342,9 @@ impl Thread {
         let inner = unsafe {
             let mut arc = Arc::<Inner>::new_uninit();
             let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr();
-            addr_of_mut!((*ptr).name).write(name);
-            addr_of_mut!((*ptr).id).write(ThreadId::new());
-            Parker::new_in_place(addr_of_mut!((*ptr).parker));
+            (&raw mut (*ptr).name).write(name);
+            (&raw mut (*ptr).id).write(id);
+            Parker::new_in_place(&raw mut (*ptr).parker);
             Pin::new_unchecked(arc.assume_init())
         };
 
@@ -1785,7 +1741,7 @@ impl<T> JoinHandle<T> {
     /// operations that happen after `join` returns.
     ///
     /// If the associated thread panics, [`Err`] is returned with the parameter given
-    /// to [`panic!`].
+    /// to [`panic!`] (though see the Notes below).
     ///
     /// [`Err`]: crate::result::Result::Err
     /// [atomic memory orderings]: crate::sync::atomic
@@ -1807,6 +1763,18 @@ impl<T> JoinHandle<T> {
     /// }).unwrap();
     /// join_handle.join().expect("Couldn't join on the associated thread");
     /// ```
+    ///
+    /// # Notes
+    ///
+    /// If a "foreign" unwinding operation (e.g. an exception thrown from C++
+    /// code, or a `panic!` in Rust code compiled or linked with a different
+    /// runtime) unwinds all the way to the thread root, the process may be
+    /// aborted; see the Notes on [`thread::spawn`]. If the process is not
+    /// aborted, this function will return a `Result::Err` containing an opaque
+    /// type.
+    ///
+    /// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html
+    /// [`thread::spawn`]: spawn
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn join(self) -> Result<T> {
         self.0.join()
diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs
index ba27c9220ae..b2305b1eda7 100644
--- a/library/std/src/thread/scoped.rs
+++ b/library/std/src/thread/scoped.rs
@@ -1,8 +1,8 @@
-use super::{current, park, Builder, JoinInner, Result, Thread};
+use super::{Builder, JoinInner, Result, Thread, current, park};
 use crate::marker::PhantomData;
-use crate::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
-use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
+use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
 use crate::sync::Arc;
+use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
 use crate::{fmt, io};
 
 /// A scope to spawn scoped threads in.
diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs
index aa464d56f95..ff45e82bd9c 100644
--- a/library/std/src/thread/tests.rs
+++ b/library/std/src/thread/tests.rs
@@ -2,7 +2,7 @@ use super::Builder;
 use crate::any::Any;
 use crate::panic::panic_any;
 use crate::sync::atomic::{AtomicBool, Ordering};
-use crate::sync::mpsc::{channel, Sender};
+use crate::sync::mpsc::{Sender, channel};
 use crate::sync::{Arc, Barrier};
 use crate::thread::{self, Scope, ThreadId};
 use crate::time::{Duration, Instant};
diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs
index de36dc4c9fd..e88f2d5e806 100644
--- a/library/std/src/time/tests.rs
+++ b/library/std/src/time/tests.rs
@@ -1,7 +1,7 @@
 use core::fmt::Debug;
 
 #[cfg(not(target_arch = "wasm32"))]
-use test::{black_box, Bencher};
+use test::{Bencher, black_box};
 
 use super::{Duration, Instant, SystemTime, UNIX_EPOCH};
 
@@ -235,8 +235,8 @@ macro_rules! bench_instant_threaded {
         #[bench]
         #[cfg(not(target_arch = "wasm32"))]
         fn $bench_name(b: &mut Bencher) -> crate::thread::Result<()> {
-            use crate::sync::atomic::{AtomicBool, Ordering};
             use crate::sync::Arc;
+            use crate::sync::atomic::{AtomicBool, Ordering};
 
             let running = Arc::new(AtomicBool::new(true));