about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/alloc.rs2
-rw-r--r--library/std/src/backtrace.rs8
-rw-r--r--library/std/src/collections/hash/map/tests.rs9
-rw-r--r--library/std/src/collections/hash/set.rs2
-rw-r--r--library/std/src/fs/tests.rs6
-rw-r--r--library/std/src/io/error/repr_bitpacked.rs8
-rw-r--r--library/std/src/io/mod.rs10
-rw-r--r--library/std/src/io/stdio.rs3
-rw-r--r--library/std/src/lib.rs37
-rw-r--r--library/std/src/macros.rs1
-rw-r--r--library/std/src/net/ip_addr.rs9
-rw-r--r--library/std/src/panic.rs3
-rw-r--r--library/std/src/panicking.rs8
-rw-r--r--library/std/src/path.rs46
-rw-r--r--library/std/src/prelude/v1.rs9
-rw-r--r--library/std/src/process.rs26
-rw-r--r--library/std/src/process/tests.rs94
-rw-r--r--library/std/src/rt.rs6
-rw-r--r--library/std/src/sync/lazy_lock.rs10
-rw-r--r--library/std/src/sync/lazy_lock/tests.rs6
-rw-r--r--library/std/src/sync/mod.rs3
-rw-r--r--library/std/src/sync/mpmc/utils.rs2
-rw-r--r--library/std/src/sync/mutex/tests.rs2
-rw-r--r--library/std/src/sync/once_lock.rs17
-rw-r--r--library/std/src/sync/remutex.rs (renamed from library/std/src/sys_common/remutex.rs)0
-rw-r--r--library/std/src/sync/remutex/tests.rs (renamed from library/std/src/sys_common/remutex/tests.rs)2
-rw-r--r--library/std/src/sync/rwlock/tests.rs4
-rw-r--r--library/std/src/sys/itron/thread.rs25
-rw-r--r--library/std/src/sys/sgx/mod.rs2
-rw-r--r--library/std/src/sys/sgx/thread.rs8
-rw-r--r--library/std/src/sys/sgx/thread_parker.rs107
-rw-r--r--library/std/src/sys/sgx/thread_parking.rs23
-rw-r--r--library/std/src/sys/unix/android.rs4
-rw-r--r--library/std/src/sys/unix/fs.rs4
-rw-r--r--library/std/src/sys/unix/kernel_copy.rs4
-rw-r--r--library/std/src/sys/unix/mod.rs19
-rw-r--r--library/std/src/sys/unix/net.rs2
-rw-r--r--library/std/src/sys/unix/process/process_common.rs67
-rw-r--r--library/std/src/sys/unix/stack_overflow.rs4
-rw-r--r--library/std/src/sys/unix/thread.rs8
-rw-r--r--library/std/src/sys/unix/thread_parker/netbsd.rs113
-rw-r--r--library/std/src/sys/unix/thread_parking/darwin.rs (renamed from library/std/src/sys/unix/thread_parker/darwin.rs)2
-rw-r--r--library/std/src/sys/unix/thread_parking/mod.rs (renamed from library/std/src/sys/unix/thread_parker/mod.rs)2
-rw-r--r--library/std/src/sys/unix/thread_parking/netbsd.rs52
-rw-r--r--library/std/src/sys/unix/thread_parking/pthread.rs (renamed from library/std/src/sys/unix/thread_parker/pthread.rs)8
-rw-r--r--library/std/src/sys/unix/weak.rs53
-rw-r--r--library/std/src/sys/unsupported/mod.rs1
-rw-r--r--library/std/src/sys/unsupported/once.rs89
-rw-r--r--library/std/src/sys/wasi/mod.rs2
-rw-r--r--library/std/src/sys/wasm/mod.rs2
-rw-r--r--library/std/src/sys/windows/mod.rs2
-rw-r--r--library/std/src/sys/windows/thread_parking.rs (renamed from library/std/src/sys/windows/thread_parker.rs)2
-rw-r--r--library/std/src/sys_common/backtrace.rs6
-rw-r--r--library/std/src/sys_common/io.rs3
-rw-r--r--library/std/src/sys_common/mod.rs3
-rw-r--r--library/std/src/sys_common/once/mod.rs27
-rw-r--r--library/std/src/sys_common/once/queue.rs (renamed from library/std/src/sys_common/once/generic.rs)0
-rw-r--r--library/std/src/sys_common/process.rs11
-rw-r--r--library/std/src/sys_common/thread_local_key.rs25
-rw-r--r--library/std/src/sys_common/thread_parking/futex.rs (renamed from library/std/src/sys_common/thread_parker/futex.rs)2
-rw-r--r--library/std/src/sys_common/thread_parking/generic.rs (renamed from library/std/src/sys_common/thread_parker/generic.rs)2
-rw-r--r--library/std/src/sys_common/thread_parking/id.rs108
-rw-r--r--library/std/src/sys_common/thread_parking/mod.rs (renamed from library/std/src/sys_common/thread_parker/mod.rs)10
-rw-r--r--library/std/src/sys_common/thread_parking/wait_flag.rs (renamed from library/std/src/sys_common/thread_parker/wait_flag.rs)2
-rw-r--r--library/std/src/thread/local.rs23
-rw-r--r--library/std/src/thread/local/tests.rs22
-rw-r--r--library/std/src/thread/mod.rs4
67 files changed, 736 insertions, 450 deletions
diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs
index 61c1ff578b2..c5a5991cc81 100644
--- a/library/std/src/alloc.rs
+++ b/library/std/src/alloc.rs
@@ -338,7 +338,7 @@ fn default_alloc_error_hook(layout: Layout) {
 
     #[allow(unused_unsafe)]
     if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
-        panic!("memory allocation of {} bytes failed\n", layout.size());
+        panic!("memory allocation of {} bytes failed", layout.size());
     } else {
         rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
     }
diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs
index 9cb74f951dd..7543ffadd41 100644
--- a/library/std/src/backtrace.rs
+++ b/library/std/src/backtrace.rs
@@ -23,10 +23,10 @@
 //!
 //! ## Platform support
 //!
-//! Not all platforms that libstd compiles for support capturing backtraces.
-//! Some platforms simply do nothing when capturing a backtrace. To check
-//! whether the platform supports capturing backtraces you can consult the
-//! `BacktraceStatus` enum as a result of `Backtrace::status`.
+//! Not all platforms that std compiles for support capturing backtraces. Some
+//! platforms simply do nothing when capturing a backtrace. To check whether the
+//! platform supports capturing backtraces you can consult the `BacktraceStatus`
+//! enum as a result of `Backtrace::status`.
 //!
 //! Like above with accuracy platform support is done on a best effort basis.
 //! Sometimes libraries might not be available at runtime or something may go
diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs
index 65634f2063f..6b89518e2e2 100644
--- a/library/std/src/collections/hash/map/tests.rs
+++ b/library/std/src/collections/hash/map/tests.rs
@@ -3,7 +3,8 @@ use super::HashMap;
 use super::RandomState;
 use crate::assert_matches::assert_matches;
 use crate::cell::RefCell;
-use rand::{thread_rng, Rng};
+use crate::test_helpers::test_rng;
+use rand::Rng;
 use realstd::collections::TryReserveErrorKind::*;
 
 // https://github.com/rust-lang/rust/issues/62301
@@ -710,16 +711,16 @@ fn test_entry_take_doesnt_corrupt() {
     }
 
     let mut m = HashMap::new();
-    let mut rng = thread_rng();
+    let mut rng = test_rng();
 
     // Populate the map with some items.
     for _ in 0..50 {
-        let x = rng.gen_range(-10, 10);
+        let x = rng.gen_range(-10..10);
         m.insert(x, ());
     }
 
     for _ in 0..1000 {
-        let x = rng.gen_range(-10, 10);
+        let x = rng.gen_range(-10..10);
         match m.entry(x) {
             Vacant(_) => {}
             Occupied(e) => {
diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs
index cee884145c7..b59f89d321c 100644
--- a/library/std/src/collections/hash/set.rs
+++ b/library/std/src/collections/hash/set.rs
@@ -317,7 +317,7 @@ impl<T, S> HashSet<T, S> {
     ///
     /// let mut set = HashSet::from([1, 2, 3, 4, 5, 6]);
     /// set.retain(|&k| k % 2 == 0);
-    /// assert_eq!(set.len(), 3);
+    /// assert_eq!(set, HashSet::from([2, 4, 6]));
     /// ```
     ///
     /// # Performance
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index b385ebde439..eb582be012b 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -10,7 +10,7 @@ use crate::sys_common::io::test::{tmpdir, TempDir};
 use crate::thread;
 use crate::time::{Duration, Instant};
 
-use rand::{rngs::StdRng, RngCore, SeedableRng};
+use rand::RngCore;
 
 #[cfg(unix)]
 use crate::os::unix::fs::symlink as symlink_dir;
@@ -1181,7 +1181,7 @@ fn _assert_send_sync() {
 #[test]
 fn binary_file() {
     let mut bytes = [0; 1024];
-    StdRng::from_entropy().fill_bytes(&mut bytes);
+    crate::test_helpers::test_rng().fill_bytes(&mut bytes);
 
     let tmpdir = tmpdir();
 
@@ -1194,7 +1194,7 @@ fn binary_file() {
 #[test]
 fn write_then_read() {
     let mut bytes = [0; 1024];
-    StdRng::from_entropy().fill_bytes(&mut bytes);
+    crate::test_helpers::test_rng().fill_bytes(&mut bytes);
 
     let tmpdir = tmpdir();
 
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
index 781ae03ad45..601c01c2128 100644
--- a/library/std/src/io/error/repr_bitpacked.rs
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -166,7 +166,7 @@ impl Repr {
         // `new_unchecked` is safe.
         let res = Self(unsafe { NonNull::new_unchecked(tagged) }, PhantomData);
         // quickly smoke-check we encoded the right thing (This generally will
-        // only run in libstd's tests, unless the user uses -Zbuild-std)
+        // only run in std's tests, unless the user uses -Zbuild-std)
         debug_assert!(matches!(res.data(), ErrorData::Custom(_)), "repr(custom) encoding failed");
         res
     }
@@ -177,7 +177,7 @@ impl Repr {
         // Safety: `TAG_OS` is not zero, so the result of the `|` is not 0.
         let res = Self(unsafe { NonNull::new_unchecked(ptr::invalid_mut(utagged)) }, PhantomData);
         // quickly smoke-check we encoded the right thing (This generally will
-        // only run in libstd's tests, unless the user uses -Zbuild-std)
+        // only run in std's tests, unless the user uses -Zbuild-std)
         debug_assert!(
             matches!(res.data(), ErrorData::Os(c) if c == code),
             "repr(os) encoding failed for {code}"
@@ -191,7 +191,7 @@ impl Repr {
         // Safety: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0.
         let res = Self(unsafe { NonNull::new_unchecked(ptr::invalid_mut(utagged)) }, PhantomData);
         // quickly smoke-check we encoded the right thing (This generally will
-        // only run in libstd's tests, unless the user uses -Zbuild-std)
+        // only run in std's tests, unless the user uses -Zbuild-std)
         debug_assert!(
             matches!(res.data(), ErrorData::Simple(k) if k == kind),
             "repr(simple) encoding failed {:?}",
@@ -348,7 +348,7 @@ fn kind_from_prim(ek: u32) -> Option<ErrorKind> {
 // that our encoding relies on for correctness and soundness. (Some of these are
 // a bit overly thorough/cautious, admittedly)
 //
-// If any of these are hit on a platform that libstd supports, we should likely
+// If any of these are hit on a platform that std supports, we should likely
 // just use `repr_unpacked.rs` there instead (unless the fix is easy).
 macro_rules! static_assert {
     ($condition:expr) => {
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 23a13523fc2..de528e85368 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -2137,8 +2137,10 @@ pub trait BufRead: Read {
     }
 
     /// Read all bytes until a newline (the `0xA` byte) is reached, and append
-    /// them to the provided buffer. You do not need to clear the buffer before
-    /// appending.
+    /// them to the provided `String` buffer.
+    ///
+    /// Previous content of the buffer will be preserved. To avoid appending to
+    /// the buffer, you need to [`clear`] it first.
     ///
     /// This function will read bytes from the underlying stream until the
     /// newline delimiter (the `0xA` byte) or EOF is found. Once found, all bytes
@@ -2151,9 +2153,11 @@ pub trait BufRead: Read {
     ///
     /// This function is blocking and should be used carefully: it is possible for
     /// an attacker to continuously send bytes without ever sending a newline
-    /// or EOF.
+    /// or EOF. You can use [`take`] to limit the maximum number of bytes read.
     ///
     /// [`Ok(0)`]: Ok
+    /// [`clear`]: String::clear
+    /// [`take`]: crate::io::Read::take
     ///
     /// # Errors
     ///
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 1141a957d87..14bfef4c7aa 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -10,9 +10,8 @@ use crate::fmt;
 use crate::fs::File;
 use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines};
 use crate::sync::atomic::{AtomicBool, Ordering};
-use crate::sync::{Arc, Mutex, MutexGuard, OnceLock};
+use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantMutex, ReentrantMutexGuard};
 use crate::sys::stdio;
-use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
 
 type LocalStream = Arc<Mutex<Vec<u8>>>;
 
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 65d4c3c891e..a7e13f5b866 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -14,7 +14,7 @@
 //! # How to read this documentation
 //!
 //! If you already know the name of what you are looking for, the fastest way to
-//! find it is to use the <a href="#" onclick="focusSearchBar();">search
+//! find it is to use the <a href="#" onclick="window.searchState.focus();">search
 //! bar</a> at the top of the page.
 //!
 //! Otherwise, you may want to jump to one of these useful sections:
@@ -202,7 +202,7 @@
     no_global_oom_handling,
     not(no_global_oom_handling)
 ))]
-// To run libstd tests without x.py without ending up with two copies of libstd, Miri needs to be
+// To run std tests without x.py without ending up with two copies of std, Miri needs to be
 // able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
 // rustc itself never sets the feature, so this line has no affect there.
 #![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
@@ -532,7 +532,7 @@ pub mod process;
 pub mod sync;
 pub mod time;
 
-// Pull in `std_float` crate  into libstd. The contents of
+// Pull in `std_float` crate  into std. The contents of
 // `std_float` are in a different repository: rust-lang/portable-simd.
 #[path = "../../portable-simd/crates/std_float/src/lib.rs"]
 #[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
@@ -602,7 +602,7 @@ mod personality;
 #[allow(dead_code, unused_attributes, fuzzy_provenance_casts)]
 mod backtrace_rs;
 
-// Re-export macros defined in libcore.
+// Re-export macros defined in core.
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated, deprecated_in_future)]
 pub use core::{
@@ -610,7 +610,7 @@ pub use core::{
     unimplemented, unreachable, write, writeln,
 };
 
-// Re-export built-in macros defined through libcore.
+// Re-export built-in macros defined through core.
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
 #[allow(deprecated)]
 pub use core::{
@@ -652,3 +652,30 @@ mod sealed {
     #[unstable(feature = "sealed", issue = "none")]
     pub trait Sealed {}
 }
+
+#[cfg(test)]
+#[allow(dead_code)] // Not used in all configurations.
+pub(crate) mod test_helpers {
+    /// Test-only replacement for `rand::thread_rng()`, which is unusable for
+    /// us, as we want to allow running stdlib tests on tier-3 targets which may
+    /// not have `getrandom` support.
+    ///
+    /// Does a bit of a song and dance to ensure that the seed is different on
+    /// each call (as some tests sadly rely on this), but doesn't try that hard.
+    ///
+    /// This is duplicated in the `core`, `alloc` test suites (as well as
+    /// `std`'s integration tests), but figuring out a mechanism to share these
+    /// seems far more painful than copy-pasting a 7 line function a couple
+    /// times, given that even under a perma-unstable feature, I don't think we
+    /// want to expose types from `rand` from `std`.
+    #[track_caller]
+    pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
+        use core::hash::{BuildHasher, Hash, Hasher};
+        let mut hasher = crate::collections::hash_map::RandomState::new().build_hasher();
+        core::panic::Location::caller().hash(&mut hasher);
+        let hc64 = hasher.finish();
+        let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
+        let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
+        rand::SeedableRng::from_seed(seed)
+    }
+}
diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs
index 6e4ba1404e5..fcc5cfafd80 100644
--- a/library/std/src/macros.rs
+++ b/library/std/src/macros.rs
@@ -3,6 +3,7 @@
 //! This module contains a set of macros which are exported from the standard
 //! library. Each macro is available for use when linking against the standard
 //! library.
+// ignore-tidy-dbg
 
 #[doc = include_str!("../../core/src/macros/panic.md")]
 #[macro_export]
diff --git a/library/std/src/net/ip_addr.rs b/library/std/src/net/ip_addr.rs
index 5453853e138..07f08c1b586 100644
--- a/library/std/src/net/ip_addr.rs
+++ b/library/std/src/net/ip_addr.rs
@@ -1195,6 +1195,9 @@ impl Ipv6Addr {
 
     /// An IPv6 address representing localhost: `::1`.
     ///
+    /// This corresponds to constant `IN6ADDR_LOOPBACK_INIT` or `in6addr_loopback` in other
+    /// languages.
+    ///
     /// # Examples
     ///
     /// ```
@@ -1203,11 +1206,15 @@ impl Ipv6Addr {
     /// let addr = Ipv6Addr::LOCALHOST;
     /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
     /// ```
+    #[doc(alias = "IN6ADDR_LOOPBACK_INIT")]
+    #[doc(alias = "in6addr_loopback")]
     #[stable(feature = "ip_constructors", since = "1.30.0")]
     pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
 
     /// An IPv6 address representing the unspecified address: `::`
     ///
+    /// This corresponds to constant `IN6ADDR_ANY_INIT` or `in6addr_any` in other languages.
+    ///
     /// # Examples
     ///
     /// ```
@@ -1216,6 +1223,8 @@ impl Ipv6Addr {
     /// let addr = Ipv6Addr::UNSPECIFIED;
     /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
     /// ```
+    #[doc(alias = "IN6ADDR_ANY_INIT")]
+    #[doc(alias = "in6addr_any")]
     #[stable(feature = "ip_constructors", since = "1.30.0")]
     pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
 
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index c4f022de021..9fa8f5702a8 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -114,6 +114,9 @@ where
 /// aborting the process as well. This function *only* catches unwinding panics,
 /// not those that abort the process.
 ///
+/// Note that if a custom panic hook has been set, it will be invoked before
+/// the panic is caught, before unwinding.
+///
 /// Also note that unwinding into Rust code with a foreign exception (e.g.
 /// an exception thrown from C++ code) is undefined behavior.
 ///
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 1039835bbbd..b30dd8eecd8 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -517,7 +517,7 @@ pub fn panicking() -> bool {
     !panic_count::count_is_zero()
 }
 
-/// Entry point of panics from the libcore crate (`panic_impl` lang item).
+/// Entry point of panics from the core crate (`panic_impl` lang item).
 #[cfg(not(test))]
 #[panic_handler]
 pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
@@ -699,7 +699,11 @@ fn rust_panic_with_hook(
         // have limited options. Currently our preference is to
         // just abort. In the future we may consider resuming
         // unwinding or otherwise exiting the thread cleanly.
-        rtprintpanic!("thread panicked while panicking. aborting.\n");
+        if !can_unwind {
+            rtprintpanic!("thread caused non-unwinding panic. aborting.\n");
+        } else {
+            rtprintpanic!("thread panicked while panicking. aborting.\n");
+        }
         crate::sys::abort_internal();
     }
 
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index a835b855ddd..82d68369312 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -271,7 +271,7 @@ pub const MAIN_SEPARATOR: char = crate::sys::path::MAIN_SEP;
 /// The primary separator of path components for the current platform.
 ///
 /// For example, `/` on Unix and `\` on Windows.
-#[unstable(feature = "main_separator_str", issue = "94071")]
+#[stable(feature = "main_separator_str", since = "CURRENT_RUSTC_VERSION")]
 pub const MAIN_SEPARATOR_STR: &str = crate::sys::path::MAIN_SEP_STR;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -306,7 +306,7 @@ unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
     // This casts are safe as OsStr is internally a wrapper around [u8] on all
     // platforms.
     //
-    // Note that currently this relies on the special knowledge that libstd has;
+    // Note that currently this relies on the special knowledge that std has;
     // these types are single-element structs but are not marked
     // repr(transparent) or repr(C) which would make these casts not allowable
     // outside std.
@@ -1246,6 +1246,9 @@ impl PathBuf {
     ///   and `path` is not empty, the new path is normalized: all references
     ///   to `.` and `..` are removed.
     ///
+    /// Consider using [`Path::join`] if you need a new `PathBuf` instead of
+    /// using this function on a cloned `PathBuf`.
+    ///
     /// # Examples
     ///
     /// Pushing a relative path extends the existing path:
@@ -1411,7 +1414,8 @@ impl PathBuf {
         self.push(file_name);
     }
 
-    /// Updates [`self.extension`] to `extension`.
+    /// Updates [`self.extension`] to `Some(extension)` or to `None` if
+    /// `extension` is empty.
     ///
     /// Returns `false` and does nothing if [`self.file_name`] is [`None`],
     /// returns `true` and updates the extension otherwise.
@@ -1419,6 +1423,20 @@ impl PathBuf {
     /// If [`self.extension`] is [`None`], the extension is added; otherwise
     /// it is replaced.
     ///
+    /// If `extension` is the empty string, [`self.extension`] will be [`None`]
+    /// afterwards, not `Some("")`.
+    ///
+    /// # Caveats
+    ///
+    /// The new `extension` may contain dots and will be used in its entirety,
+    /// but only the part after the final dot will be reflected in
+    /// [`self.extension`].
+    ///
+    /// If the file stem contains internal dots and `extension` is empty, part
+    /// of the old file stem will be considered the new [`self.extension`].
+    ///
+    /// See the examples below.
+    ///
     /// [`self.file_name`]: Path::file_name
     /// [`self.extension`]: Path::extension
     ///
@@ -1432,8 +1450,20 @@ impl PathBuf {
     /// p.set_extension("force");
     /// assert_eq!(Path::new("/feel/the.force"), p.as_path());
     ///
-    /// p.set_extension("dark_side");
-    /// assert_eq!(Path::new("/feel/the.dark_side"), p.as_path());
+    /// p.set_extension("dark.side");
+    /// assert_eq!(Path::new("/feel/the.dark.side"), p.as_path());
+    ///
+    /// p.set_extension("cookie");
+    /// assert_eq!(Path::new("/feel/the.dark.cookie"), p.as_path());
+    ///
+    /// p.set_extension("");
+    /// assert_eq!(Path::new("/feel/the.dark"), p.as_path());
+    ///
+    /// p.set_extension("");
+    /// assert_eq!(Path::new("/feel/the"), p.as_path());
+    ///
+    /// p.set_extension("");
+    /// assert_eq!(Path::new("/feel/the"), p.as_path());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
@@ -2039,12 +2069,12 @@ impl Path {
     /// #![feature(path_as_mut_os_str)]
     /// use std::path::{Path, PathBuf};
     ///
-    /// let mut path = PathBuf::from("/Foo.TXT").into_boxed_path();
+    /// let mut path = PathBuf::from("Foo.TXT");
     ///
-    /// assert_ne!(&*path, Path::new("/foo.txt"));
+    /// assert_ne!(path, Path::new("foo.txt"));
     ///
     /// path.as_mut_os_str().make_ascii_lowercase();
-    /// assert_eq!(&*path, Path::new("/foo.txt"));
+    /// assert_eq!(path, Path::new("foo.txt"));
     /// ```
     #[unstable(feature = "path_as_mut_os_str", issue = "105021")]
     #[must_use]
diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs
index a5a798078eb..2aefd7c513d 100644
--- a/library/std/src/prelude/v1.rs
+++ b/library/std/src/prelude/v1.rs
@@ -59,14 +59,12 @@ pub use core::prelude::v1::{RustcDecodable, RustcEncodable};
 
 // Do not `doc(no_inline)` so that they become doc items on their own
 // (no public module for them to be re-exported from).
-#[cfg(not(bootstrap))]
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-pub use core::prelude::v1::alloc_error_handler;
-#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-pub use core::prelude::v1::{bench, derive, global_allocator, test, test_case};
+pub use core::prelude::v1::{
+    alloc_error_handler, bench, derive, global_allocator, test, test_case,
+};
 
 #[unstable(feature = "derive_const", issue = "none")]
-#[cfg(not(bootstrap))]
 pub use core::prelude::v1::derive_const;
 
 // Do not `doc(no_inline)` either.
@@ -91,7 +89,6 @@ pub use core::prelude::v1::cfg_eval;
     issue = "23416",
     reason = "placeholder syntax for type ascription"
 )]
-#[cfg(not(bootstrap))]
 pub use core::prelude::v1::type_ascribe;
 
 // The file so far is equivalent to src/libcore/prelude/v1.rs,
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 17aff342c15..62ce2cb33dc 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1038,6 +1038,15 @@ impl fmt::Debug for Command {
     /// Format the program and arguments of a Command for display. Any
     /// non-utf8 data is lossily converted using the utf8 replacement
     /// character.
+    ///
+    /// The default format approximates a shell invocation of the program along with its
+    /// arguments. It does not include most of the other command properties. The output is not guaranteed to work
+    /// (e.g. due to lack of shell-escaping or differences in path resolution)
+    /// On some platforms you can use [the alternate syntax] to show more fields.
+    ///
+    /// Note that the debug implementation is platform-specific.
+    ///
+    /// [the alternate syntax]: fmt#sign0
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.inner.fmt(f)
     }
@@ -2155,18 +2164,11 @@ pub fn id() -> u32 {
 /// to provide similar functionality.
 #[cfg_attr(not(test), lang = "termination")]
 #[stable(feature = "termination_trait_lib", since = "1.61.0")]
-#[rustc_on_unimplemented(
-    on(
-        all(not(bootstrap), cause = "MainFunctionType"),
-        message = "`main` has invalid return type `{Self}`",
-        label = "`main` can only return types that implement `{Termination}`"
-    ),
-    on(
-        bootstrap,
-        message = "`main` has invalid return type `{Self}`",
-        label = "`main` can only return types that implement `{Termination}`"
-    )
-)]
+#[rustc_on_unimplemented(on(
+    cause = "MainFunctionType",
+    message = "`main` has invalid return type `{Self}`",
+    label = "`main` can only return types that implement `{Termination}`"
+))]
 pub trait Termination {
     /// Is called to get the representation of the value as status code.
     /// This status code is returned to the operating system.
diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs
index 955ad68916c..b4f6cc2daba 100644
--- a/library/std/src/process/tests.rs
+++ b/library/std/src/process/tests.rs
@@ -417,6 +417,100 @@ fn env_empty() {
     assert!(p.is_ok());
 }
 
+#[test]
+#[cfg(not(windows))]
+#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)]
+fn main() {
+    const PIDFD: &'static str =
+        if cfg!(target_os = "linux") { "    create_pidfd: false,\n" } else { "" };
+
+    let mut command = Command::new("some-boring-name");
+
+    assert_eq!(format!("{command:?}"), format!(r#""some-boring-name""#));
+
+    assert_eq!(
+        format!("{command:#?}"),
+        format!(
+            r#"Command {{
+    program: "some-boring-name",
+    args: [
+        "some-boring-name",
+    ],
+{PIDFD}}}"#
+        )
+    );
+
+    command.args(&["1", "2", "3"]);
+
+    assert_eq!(format!("{command:?}"), format!(r#""some-boring-name" "1" "2" "3""#));
+
+    assert_eq!(
+        format!("{command:#?}"),
+        format!(
+            r#"Command {{
+    program: "some-boring-name",
+    args: [
+        "some-boring-name",
+        "1",
+        "2",
+        "3",
+    ],
+{PIDFD}}}"#
+        )
+    );
+
+    crate::os::unix::process::CommandExt::arg0(&mut command, "exciting-name");
+
+    assert_eq!(
+        format!("{command:?}"),
+        format!(r#"["some-boring-name"] "exciting-name" "1" "2" "3""#)
+    );
+
+    assert_eq!(
+        format!("{command:#?}"),
+        format!(
+            r#"Command {{
+    program: "some-boring-name",
+    args: [
+        "exciting-name",
+        "1",
+        "2",
+        "3",
+    ],
+{PIDFD}}}"#
+        )
+    );
+
+    let mut command_with_env_and_cwd = Command::new("boring-name");
+    command_with_env_and_cwd.current_dir("/some/path").env("FOO", "bar");
+    assert_eq!(
+        format!("{command_with_env_and_cwd:?}"),
+        r#"cd "/some/path" && FOO="bar" "boring-name""#
+    );
+    assert_eq!(
+        format!("{command_with_env_and_cwd:#?}"),
+        format!(
+            r#"Command {{
+    program: "boring-name",
+    args: [
+        "boring-name",
+    ],
+    env: CommandEnv {{
+        clear: false,
+        vars: {{
+            "FOO": Some(
+                "bar",
+            ),
+        }},
+    }},
+    cwd: Some(
+        "/some/path",
+    ),
+{PIDFD}}}"#
+        )
+    );
+}
+
 // See issue #91991
 #[test]
 #[cfg(windows)]
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index 9c2f0c1dd3e..f1eeb75be7c 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -139,9 +139,9 @@ fn lang_start_internal(
     // mechanism itself.
     //
     // There are a couple of instances where unwinding can begin. First is inside of the
-    // `rt::init`, `rt::cleanup` and similar functions controlled by libstd. In those instances a
-    // panic is a libstd implementation bug. A quite likely one too, as there isn't any way to
-    // prevent libstd from accidentally introducing a panic to these functions. Another is from
+    // `rt::init`, `rt::cleanup` and similar functions controlled by bstd. In those instances a
+    // panic is a std implementation bug. A quite likely one too, as there isn't any way to
+    // 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)?;
diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs
index c8d3289ca4a..4a15305301d 100644
--- a/library/std/src/sync/lazy_lock.rs
+++ b/library/std/src/sync/lazy_lock.rs
@@ -46,17 +46,15 @@ pub struct LazyLock<T, F = fn() -> T> {
     cell: OnceLock<T>,
     init: Cell<Option<F>>,
 }
-
-impl<T, F> LazyLock<T, F> {
+impl<T, F: FnOnce() -> T> LazyLock<T, F> {
     /// Creates a new lazy value with the given initializing
     /// function.
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub const fn new(f: F) -> LazyLock<T, F> {
         LazyLock { cell: OnceLock::new(), init: Cell::new(Some(f)) }
     }
-}
 
-impl<T, F: FnOnce() -> T> LazyLock<T, F> {
     /// Forces the evaluation of this lazy value and
     /// returns a reference to result. This is equivalent
     /// to the `Deref` impl, but is explicit.
@@ -73,6 +71,7 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
     /// assert_eq!(LazyLock::force(&lazy), &92);
     /// assert_eq!(&*lazy, &92);
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn force(this: &LazyLock<T, F>) -> &T {
         this.cell.get_or_init(|| match this.init.take() {
@@ -85,6 +84,8 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
     type Target = T;
+
+    #[inline]
     fn deref(&self) -> &T {
         LazyLock::force(self)
     }
@@ -93,6 +94,7 @@ impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T: Default> Default for LazyLock<T> {
     /// Creates a new lazy value using `Default` as the initializing function.
+    #[inline]
     fn default() -> LazyLock<T> {
         LazyLock::new(T::default)
     }
diff --git a/library/std/src/sync/lazy_lock/tests.rs b/library/std/src/sync/lazy_lock/tests.rs
index f11b66bfca5..a5d4e25c596 100644
--- a/library/std/src/sync/lazy_lock/tests.rs
+++ b/library/std/src/sync/lazy_lock/tests.rs
@@ -136,6 +136,12 @@ fn sync_lazy_poisoning() {
     }
 }
 
+// Check that we can infer `T` from closure's type.
+#[test]
+fn lazy_type_inference() {
+    let _ = LazyCell::new(|| ());
+}
+
 #[test]
 fn is_sync_send() {
     fn assert_traits<T: Send + Sync>() {}
diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs
index 4fee8d3e92f..ba20bab87a4 100644
--- a/library/std/src/sync/mod.rs
+++ b/library/std/src/sync/mod.rs
@@ -177,6 +177,8 @@ pub use self::lazy_lock::LazyLock;
 #[unstable(feature = "once_cell", issue = "74465")]
 pub use self::once_lock::OnceLock;
 
+pub(crate) use self::remutex::{ReentrantMutex, ReentrantMutexGuard};
+
 pub mod mpsc;
 
 mod barrier;
@@ -187,4 +189,5 @@ mod mutex;
 mod once;
 mod once_lock;
 mod poison;
+mod remutex;
 mod rwlock;
diff --git a/library/std/src/sync/mpmc/utils.rs b/library/std/src/sync/mpmc/utils.rs
index d0904b4b94c..e030c55ce8f 100644
--- a/library/std/src/sync/mpmc/utils.rs
+++ b/library/std/src/sync/mpmc/utils.rs
@@ -136,7 +136,7 @@ impl Backoff {
         }
     }
 
-    /// Returns `true` if exponential backoff has completed and blocking the thread is advised.
+    /// Returns `true` if quadratic backoff has completed and blocking the thread is advised.
     #[inline]
     pub fn is_completed(&self) -> bool {
         self.step.get() > YIELD_LIMIT
diff --git a/library/std/src/sync/mutex/tests.rs b/library/std/src/sync/mutex/tests.rs
index 93900566f11..1786a3c09ff 100644
--- a/library/std/src/sync/mutex/tests.rs
+++ b/library/std/src/sync/mutex/tests.rs
@@ -181,7 +181,7 @@ fn test_mutex_arc_poison() {
     let arc2 = arc.clone();
     let _ = thread::spawn(move || {
         let lock = arc2.lock().unwrap();
-        assert_eq!(*lock, 2);
+        assert_eq!(*lock, 2); // deliberate assertion failure to poison the mutex
     })
     .join();
     assert!(arc.lock().is_err());
diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs
index 16d1fd2a576..ed339ca5df6 100644
--- a/library/std/src/sync/once_lock.rs
+++ b/library/std/src/sync/once_lock.rs
@@ -61,8 +61,9 @@ pub struct OnceLock<T> {
 
 impl<T> OnceLock<T> {
     /// Creates a new empty cell.
-    #[unstable(feature = "once_cell", issue = "74465")]
+    #[inline]
     #[must_use]
+    #[unstable(feature = "once_cell", issue = "74465")]
     pub const fn new() -> OnceLock<T> {
         OnceLock {
             once: Once::new(),
@@ -75,6 +76,7 @@ impl<T> OnceLock<T> {
     ///
     /// Returns `None` if the cell is empty, or being initialized. This
     /// method never blocks.
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn get(&self) -> Option<&T> {
         if self.is_initialized() {
@@ -88,6 +90,7 @@ impl<T> OnceLock<T> {
     /// Gets the mutable reference to the underlying value.
     ///
     /// Returns `None` if the cell is empty. This method never blocks.
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn get_mut(&mut self) -> Option<&mut T> {
         if self.is_initialized() {
@@ -125,6 +128,7 @@ impl<T> OnceLock<T> {
     ///     assert_eq!(CELL.get(), Some(&92));
     /// }
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn set(&self, value: T) -> Result<(), T> {
         let mut value = Some(value);
@@ -164,6 +168,7 @@ impl<T> OnceLock<T> {
     /// let value = cell.get_or_init(|| unreachable!());
     /// assert_eq!(value, &92);
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn get_or_init<F>(&self, f: F) -> &T
     where
@@ -203,6 +208,7 @@ impl<T> OnceLock<T> {
     /// assert_eq!(value, Ok(&92));
     /// assert_eq!(cell.get(), Some(&92))
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
     where
@@ -241,6 +247,7 @@ impl<T> OnceLock<T> {
     /// cell.set("hello".to_string()).unwrap();
     /// assert_eq!(cell.into_inner(), Some("hello".to_string()));
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn into_inner(mut self) -> Option<T> {
         self.take()
@@ -267,6 +274,7 @@ impl<T> OnceLock<T> {
     /// assert_eq!(cell.take(), Some("hello".to_string()));
     /// assert_eq!(cell.get(), None);
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn take(&mut self) -> Option<T> {
         if self.is_initialized() {
@@ -315,6 +323,7 @@ impl<T> OnceLock<T> {
     /// # Safety
     ///
     /// The value must be initialized
+    #[inline]
     unsafe fn get_unchecked(&self) -> &T {
         debug_assert!(self.is_initialized());
         (&*self.value.get()).assume_init_ref()
@@ -323,6 +332,7 @@ impl<T> OnceLock<T> {
     /// # Safety
     ///
     /// The value must be initialized
+    #[inline]
     unsafe fn get_unchecked_mut(&mut self) -> &mut T {
         debug_assert!(self.is_initialized());
         (&mut *self.value.get()).assume_init_mut()
@@ -360,6 +370,7 @@ impl<T> const Default for OnceLock<T> {
     ///     assert_eq!(OnceLock::<()>::new(), OnceLock::default());
     /// }
     /// ```
+    #[inline]
     fn default() -> OnceLock<T> {
         OnceLock::new()
     }
@@ -377,6 +388,7 @@ impl<T: fmt::Debug> fmt::Debug for OnceLock<T> {
 
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T: Clone> Clone for OnceLock<T> {
+    #[inline]
     fn clone(&self) -> OnceLock<T> {
         let cell = Self::new();
         if let Some(value) = self.get() {
@@ -408,6 +420,7 @@ impl<T> From<T> for OnceLock<T> {
     /// Ok(())
     /// # }
     /// ```
+    #[inline]
     fn from(value: T) -> Self {
         let cell = Self::new();
         match cell.set(value) {
@@ -419,6 +432,7 @@ impl<T> From<T> for OnceLock<T> {
 
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T: PartialEq> PartialEq for OnceLock<T> {
+    #[inline]
     fn eq(&self, other: &OnceLock<T>) -> bool {
         self.get() == other.get()
     }
@@ -429,6 +443,7 @@ impl<T: Eq> Eq for OnceLock<T> {}
 
 #[unstable(feature = "once_cell", issue = "74465")]
 unsafe impl<#[may_dangle] T> Drop for OnceLock<T> {
+    #[inline]
     fn drop(&mut self) {
         if self.is_initialized() {
             // SAFETY: The cell is initialized and being dropped, so it can't
diff --git a/library/std/src/sys_common/remutex.rs b/library/std/src/sync/remutex.rs
index 4c054da6471..4c054da6471 100644
--- a/library/std/src/sys_common/remutex.rs
+++ b/library/std/src/sync/remutex.rs
diff --git a/library/std/src/sys_common/remutex/tests.rs b/library/std/src/sync/remutex/tests.rs
index 8e97ce11c34..fc553081d42 100644
--- a/library/std/src/sys_common/remutex/tests.rs
+++ b/library/std/src/sync/remutex/tests.rs
@@ -1,6 +1,6 @@
+use super::{ReentrantMutex, ReentrantMutexGuard};
 use crate::cell::RefCell;
 use crate::sync::Arc;
-use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
 use crate::thread;
 
 #[test]
diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs
index b5b3ad9898e..1a9d3d3f12f 100644
--- a/library/std/src/sync/rwlock/tests.rs
+++ b/library/std/src/sync/rwlock/tests.rs
@@ -2,7 +2,7 @@ use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sync::mpsc::channel;
 use crate::sync::{Arc, RwLock, RwLockReadGuard, TryLockError};
 use crate::thread;
-use rand::{self, Rng};
+use rand::Rng;
 
 #[derive(Eq, PartialEq, Debug)]
 struct NonCopy(i32);
@@ -28,7 +28,7 @@ fn frob() {
         let tx = tx.clone();
         let r = r.clone();
         thread::spawn(move || {
-            let mut rng = rand::thread_rng();
+            let mut rng = crate::test_helpers::test_rng();
             for _ in 0..M {
                 if rng.gen_bool(1.0 / (N as f64)) {
                     drop(r.write().unwrap());
diff --git a/library/std/src/sys/itron/thread.rs b/library/std/src/sys/itron/thread.rs
index c2b36680872..535703be33f 100644
--- a/library/std/src/sys/itron/thread.rs
+++ b/library/std/src/sys/itron/thread.rs
@@ -119,7 +119,7 @@ impl Thread {
 
             let old_lifecycle = inner
                 .lifecycle
-                .swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::Release);
+                .swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::AcqRel);
 
             match old_lifecycle {
                 LIFECYCLE_DETACHED => {
@@ -129,9 +129,9 @@ impl Thread {
 
                     // In this case, `*p_inner`'s ownership has been moved to
                     // us, and we are responsible for dropping it. The acquire
-                    // ordering is not necessary because the parent thread made
-                    // no memory access needing synchronization since the call
-                    // to `acre_tsk`.
+                    // ordering ensures that the swap operation that wrote
+                    // `LIFECYCLE_DETACHED` happens-before `Box::from_raw(
+                    // p_inner)`.
                     // Safety: See above.
                     let _ = unsafe { Box::from_raw(p_inner) };
 
@@ -151,6 +151,9 @@ impl Thread {
                     // Since the parent might drop `*inner` and terminate us as
                     // soon as it sees `JOIN_FINALIZE`, the release ordering
                     // must be used in the above `swap` call.
+                    //
+                    // To make the task referred to by `parent_tid` visible, we
+                    // must use the acquire ordering in the above `swap` call.
 
                     // [JOINING → JOIN_FINALIZE]
                     // Wake up the parent task.
@@ -218,11 +221,15 @@ impl Thread {
 
         let current_task = current_task as usize;
 
-        match inner.lifecycle.swap(current_task, Ordering::Acquire) {
+        match inner.lifecycle.swap(current_task, Ordering::AcqRel) {
             LIFECYCLE_INIT => {
                 // [INIT → JOINING]
                 // The child task will transition the state to `JOIN_FINALIZE`
                 // and wake us up.
+                //
+                // To make the task referred to by `current_task` visible from
+                // the child task's point of view, we must use the release
+                // ordering in the above `swap` call.
                 loop {
                     expect_success_aborting(unsafe { abi::slp_tsk() }, &"slp_tsk");
                     // To synchronize with the child task's memory accesses to
@@ -267,15 +274,15 @@ impl Drop for Thread {
         let inner = unsafe { self.p_inner.as_ref() };
 
         // Detach the thread.
-        match inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::Acquire) {
+        match inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::AcqRel) {
             LIFECYCLE_INIT => {
                 // [INIT → DETACHED]
                 // When the time comes, the child will figure out that no
                 // one will ever join it.
                 // The ownership of `*p_inner` is moved to the child thread.
-                // However, the release ordering is not necessary because we
-                // made no memory access needing synchronization since the call
-                // to `acre_tsk`.
+                // The release ordering ensures that the above swap operation on
+                // `lifecycle` happens-before the child thread's
+                // `Box::from_raw(p_inner)`.
             }
             LIFECYCLE_FINISHED => {
                 // [FINISHED → JOINED]
diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs
index 63e070207cd..9865a945bad 100644
--- a/library/std/src/sys/sgx/mod.rs
+++ b/library/std/src/sys/sgx/mod.rs
@@ -34,7 +34,7 @@ pub mod process;
 pub mod stdio;
 pub mod thread;
 pub mod thread_local_key;
-pub mod thread_parker;
+pub mod thread_parking;
 pub mod time;
 
 mod condvar;
diff --git a/library/std/src/sys/sgx/thread.rs b/library/std/src/sys/sgx/thread.rs
index 579f758c6cc..1608b8cb642 100644
--- a/library/std/src/sys/sgx/thread.rs
+++ b/library/std/src/sys/sgx/thread.rs
@@ -65,9 +65,9 @@ mod task_queue {
 /// execution. The signal is sent once all TLS destructors have finished at
 /// which point no new thread locals should be created.
 pub mod wait_notify {
-    use super::super::thread_parker::Parker;
     use crate::pin::Pin;
     use crate::sync::Arc;
+    use crate::sys_common::thread_parking::Parker;
 
     pub struct Notifier(Arc<Parker>);
 
@@ -87,14 +87,14 @@ pub mod wait_notify {
         /// called, this will return immediately, otherwise the current thread
         /// is blocked until notified.
         pub fn wait(self) {
-            // This is not actually `unsafe`, but it uses the `Parker` API,
-            // which needs `unsafe` on some platforms.
+            // SAFETY:
+            // This is only ever called on one thread.
             unsafe { Pin::new(&*self.0).park() }
         }
     }
 
     pub fn new() -> (Notifier, Waiter) {
-        let inner = Arc::new(Parker::new_internal());
+        let inner = Arc::new(Parker::new());
         (Notifier(inner.clone()), Waiter(inner))
     }
 }
diff --git a/library/std/src/sys/sgx/thread_parker.rs b/library/std/src/sys/sgx/thread_parker.rs
deleted file mode 100644
index 1c55bcffb1e..00000000000
--- a/library/std/src/sys/sgx/thread_parker.rs
+++ /dev/null
@@ -1,107 +0,0 @@
-//! Thread parking based on SGX events.
-
-use super::abi::{thread, usercalls};
-use crate::io::ErrorKind;
-use crate::pin::Pin;
-use crate::ptr::{self, NonNull};
-use crate::sync::atomic::AtomicPtr;
-use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
-use crate::time::Duration;
-use fortanix_sgx_abi::{EV_UNPARK, WAIT_INDEFINITE};
-
-// The TCS structure must be page-aligned (this is checked by EENTER), so these cannot
-// be valid pointers
-const EMPTY: *mut u8 = ptr::invalid_mut(1);
-const NOTIFIED: *mut u8 = ptr::invalid_mut(2);
-
-pub struct Parker {
-    /// The park state. One of EMPTY, NOTIFIED or a TCS address.
-    /// A state change to NOTIFIED must be done with release ordering
-    /// and be observed with acquire ordering so that operations after
-    /// `thread::park` returns will not occur before the unpark message
-    /// was sent.
-    state: AtomicPtr<u8>,
-}
-
-impl Parker {
-    /// Construct the thread parker. The UNIX parker implementation
-    /// requires this to happen in-place.
-    pub unsafe fn new(parker: *mut Parker) {
-        unsafe { parker.write(Parker::new_internal()) }
-    }
-
-    pub(super) fn new_internal() -> Parker {
-        Parker { state: AtomicPtr::new(EMPTY) }
-    }
-
-    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
-    pub unsafe fn park(self: Pin<&Self>) {
-        if self.state.load(Acquire) != NOTIFIED {
-            let mut prev = EMPTY;
-            loop {
-                // Guard against changing TCS addresses by always setting the state to
-                // the current value.
-                let tcs = thread::current().as_ptr();
-                if self.state.compare_exchange(prev, tcs, Relaxed, Acquire).is_ok() {
-                    let event = usercalls::wait(EV_UNPARK, WAIT_INDEFINITE).unwrap();
-                    assert!(event & EV_UNPARK == EV_UNPARK);
-                    prev = tcs;
-                } else {
-                    // The state was definitely changed by another thread at this point.
-                    // The only time this occurs is when the state is changed to NOTIFIED.
-                    // We observed this change with acquire ordering, so we can simply
-                    // change the state to EMPTY with a relaxed store.
-                    break;
-                }
-            }
-        }
-
-        // At this point, the token was definately read with acquire ordering,
-        // so this can be a relaxed store.
-        self.state.store(EMPTY, Relaxed);
-    }
-
-    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
-    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
-        let timeout = u128::min(dur.as_nanos(), WAIT_INDEFINITE as u128 - 1) as u64;
-        let tcs = thread::current().as_ptr();
-
-        if self.state.load(Acquire) != NOTIFIED {
-            if self.state.compare_exchange(EMPTY, tcs, Relaxed, Acquire).is_ok() {
-                match usercalls::wait(EV_UNPARK, timeout) {
-                    Ok(event) => assert!(event & EV_UNPARK == EV_UNPARK),
-                    Err(e) => {
-                        assert!(matches!(e.kind(), ErrorKind::TimedOut | ErrorKind::WouldBlock))
-                    }
-                }
-
-                // Swap to provide acquire ordering even if the timeout occurred
-                // before the token was set. This situation can result in spurious
-                // wakeups on the next call to `park_timeout`, but it is better to let
-                // those be handled by the user than do some perhaps unnecessary, but
-                // always expensive guarding.
-                self.state.swap(EMPTY, Acquire);
-                return;
-            }
-        }
-
-        // The token was already read with `acquire` ordering, this can be a store.
-        self.state.store(EMPTY, Relaxed);
-    }
-
-    // This implementation doesn't require `Pin`, but other implementations do.
-    pub fn unpark(self: Pin<&Self>) {
-        let state = self.state.swap(NOTIFIED, Release);
-
-        if !matches!(state, EMPTY | NOTIFIED) {
-            // There is a thread waiting, wake it up.
-            let tcs = NonNull::new(state).unwrap();
-            // This will fail if the thread has already terminated or its TCS is destroyed
-            // by the time the signal is sent, but that is fine. If another thread receives
-            // the same TCS, it will receive this notification as a spurious wakeup, but
-            // all users of `wait` should and (internally) do guard against those where
-            // necessary.
-            let _ = usercalls::send(EV_UNPARK, Some(tcs));
-        }
-    }
-}
diff --git a/library/std/src/sys/sgx/thread_parking.rs b/library/std/src/sys/sgx/thread_parking.rs
new file mode 100644
index 00000000000..0006cd4f1be
--- /dev/null
+++ b/library/std/src/sys/sgx/thread_parking.rs
@@ -0,0 +1,23 @@
+use super::abi::usercalls;
+use crate::io::ErrorKind;
+use crate::time::Duration;
+use fortanix_sgx_abi::{EV_UNPARK, WAIT_INDEFINITE};
+
+pub type ThreadId = fortanix_sgx_abi::Tcs;
+
+pub use super::abi::thread::current;
+
+pub fn park(_hint: usize) {
+    usercalls::wait(EV_UNPARK, WAIT_INDEFINITE).unwrap();
+}
+
+pub fn park_timeout(dur: Duration, _hint: usize) {
+    let timeout = u128::min(dur.as_nanos(), WAIT_INDEFINITE as u128 - 1) as u64;
+    if let Err(e) = usercalls::wait(EV_UNPARK, timeout) {
+        assert!(matches!(e.kind(), ErrorKind::TimedOut | ErrorKind::WouldBlock))
+    }
+}
+
+pub fn unpark(tid: ThreadId, _hint: usize) {
+    let _ = usercalls::send(EV_UNPARK, Some(tid));
+}
diff --git a/library/std/src/sys/unix/android.rs b/library/std/src/sys/unix/android.rs
index 73ff10ab8a2..0f704994f55 100644
--- a/library/std/src/sys/unix/android.rs
+++ b/library/std/src/sys/unix/android.rs
@@ -1,7 +1,7 @@
 //! Android ABI-compatibility module
 //!
-//! The ABI of Android has changed quite a bit over time, and libstd attempts to
-//! be both forwards and backwards compatible as much as possible. We want to
+//! The ABI of Android has changed quite a bit over time, and std attempts to be
+//! both forwards and backwards compatible as much as possible. We want to
 //! always work with the most recent version of Android, but we also want to
 //! work with older versions of Android for whenever projects need to.
 //!
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index d5f50d77911..aea0c26ee8b 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -1754,11 +1754,11 @@ mod remove_dir_impl {
     use crate::sys::{cvt, cvt_r};
 
     #[cfg(not(any(
-        target_os = "linux",
+        all(target_os = "linux", target_env = "gnu"),
         all(target_os = "macos", not(target_arch = "aarch64"))
     )))]
     use libc::{fdopendir, openat, unlinkat};
-    #[cfg(target_os = "linux")]
+    #[cfg(all(target_os = "linux", target_env = "gnu"))]
     use libc::{fdopendir, openat64 as openat, unlinkat};
     #[cfg(all(target_os = "macos", not(target_arch = "aarch64")))]
     use macos_weak::{fdopendir, openat, unlinkat};
diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs
index 6fa85e859c0..0f7107122b7 100644
--- a/library/std/src/sys/unix/kernel_copy.rs
+++ b/library/std/src/sys/unix/kernel_copy.rs
@@ -61,9 +61,9 @@ use crate::ptr;
 use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering};
 use crate::sys::cvt;
 use crate::sys::weak::syscall;
-#[cfg(not(target_os = "linux"))]
+#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
 use libc::sendfile as sendfile64;
-#[cfg(target_os = "linux")]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
 use libc::sendfile64;
 use libc::{EBADF, EINVAL, ENOSYS, EOPNOTSUPP, EOVERFLOW, EPERM, EXDEV};
 
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 3d60941e84e..30a96be1430 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -40,7 +40,7 @@ pub mod stdio;
 pub mod thread;
 pub mod thread_local_dtor;
 pub mod thread_local_key;
-pub mod thread_parker;
+pub mod thread_parking;
 pub mod time;
 
 #[cfg(target_os = "espidf")]
@@ -95,9 +95,9 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
         )))]
         'poll: {
             use crate::sys::os::errno;
-            #[cfg(not(target_os = "linux"))]
+            #[cfg(not(all(target_os = "linux", target_env = "gnu")))]
             use libc::open as open64;
-            #[cfg(target_os = "linux")]
+            #[cfg(all(target_os = "linux", target_env = "gnu"))]
             use libc::open64;
             let pfds: &mut [_] = &mut [
                 libc::pollfd { fd: 0, events: 0, revents: 0 },
@@ -143,9 +143,9 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
         )))]
         {
             use crate::sys::os::errno;
-            #[cfg(not(target_os = "linux"))]
+            #[cfg(not(all(target_os = "linux", target_env = "gnu")))]
             use libc::open as open64;
-            #[cfg(target_os = "linux")]
+            #[cfg(all(target_os = "linux", target_env = "gnu"))]
             use libc::open64;
             for fd in 0..3 {
                 if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF {
@@ -164,7 +164,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
     unsafe fn reset_sigpipe(#[allow(unused_variables)] sigpipe: u8) {
         #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "horizon")))]
         {
-            // We don't want to add this as a public type to libstd, nor do we
+            // We don't want to add this as a public type to std, nor do we
             // want to `include!` a file from the compiler (which would break
             // Miri and xargo for example), so we choose to duplicate these
             // constants from `compiler/rustc_session/src/config/sigpipe.rs`.
@@ -184,12 +184,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
                 sigpipe::SIG_DFL => (true, Some(libc::SIG_DFL)),
                 _ => unreachable!(),
             };
-            // The bootstrap compiler doesn't know about sigpipe::DEFAULT, and always passes in
-            // SIG_IGN. This causes some tests to fail because they expect SIGPIPE to be reset to
-            // default on process spawning (which doesn't happen if #[unix_sigpipe] is specified).
-            // Since we can't differentiate between the cases here, treat SIG_IGN as DEFAULT
-            // unconditionally.
-            if sigpipe_attr_specified && !(cfg!(bootstrap) && sigpipe == sigpipe::SIG_IGN) {
+            if sigpipe_attr_specified {
                 UNIX_SIGPIPE_ATTR_SPECIFIED.store(true, crate::sync::atomic::Ordering::Relaxed);
             }
             if let Some(handler) = handler {
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index b84bf8f9264..c86f80972a6 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -512,7 +512,7 @@ impl FromRawFd for Socket {
 // A workaround for this bug is to call the res_init libc function, to clear
 // the cached configs. Unfortunately, while we believe glibc's implementation
 // of res_init is thread-safe, we know that other implementations are not
-// (https://github.com/rust-lang/rust/issues/43592). Code here in libstd could
+// (https://github.com/rust-lang/rust/issues/43592). Code here in std could
 // try to synchronize its res_init calls with a Mutex, but that wouldn't
 // protect programs that call into libc in other ways. So instead of calling
 // res_init unconditionally, we call it only when we detect we're linking
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index 848adca78c0..afd03d79c0b 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -144,6 +144,7 @@ pub enum ChildStdio {
     Null,
 }
 
+#[derive(Debug)]
 pub enum Stdio {
     Inherit,
     Null,
@@ -510,16 +511,68 @@ impl ChildStdio {
 }
 
 impl fmt::Debug for Command {
+    // show all attributes but `self.closures` which does not implement `Debug`
+    // and `self.argv` which is not useful for debugging
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if self.program != self.args[0] {
-            write!(f, "[{:?}] ", self.program)?;
-        }
-        write!(f, "{:?}", self.args[0])?;
+        if f.alternate() {
+            let mut debug_command = f.debug_struct("Command");
+            debug_command.field("program", &self.program).field("args", &self.args);
+            if !self.env.is_unchanged() {
+                debug_command.field("env", &self.env);
+            }
+
+            if self.cwd.is_some() {
+                debug_command.field("cwd", &self.cwd);
+            }
+            if self.uid.is_some() {
+                debug_command.field("uid", &self.uid);
+            }
+            if self.gid.is_some() {
+                debug_command.field("gid", &self.gid);
+            }
+
+            if self.groups.is_some() {
+                debug_command.field("groups", &self.groups);
+            }
+
+            if self.stdin.is_some() {
+                debug_command.field("stdin", &self.stdin);
+            }
+            if self.stdout.is_some() {
+                debug_command.field("stdout", &self.stdout);
+            }
+            if self.stderr.is_some() {
+                debug_command.field("stderr", &self.stderr);
+            }
+            if self.pgroup.is_some() {
+                debug_command.field("pgroup", &self.pgroup);
+            }
+
+            #[cfg(target_os = "linux")]
+            {
+                debug_command.field("create_pidfd", &self.create_pidfd);
+            }
 
-        for arg in &self.args[1..] {
-            write!(f, " {:?}", arg)?;
+            debug_command.finish()
+        } else {
+            if let Some(ref cwd) = self.cwd {
+                write!(f, "cd {cwd:?} && ")?;
+            }
+            for (key, value_opt) in self.get_envs() {
+                if let Some(value) = value_opt {
+                    write!(f, "{}={value:?} ", key.to_string_lossy())?;
+                }
+            }
+            if self.program != self.args[0] {
+                write!(f, "[{:?}] ", self.program)?;
+            }
+            write!(f, "{:?}", self.args[0])?;
+
+            for arg in &self.args[1..] {
+                write!(f, " {:?}", arg)?;
+            }
+            Ok(())
         }
-        Ok(())
     }
 }
 
diff --git a/library/std/src/sys/unix/stack_overflow.rs b/library/std/src/sys/unix/stack_overflow.rs
index 957e086798f..b59d4ba26af 100644
--- a/library/std/src/sys/unix/stack_overflow.rs
+++ b/library/std/src/sys/unix/stack_overflow.rs
@@ -45,9 +45,9 @@ mod imp {
     use crate::thread;
 
     use libc::MAP_FAILED;
-    #[cfg(not(target_os = "linux"))]
+    #[cfg(not(all(target_os = "linux", target_env = "gnu")))]
     use libc::{mmap as mmap64, munmap};
-    #[cfg(target_os = "linux")]
+    #[cfg(all(target_os = "linux", target_env = "gnu"))]
     use libc::{mmap64, munmap};
     use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL};
     use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE};
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index d454a2a717c..b251949bda2 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -505,7 +505,7 @@ mod cgroups {
                     let limit = raw_quota.next()?;
                     let period = raw_quota.next()?;
                     match (limit.parse::<usize>(), period.parse::<usize>()) {
-                        (Ok(limit), Ok(period)) => {
+                        (Ok(limit), Ok(period)) if period > 0 => {
                             quota = quota.min(limit / period);
                         }
                         _ => {}
@@ -565,7 +565,7 @@ mod cgroups {
                 let period = parse_file("cpu.cfs_period_us");
 
                 match (limit, period) {
-                    (Some(limit), Some(period)) => quota = quota.min(limit / period),
+                    (Some(limit), Some(period)) if period > 0 => quota = quota.min(limit / period),
                     _ => {}
                 }
 
@@ -653,9 +653,9 @@ pub mod guard {
 ))]
 #[cfg_attr(test, allow(dead_code))]
 pub mod guard {
-    #[cfg(not(target_os = "linux"))]
+    #[cfg(not(all(target_os = "linux", target_env = "gnu")))]
     use libc::{mmap as mmap64, mprotect};
-    #[cfg(target_os = "linux")]
+    #[cfg(all(target_os = "linux", target_env = "gnu"))]
     use libc::{mmap64, mprotect};
     use libc::{MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE};
 
diff --git a/library/std/src/sys/unix/thread_parker/netbsd.rs b/library/std/src/sys/unix/thread_parker/netbsd.rs
deleted file mode 100644
index 7657605b52f..00000000000
--- a/library/std/src/sys/unix/thread_parker/netbsd.rs
+++ /dev/null
@@ -1,113 +0,0 @@
-use crate::ffi::{c_int, c_void};
-use crate::pin::Pin;
-use crate::ptr::{null, null_mut};
-use crate::sync::atomic::{
-    AtomicU64,
-    Ordering::{Acquire, Relaxed, Release},
-};
-use crate::time::Duration;
-use libc::{_lwp_self, clockid_t, lwpid_t, time_t, timespec, CLOCK_MONOTONIC};
-
-extern "C" {
-    fn ___lwp_park60(
-        clock_id: clockid_t,
-        flags: c_int,
-        ts: *mut timespec,
-        unpark: lwpid_t,
-        hint: *const c_void,
-        unparkhint: *const c_void,
-    ) -> c_int;
-    fn _lwp_unpark(lwp: lwpid_t, hint: *const c_void) -> c_int;
-}
-
-/// The thread is not parked and the token is not available.
-///
-/// Zero cannot be a valid LWP id, since it is used as empty value for the unpark
-/// argument in _lwp_park.
-const EMPTY: u64 = 0;
-/// The token is available. Do not park anymore.
-const NOTIFIED: u64 = u64::MAX;
-
-pub struct Parker {
-    /// The parker state. Contains either one of the two state values above or the LWP
-    /// id of the parked thread.
-    state: AtomicU64,
-}
-
-impl Parker {
-    pub unsafe fn new(parker: *mut Parker) {
-        parker.write(Parker { state: AtomicU64::new(EMPTY) })
-    }
-
-    // Does not actually need `unsafe` or `Pin`, but the pthread implementation does.
-    pub unsafe fn park(self: Pin<&Self>) {
-        // If the token has already been made available, we can skip
-        // a bit of work, so check for it here.
-        if self.state.load(Acquire) != NOTIFIED {
-            let parked = _lwp_self() as u64;
-            let hint = self.state.as_mut_ptr().cast();
-            if self.state.compare_exchange(EMPTY, parked, Relaxed, Acquire).is_ok() {
-                // Loop to guard against spurious wakeups.
-                loop {
-                    ___lwp_park60(0, 0, null_mut(), 0, hint, null());
-                    if self.state.load(Acquire) == NOTIFIED {
-                        break;
-                    }
-                }
-            }
-        }
-
-        // At this point, the change to NOTIFIED has always been observed with acquire
-        // ordering, so we can just use a relaxed store here (instead of a swap).
-        self.state.store(EMPTY, Relaxed);
-    }
-
-    // Does not actually need `unsafe` or `Pin`, but the pthread implementation does.
-    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
-        if self.state.load(Acquire) != NOTIFIED {
-            let parked = _lwp_self() as u64;
-            let hint = self.state.as_mut_ptr().cast();
-            let mut timeout = timespec {
-                // Saturate so that the operation will definitely time out
-                // (even if it is after the heat death of the universe).
-                tv_sec: dur.as_secs().try_into().ok().unwrap_or(time_t::MAX),
-                tv_nsec: dur.subsec_nanos().into(),
-            };
-
-            if self.state.compare_exchange(EMPTY, parked, Relaxed, Acquire).is_ok() {
-                // Timeout needs to be mutable since it is modified on NetBSD 9.0 and
-                // above.
-                ___lwp_park60(CLOCK_MONOTONIC, 0, &mut timeout, 0, hint, null());
-                // Use a swap to get acquire ordering even if the token was set after
-                // the timeout occurred.
-                self.state.swap(EMPTY, Acquire);
-                return;
-            }
-        }
-
-        self.state.store(EMPTY, Relaxed);
-    }
-
-    // Does not actually need `Pin`, but the pthread implementation does.
-    pub fn unpark(self: Pin<&Self>) {
-        let state = self.state.swap(NOTIFIED, Release);
-        if !matches!(state, EMPTY | NOTIFIED) {
-            let lwp = state as lwpid_t;
-            let hint = self.state.as_mut_ptr().cast();
-
-            // If the parking thread terminated and did not actually park, this will
-            // probably return an error, which is OK. In the worst case, another
-            // thread has received the same LWP id. It will then receive a spurious
-            // wakeup, but those are allowable per the API contract. The same reasoning
-            // applies if a timeout occurred before this call, but the state was not
-            // yet reset.
-
-            // SAFETY:
-            // The syscall has no invariants to hold. Only unsafe because it is an
-            // extern function.
-            unsafe {
-                _lwp_unpark(lwp, hint);
-            }
-        }
-    }
-}
diff --git a/library/std/src/sys/unix/thread_parker/darwin.rs b/library/std/src/sys/unix/thread_parking/darwin.rs
index 2f5356fe227..b709fada3b4 100644
--- a/library/std/src/sys/unix/thread_parker/darwin.rs
+++ b/library/std/src/sys/unix/thread_parking/darwin.rs
@@ -46,7 +46,7 @@ unsafe impl Sync for Parker {}
 unsafe impl Send for Parker {}
 
 impl Parker {
-    pub unsafe fn new(parker: *mut Parker) {
+    pub unsafe fn new_in_place(parker: *mut Parker) {
         let semaphore = dispatch_semaphore_create(0);
         assert!(
             !semaphore.is_null(),
diff --git a/library/std/src/sys/unix/thread_parker/mod.rs b/library/std/src/sys/unix/thread_parking/mod.rs
index 35f1e68a87e..185333c072f 100644
--- a/library/std/src/sys/unix/thread_parker/mod.rs
+++ b/library/std/src/sys/unix/thread_parking/mod.rs
@@ -24,7 +24,7 @@ cfg_if::cfg_if! {
         pub use darwin::Parker;
     } else if #[cfg(target_os = "netbsd")] {
         mod netbsd;
-        pub use netbsd::Parker;
+        pub use netbsd::{current, park, park_timeout, unpark, ThreadId};
     } else {
         mod pthread;
         pub use pthread::Parker;
diff --git a/library/std/src/sys/unix/thread_parking/netbsd.rs b/library/std/src/sys/unix/thread_parking/netbsd.rs
new file mode 100644
index 00000000000..3be08122138
--- /dev/null
+++ b/library/std/src/sys/unix/thread_parking/netbsd.rs
@@ -0,0 +1,52 @@
+use crate::ffi::{c_int, c_void};
+use crate::ptr;
+use crate::time::Duration;
+use libc::{_lwp_self, clockid_t, lwpid_t, time_t, timespec, CLOCK_MONOTONIC};
+
+extern "C" {
+    fn ___lwp_park60(
+        clock_id: clockid_t,
+        flags: c_int,
+        ts: *mut timespec,
+        unpark: lwpid_t,
+        hint: *const c_void,
+        unparkhint: *const c_void,
+    ) -> c_int;
+    fn _lwp_unpark(lwp: lwpid_t, hint: *const c_void) -> c_int;
+}
+
+pub type ThreadId = lwpid_t;
+
+#[inline]
+pub fn current() -> ThreadId {
+    unsafe { _lwp_self() }
+}
+
+#[inline]
+pub fn park(hint: usize) {
+    unsafe {
+        ___lwp_park60(0, 0, ptr::null_mut(), 0, ptr::invalid(hint), ptr::null());
+    }
+}
+
+pub fn park_timeout(dur: Duration, hint: usize) {
+    let mut timeout = timespec {
+        // Saturate so that the operation will definitely time out
+        // (even if it is after the heat death of the universe).
+        tv_sec: dur.as_secs().try_into().ok().unwrap_or(time_t::MAX),
+        tv_nsec: dur.subsec_nanos().into(),
+    };
+
+    // Timeout needs to be mutable since it is modified on NetBSD 9.0 and
+    // above.
+    unsafe {
+        ___lwp_park60(CLOCK_MONOTONIC, 0, &mut timeout, 0, ptr::invalid(hint), ptr::null());
+    }
+}
+
+#[inline]
+pub fn unpark(tid: ThreadId, hint: usize) {
+    unsafe {
+        _lwp_unpark(tid, ptr::invalid(hint));
+    }
+}
diff --git a/library/std/src/sys/unix/thread_parker/pthread.rs b/library/std/src/sys/unix/thread_parking/pthread.rs
index c400c771567..082d25e68f5 100644
--- a/library/std/src/sys/unix/thread_parker/pthread.rs
+++ b/library/std/src/sys/unix/thread_parking/pthread.rs
@@ -44,7 +44,8 @@ unsafe fn wait_timeout(
         target_os = "macos",
         target_os = "ios",
         target_os = "watchos",
-        target_os = "espidf"
+        target_os = "espidf",
+        target_os = "horizon",
     ))]
     let (now, dur) = {
         use crate::cmp::min;
@@ -70,7 +71,8 @@ unsafe fn wait_timeout(
         target_os = "macos",
         target_os = "ios",
         target_os = "watchos",
-        target_os = "espidf"
+        target_os = "espidf",
+        target_os = "horizon",
     )))]
     let (now, dur) = {
         use crate::sys::time::Timespec;
@@ -97,7 +99,7 @@ impl Parker {
     ///
     /// # Safety
     /// The constructed parker must never be moved.
-    pub unsafe fn new(parker: *mut Parker) {
+    pub unsafe fn new_in_place(parker: *mut Parker) {
         // Use the default mutex implementation to allow for simpler initialization.
         // This could lead to undefined behaviour when deadlocking. This is avoided
         // by not deadlocking. Note in particular the unlocking operation before any
diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs
index f5a4ce929b2..62ffee70bec 100644
--- a/library/std/src/sys/unix/weak.rs
+++ b/library/std/src/sys/unix/weak.rs
@@ -1,9 +1,8 @@
 //! Support for "weak linkage" to symbols on Unix
 //!
-//! Some I/O operations we do in libstd require newer versions of OSes but we
-//! need to maintain binary compatibility with older releases for now. In order
-//! to use the new functionality when available we use this module for
-//! detection.
+//! Some I/O operations we do in std require newer versions of OSes but we need
+//! to maintain binary compatibility with older releases for now. In order to
+//! use the new functionality when available we use this module for detection.
 //!
 //! One option to use here is weak linkage, but that is unfortunately only
 //! really workable with ELF. Otherwise, use dlsym to get the symbol value at
@@ -29,7 +28,7 @@ use crate::ptr;
 use crate::sync::atomic::{self, AtomicPtr, Ordering};
 
 // We can use true weak linkage on ELF targets.
-#[cfg(all(not(any(target_os = "macos", target_os = "ios")), not(bootstrap)))]
+#[cfg(not(any(target_os = "macos", target_os = "ios")))]
 pub(crate) macro weak {
     (fn $name:ident($($t:ty),*) -> $ret:ty) => (
         let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
@@ -43,30 +42,14 @@ pub(crate) macro weak {
     )
 }
 
-#[cfg(all(not(any(target_os = "macos", target_os = "ios")), bootstrap))]
-pub(crate) macro weak {
-    (fn $name:ident($($t:ty),*) -> $ret:ty) => (
-        let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
-            extern "C" {
-                #[linkage = "extern_weak"]
-                static $name: *const libc::c_void;
-            }
-            #[allow(unused_unsafe)]
-            ExternWeak::new(unsafe { $name })
-        };
-    )
-}
-
 // On non-ELF targets, use the dlsym approximation of weak linkage.
 #[cfg(any(target_os = "macos", target_os = "ios"))]
 pub(crate) use self::dlsym as weak;
 
-#[cfg(not(bootstrap))]
 pub(crate) struct ExternWeak<F: Copy> {
     weak_ptr: Option<F>,
 }
 
-#[cfg(not(bootstrap))]
 impl<F: Copy> ExternWeak<F> {
     #[inline]
     pub(crate) fn new(weak_ptr: Option<F>) -> Self {
@@ -79,34 +62,6 @@ impl<F: Copy> ExternWeak<F> {
     }
 }
 
-#[cfg(bootstrap)]
-pub(crate) struct ExternWeak<F> {
-    weak_ptr: *const libc::c_void,
-    _marker: PhantomData<F>,
-}
-
-#[cfg(bootstrap)]
-impl<F> ExternWeak<F> {
-    #[inline]
-    pub(crate) fn new(weak_ptr: *const libc::c_void) -> Self {
-        ExternWeak { weak_ptr, _marker: PhantomData }
-    }
-}
-
-#[cfg(bootstrap)]
-impl<F> ExternWeak<F> {
-    #[inline]
-    pub(crate) fn get(&self) -> Option<F> {
-        unsafe {
-            if self.weak_ptr.is_null() {
-                None
-            } else {
-                Some(mem::transmute_copy::<*const libc::c_void, F>(&self.weak_ptr))
-            }
-        }
-    }
-}
-
 pub(crate) macro dlsym {
     (fn $name:ident($($t:ty),*) -> $ret:ty) => (
          dlsym!(fn $name($($t),*) -> $ret, stringify!($name));
diff --git a/library/std/src/sys/unsupported/mod.rs b/library/std/src/sys/unsupported/mod.rs
index 7bf6d40b76d..15b22c620d5 100644
--- a/library/std/src/sys/unsupported/mod.rs
+++ b/library/std/src/sys/unsupported/mod.rs
@@ -9,6 +9,7 @@ pub mod fs;
 pub mod io;
 pub mod locks;
 pub mod net;
+pub mod once;
 pub mod os;
 #[path = "../unix/os_str.rs"]
 pub mod os_str;
diff --git a/library/std/src/sys/unsupported/once.rs b/library/std/src/sys/unsupported/once.rs
new file mode 100644
index 00000000000..b4bb4975f41
--- /dev/null
+++ b/library/std/src/sys/unsupported/once.rs
@@ -0,0 +1,89 @@
+use crate::cell::Cell;
+use crate::sync as public;
+
+pub struct Once {
+    state: Cell<State>,
+}
+
+pub struct OnceState {
+    poisoned: bool,
+    set_state_to: Cell<State>,
+}
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+enum State {
+    Incomplete,
+    Poisoned,
+    Running,
+    Complete,
+}
+
+struct CompletionGuard<'a> {
+    state: &'a Cell<State>,
+    set_state_on_drop_to: State,
+}
+
+impl<'a> Drop for CompletionGuard<'a> {
+    fn drop(&mut self) {
+        self.state.set(self.set_state_on_drop_to);
+    }
+}
+
+// Safety: threads are not supported on this platform.
+unsafe impl Sync for Once {}
+
+impl Once {
+    #[inline]
+    #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
+    pub const fn new() -> Once {
+        Once { state: Cell::new(State::Incomplete) }
+    }
+
+    #[inline]
+    pub fn is_completed(&self) -> bool {
+        self.state.get() == State::Complete
+    }
+
+    #[cold]
+    #[track_caller]
+    pub fn call(&self, ignore_poisoning: bool, f: &mut impl FnMut(&public::OnceState)) {
+        let state = self.state.get();
+        match state {
+            State::Poisoned if !ignore_poisoning => {
+                // Panic to propagate the poison.
+                panic!("Once instance has previously been poisoned");
+            }
+            State::Incomplete | State::Poisoned => {
+                self.state.set(State::Running);
+                // `guard` will set the new state on drop.
+                let mut guard =
+                    CompletionGuard { state: &self.state, set_state_on_drop_to: State::Poisoned };
+                // Run the function, letting it know if we're poisoned or not.
+                let f_state = public::OnceState {
+                    inner: OnceState {
+                        poisoned: state == State::Poisoned,
+                        set_state_to: Cell::new(State::Complete),
+                    },
+                };
+                f(&f_state);
+                guard.set_state_on_drop_to = f_state.inner.set_state_to.get();
+            }
+            State::Running => {
+                panic!("one-time initialization may not be performed recursively");
+            }
+            State::Complete => {}
+        }
+    }
+}
+
+impl OnceState {
+    #[inline]
+    pub fn is_poisoned(&self) -> bool {
+        self.poisoned
+    }
+
+    #[inline]
+    pub fn poison(&self) {
+        self.set_state_to.set(State::Poisoned)
+    }
+}
diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs
index c8c47763a34..1dc3f2b2026 100644
--- a/library/std/src/sys/wasi/mod.rs
+++ b/library/std/src/sys/wasi/mod.rs
@@ -32,6 +32,8 @@ pub mod io;
 #[path = "../unsupported/locks/mod.rs"]
 pub mod locks;
 pub mod net;
+#[path = "../unsupported/once.rs"]
+pub mod once;
 pub mod os;
 #[path = "../unix/os_str.rs"]
 pub mod os_str;
diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs
index d68c3e5f1df..77ebe3c4ac6 100644
--- a/library/std/src/sys/wasm/mod.rs
+++ b/library/std/src/sys/wasm/mod.rs
@@ -66,6 +66,8 @@ cfg_if::cfg_if! {
     } else {
         #[path = "../unsupported/locks/mod.rs"]
         pub mod locks;
+        #[path = "../unsupported/once.rs"]
+        pub mod once;
         #[path = "../unsupported/thread.rs"]
         pub mod thread;
     }
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index e67411e1686..77359abe429 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -33,7 +33,7 @@ pub mod stdio;
 pub mod thread;
 pub mod thread_local_dtor;
 pub mod thread_local_key;
-pub mod thread_parker;
+pub mod thread_parking;
 pub mod time;
 cfg_if::cfg_if! {
     if #[cfg(not(target_vendor = "uwp"))] {
diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parking.rs
index 2f7ae863b6a..5d43676adbb 100644
--- a/library/std/src/sys/windows/thread_parker.rs
+++ b/library/std/src/sys/windows/thread_parking.rs
@@ -97,7 +97,7 @@ const NOTIFIED: i8 = 1;
 impl Parker {
     /// Construct the Windows parker. The UNIX parker implementation
     /// requires this to happen in-place.
-    pub unsafe fn new(parker: *mut Parker) {
+    pub unsafe fn new_in_place(parker: *mut Parker) {
         parker.write(Self { state: AtomicI8::new(EMPTY) });
     }
 
diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs
index 8807077cb49..f1d804ef40c 100644
--- a/library/std/src/sys_common/backtrace.rs
+++ b/library/std/src/sys_common/backtrace.rs
@@ -20,7 +20,7 @@ pub fn lock() -> impl Drop {
 /// Prints the current backtrace.
 pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
     // There are issues currently linking libbacktrace into tests, and in
-    // general during libstd's own unit tests we're not testing this path. In
+    // general during std's own unit tests we're not testing this path. In
     // test mode immediately return here to optimize away any references to the
     // libbacktrace symbols
     if cfg!(test) {
@@ -111,7 +111,7 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
 }
 
 /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
-/// this is only inline(never) when backtraces in libstd are enabled, otherwise
+/// this is only inline(never) when backtraces in std are enabled, otherwise
 /// it's fine to optimize away.
 #[cfg_attr(feature = "backtrace", inline(never))]
 pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
@@ -127,7 +127,7 @@ where
 }
 
 /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
-/// this is only inline(never) when backtraces in libstd are enabled, otherwise
+/// this is only inline(never) when backtraces in std are enabled, otherwise
 /// it's fine to optimize away.
 #[cfg_attr(feature = "backtrace", inline(never))]
 pub fn __rust_end_short_backtrace<F, T>(f: F) -> T
diff --git a/library/std/src/sys_common/io.rs b/library/std/src/sys_common/io.rs
index d1e9fed41fc..4a42ff3c618 100644
--- a/library/std/src/sys_common/io.rs
+++ b/library/std/src/sys_common/io.rs
@@ -39,9 +39,10 @@ pub mod test {
         }
     }
 
+    #[track_caller] // for `test_rng`
     pub fn tmpdir() -> TempDir {
         let p = env::temp_dir();
-        let mut r = rand::thread_rng();
+        let mut r = crate::test_helpers::test_rng();
         let ret = p.join(&format!("rust-{}", r.next_u32()));
         fs::create_dir(&ret).unwrap();
         TempDir(ret)
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index b1987aa0f62..6b24b0e9aa8 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -27,11 +27,10 @@ pub mod lazy_box;
 pub mod memchr;
 pub mod once;
 pub mod process;
-pub mod remutex;
 pub mod thread;
 pub mod thread_info;
 pub mod thread_local_dtor;
-pub mod thread_parker;
+pub mod thread_parking;
 pub mod wstr;
 pub mod wtf8;
 
diff --git a/library/std/src/sys_common/once/mod.rs b/library/std/src/sys_common/once/mod.rs
index 8742e68cc7a..359697d8313 100644
--- a/library/std/src/sys_common/once/mod.rs
+++ b/library/std/src/sys_common/once/mod.rs
@@ -6,22 +6,6 @@
 // As a result, we end up implementing it ourselves in the standard library.
 // This also gives us the opportunity to optimize the implementation a bit which
 // should help the fast path on call sites.
-//
-// So to recap, the guarantees of a Once are that it will call the
-// initialization closure at most once, and it will never return until the one
-// that's running has finished running. This means that we need some form of
-// blocking here while the custom callback is running at the very least.
-// Additionally, we add on the restriction of **poisoning**. Whenever an
-// initialization closure panics, the Once enters a "poisoned" state which means
-// that all future calls will immediately panic as well.
-//
-// So to implement this, one might first reach for a `Mutex`, but those cannot
-// be put into a `static`. It also gets a lot harder with poisoning to figure
-// out when the mutex needs to be deallocated because it's not after the closure
-// finishes, but after the first successful closure finishes.
-//
-// All in all, this is instead implemented with atomics and lock-free
-// operations! Whee!
 
 cfg_if::cfg_if! {
     if #[cfg(any(
@@ -36,8 +20,15 @@ cfg_if::cfg_if! {
     ))] {
         mod futex;
         pub use futex::{Once, OnceState};
+    } else if #[cfg(any(
+        windows,
+        target_family = "unix",
+        all(target_vendor = "fortanix", target_env = "sgx"),
+        target_os = "solid_asp3",
+    ))] {
+        mod queue;
+        pub use queue::{Once, OnceState};
     } else {
-        mod generic;
-        pub use generic::{Once, OnceState};
+        pub use crate::sys::once::{Once, OnceState};
     }
 }
diff --git a/library/std/src/sys_common/once/generic.rs b/library/std/src/sys_common/once/queue.rs
index d953a674592..d953a674592 100644
--- a/library/std/src/sys_common/once/generic.rs
+++ b/library/std/src/sys_common/once/queue.rs
diff --git a/library/std/src/sys_common/process.rs b/library/std/src/sys_common/process.rs
index ae11412067b..18883048dae 100644
--- a/library/std/src/sys_common/process.rs
+++ b/library/std/src/sys_common/process.rs
@@ -4,12 +4,13 @@
 use crate::collections::BTreeMap;
 use crate::env;
 use crate::ffi::{OsStr, OsString};
+use crate::fmt;
 use crate::io;
 use crate::sys::pipe::read2;
 use crate::sys::process::{EnvKey, ExitStatus, Process, StdioPipes};
 
 // Stores a set of changes to an environment
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 pub struct CommandEnv {
     clear: bool,
     saw_path: bool,
@@ -22,6 +23,14 @@ impl Default for CommandEnv {
     }
 }
 
+impl fmt::Debug for CommandEnv {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut debug_command_env = f.debug_struct("CommandEnv");
+        debug_command_env.field("clear", &self.clear).field("vars", &self.vars);
+        debug_command_env.finish()
+    }
+}
+
 impl CommandEnv {
     // Capture the current environment with these changes applied
     pub fn capture(&self) -> BTreeMap<EnvKey, OsString> {
diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs
index 747579f1781..2672a2a75b0 100644
--- a/library/std/src/sys_common/thread_local_key.rs
+++ b/library/std/src/sys_common/thread_local_key.rs
@@ -117,10 +117,14 @@ pub struct Key {
 /// This value specifies no destructor by default.
 pub const INIT: StaticKey = StaticKey::new(None);
 
+// Define a sentinel value that is unlikely to be returned
+// as a TLS key (but it may be returned).
+const KEY_SENTVAL: usize = 0;
+
 impl StaticKey {
     #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
     pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> StaticKey {
-        StaticKey { key: atomic::AtomicUsize::new(0), dtor }
+        StaticKey { key: atomic::AtomicUsize::new(KEY_SENTVAL), dtor }
     }
 
     /// Gets the value associated with this TLS key
@@ -144,31 +148,36 @@ impl StaticKey {
     #[inline]
     unsafe fn key(&self) -> imp::Key {
         match self.key.load(Ordering::Relaxed) {
-            0 => self.lazy_init() as imp::Key,
+            KEY_SENTVAL => self.lazy_init() as imp::Key,
             n => n as imp::Key,
         }
     }
 
     unsafe fn lazy_init(&self) -> usize {
-        // POSIX allows the key created here to be 0, but the compare_exchange
-        // below relies on using 0 as a sentinel value to check who won the
+        // POSIX allows the key created here to be KEY_SENTVAL, but the compare_exchange
+        // below relies on using KEY_SENTVAL as a sentinel value to check who won the
         // race to set the shared TLS key. As far as I know, there is no
         // guaranteed value that cannot be returned as a posix_key_create key,
         // so there is no value we can initialize the inner key with to
         // prove that it has not yet been set. As such, we'll continue using a
-        // value of 0, but with some gyrations to make sure we have a non-0
+        // value of KEY_SENTVAL, but with some gyrations to make sure we have a non-KEY_SENTVAL
         // value returned from the creation routine.
         // FIXME: this is clearly a hack, and should be cleaned up.
         let key1 = imp::create(self.dtor);
-        let key = if key1 != 0 {
+        let key = if key1 as usize != KEY_SENTVAL {
             key1
         } else {
             let key2 = imp::create(self.dtor);
             imp::destroy(key1);
             key2
         };
-        rtassert!(key != 0);
-        match self.key.compare_exchange(0, key as usize, Ordering::SeqCst, Ordering::SeqCst) {
+        rtassert!(key as usize != KEY_SENTVAL);
+        match self.key.compare_exchange(
+            KEY_SENTVAL,
+            key as usize,
+            Ordering::SeqCst,
+            Ordering::SeqCst,
+        ) {
             // The CAS succeeded, so we've created the actual key
             Ok(_) => key as usize,
             // If someone beat us to the punch, use their key instead
diff --git a/library/std/src/sys_common/thread_parker/futex.rs b/library/std/src/sys_common/thread_parking/futex.rs
index d9e2f39e345..588e7b27826 100644
--- a/library/std/src/sys_common/thread_parker/futex.rs
+++ b/library/std/src/sys_common/thread_parking/futex.rs
@@ -35,7 +35,7 @@ pub struct Parker {
 impl Parker {
     /// Construct the futex parker. The UNIX parker implementation
     /// requires this to happen in-place.
-    pub unsafe fn new(parker: *mut Parker) {
+    pub unsafe fn new_in_place(parker: *mut Parker) {
         parker.write(Self { state: AtomicU32::new(EMPTY) });
     }
 
diff --git a/library/std/src/sys_common/thread_parker/generic.rs b/library/std/src/sys_common/thread_parking/generic.rs
index f3d8b34d3fd..3209bffe353 100644
--- a/library/std/src/sys_common/thread_parker/generic.rs
+++ b/library/std/src/sys_common/thread_parking/generic.rs
@@ -19,7 +19,7 @@ pub struct Parker {
 impl Parker {
     /// Construct the generic parker. The UNIX parker implementation
     /// requires this to happen in-place.
-    pub unsafe fn new(parker: *mut Parker) {
+    pub unsafe fn new_in_place(parker: *mut Parker) {
         parker.write(Parker {
             state: AtomicUsize::new(EMPTY),
             lock: Mutex::new(()),
diff --git a/library/std/src/sys_common/thread_parking/id.rs b/library/std/src/sys_common/thread_parking/id.rs
new file mode 100644
index 00000000000..e98169597c3
--- /dev/null
+++ b/library/std/src/sys_common/thread_parking/id.rs
@@ -0,0 +1,108 @@
+//! Thread parking using thread ids.
+//!
+//! Some platforms (notably NetBSD) have thread parking primitives whose semantics
+//! match those offered by `thread::park`, with the difference that the thread to
+//! be unparked is referenced by a platform-specific thread id. Since the thread
+//! parker is constructed before that id is known, an atomic state variable is used
+//! to manage the park state and propagate the thread id. This also avoids platform
+//! calls in the case where `unpark` is called before `park`.
+
+use crate::cell::UnsafeCell;
+use crate::pin::Pin;
+use crate::sync::atomic::{
+    fence, AtomicI8,
+    Ordering::{Acquire, Relaxed, Release},
+};
+use crate::sys::thread_parking::{current, park, park_timeout, unpark, ThreadId};
+use crate::time::Duration;
+
+pub struct Parker {
+    state: AtomicI8,
+    tid: UnsafeCell<Option<ThreadId>>,
+}
+
+const PARKED: i8 = -1;
+const EMPTY: i8 = 0;
+const NOTIFIED: i8 = 1;
+
+impl Parker {
+    pub fn new() -> Parker {
+        Parker { state: AtomicI8::new(EMPTY), tid: UnsafeCell::new(None) }
+    }
+
+    /// Create a new thread parker. UNIX requires this to happen in-place.
+    pub unsafe fn new_in_place(parker: *mut Parker) {
+        parker.write(Parker::new())
+    }
+
+    /// # Safety
+    /// * must always be called from the same thread
+    /// * must be called before the state is set to PARKED
+    unsafe fn init_tid(&self) {
+        // The field is only ever written to from this thread, so we don't need
+        // synchronization to read it here.
+        if self.tid.get().read().is_none() {
+            // Because this point is only reached once, before the state is set
+            // to PARKED for the first time, the non-atomic write here can not
+            // conflict with reads by other threads.
+            self.tid.get().write(Some(current()));
+            // Ensure that the write can be observed by all threads reading the
+            // state. Synchronizes with the acquire barrier in `unpark`.
+            fence(Release);
+        }
+    }
+
+    pub unsafe fn park(self: Pin<&Self>) {
+        self.init_tid();
+
+        // Changes NOTIFIED to EMPTY and EMPTY to PARKED.
+        let mut state = self.state.fetch_sub(1, Acquire).wrapping_sub(1);
+        if state == PARKED {
+            // Loop to guard against spurious wakeups.
+            while state == PARKED {
+                park(self.state.as_mut_ptr().addr());
+                state = self.state.load(Acquire);
+            }
+
+            // Since the state change has already been observed with acquire
+            // ordering, the state can be reset with a relaxed store instead
+            // of a swap.
+            self.state.store(EMPTY, Relaxed);
+        }
+    }
+
+    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
+        self.init_tid();
+
+        let state = self.state.fetch_sub(1, Acquire).wrapping_sub(1);
+        if state == PARKED {
+            park_timeout(dur, self.state.as_mut_ptr().addr());
+            // Swap to ensure that we observe all state changes with acquire
+            // ordering, even if the state has been changed after the timeout
+            // occured.
+            self.state.swap(EMPTY, Acquire);
+        }
+    }
+
+    pub fn unpark(self: Pin<&Self>) {
+        let state = self.state.swap(NOTIFIED, Release);
+        if state == PARKED {
+            // Synchronize with the release fence in `init_tid` to observe the
+            // write to `tid`.
+            fence(Acquire);
+            // # Safety
+            // The thread id is initialized before the state is set to `PARKED`
+            // for the first time and is not written to from that point on
+            // (negating the need for an atomic read).
+            let tid = unsafe { self.tid.get().read().unwrap_unchecked() };
+            // It is possible that the waiting thread woke up because of a timeout
+            // and terminated before this call is made. This call then returns an
+            // error or wakes up an unrelated thread. The platform API and
+            // environment does allow this, however.
+            unpark(tid, self.state.as_mut_ptr().addr());
+        }
+    }
+}
+
+unsafe impl Send for Parker {}
+unsafe impl Sync for Parker {}
diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parking/mod.rs
index 08a2bdd8229..0ead6633c35 100644
--- a/library/std/src/sys_common/thread_parker/mod.rs
+++ b/library/std/src/sys_common/thread_parking/mod.rs
@@ -11,13 +11,17 @@ cfg_if::cfg_if! {
     ))] {
         mod futex;
         pub use futex::Parker;
+    } else if #[cfg(any(
+        target_os = "netbsd",
+        all(target_vendor = "fortanix", target_env = "sgx"),
+    ))] {
+        mod id;
+        pub use id::Parker;
     } else if #[cfg(target_os = "solid_asp3")] {
         mod wait_flag;
         pub use wait_flag::Parker;
     } else if #[cfg(any(windows, target_family = "unix"))] {
-        pub use crate::sys::thread_parker::Parker;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
-        pub use crate::sys::thread_parker::Parker;
+        pub use crate::sys::thread_parking::Parker;
     } else {
         mod generic;
         pub use generic::Parker;
diff --git a/library/std/src/sys_common/thread_parker/wait_flag.rs b/library/std/src/sys_common/thread_parking/wait_flag.rs
index 6561c186655..d0f8899a94e 100644
--- a/library/std/src/sys_common/thread_parker/wait_flag.rs
+++ b/library/std/src/sys_common/thread_parking/wait_flag.rs
@@ -41,7 +41,7 @@ pub struct Parker {
 impl Parker {
     /// Construct a parker for the current thread. The UNIX parker
     /// implementation requires this to happen in-place.
-    pub unsafe fn new(parker: *mut Parker) {
+    pub unsafe fn new_in_place(parker: *mut Parker) {
         parker.write(Parker { state: AtomicI8::new(EMPTY), wait_flag: WaitFlag::new() })
     }
 
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 5d267891bb0..b30bb7b77ef 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -905,9 +905,8 @@ pub mod statik {
 pub mod fast {
     use super::lazy::LazyKeyInner;
     use crate::cell::Cell;
-    use crate::fmt;
-    use crate::mem;
     use crate::sys::thread_local_dtor::register_dtor;
+    use crate::{fmt, mem, panic};
 
     #[derive(Copy, Clone)]
     enum DtorState {
@@ -950,7 +949,7 @@ pub mod fast {
 
         // note that this is just a publicly-callable function only for the
         // const-initialized form of thread locals, basically a way to call the
-        // free `register_dtor` function defined elsewhere in libstd.
+        // free `register_dtor` function defined elsewhere in std.
         pub unsafe fn register_dtor(a: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
             unsafe {
                 register_dtor(a, dtor);
@@ -1028,10 +1027,15 @@ pub mod fast {
         // `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
         // causes future calls to `get` to run `try_initialize_drop` again,
         // which will now fail, and return `None`.
-        unsafe {
+        //
+        // Wrap the call in a catch to ensure unwinding is caught in the event
+        // a panic takes place in a destructor.
+        if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe {
             let value = (*ptr).inner.take();
             (*ptr).dtor_state.set(DtorState::RunningOrHasRun);
             drop(value);
+        })) {
+            rtabort!("thread local panicked on drop");
         }
     }
 }
@@ -1044,10 +1048,8 @@ pub mod fast {
 pub mod os {
     use super::lazy::LazyKeyInner;
     use crate::cell::Cell;
-    use crate::fmt;
-    use crate::marker;
-    use crate::ptr;
     use crate::sys_common::thread_local_key::StaticKey as OsStaticKey;
+    use crate::{fmt, marker, panic, ptr};
 
     /// Use a regular global static to store this key; the state provided will then be
     /// thread-local.
@@ -1137,12 +1139,17 @@ pub mod os {
         //
         // Note that to prevent an infinite loop we reset it back to null right
         // before we return from the destructor ourselves.
-        unsafe {
+        //
+        // Wrap the call in a catch to ensure unwinding is caught in the event
+        // a panic takes place in a destructor.
+        if let Err(_) = panic::catch_unwind(|| unsafe {
             let ptr = Box::from_raw(ptr as *mut Value<T>);
             let key = ptr.key;
             key.os.set(ptr::invalid_mut(1));
             drop(ptr);
             key.os.set(ptr::null_mut());
+        }) {
+            rtabort!("thread local panicked on drop");
         }
     }
 }
diff --git a/library/std/src/thread/local/tests.rs b/library/std/src/thread/local/tests.rs
index 80dc4c038d6..964c7fc5b0c 100644
--- a/library/std/src/thread/local/tests.rs
+++ b/library/std/src/thread/local/tests.rs
@@ -23,11 +23,11 @@ impl Signal {
     }
 }
 
-struct Foo(Signal);
+struct NotifyOnDrop(Signal);
 
-impl Drop for Foo {
+impl Drop for NotifyOnDrop {
     fn drop(&mut self) {
-        let Foo(ref f) = *self;
+        let NotifyOnDrop(ref f) = *self;
         f.notify();
     }
 }
@@ -82,18 +82,18 @@ fn states() {
 
 #[test]
 fn smoke_dtor() {
-    thread_local!(static FOO: UnsafeCell<Option<Foo>> = UnsafeCell::new(None));
+    thread_local!(static FOO: UnsafeCell<Option<NotifyOnDrop>> = UnsafeCell::new(None));
     run(&FOO);
-    thread_local!(static FOO2: UnsafeCell<Option<Foo>> = const { UnsafeCell::new(None) });
+    thread_local!(static FOO2: UnsafeCell<Option<NotifyOnDrop>> = const { UnsafeCell::new(None) });
     run(&FOO2);
 
-    fn run(key: &'static LocalKey<UnsafeCell<Option<Foo>>>) {
+    fn run(key: &'static LocalKey<UnsafeCell<Option<NotifyOnDrop>>>) {
         let signal = Signal::default();
         let signal2 = signal.clone();
         let t = thread::spawn(move || unsafe {
             let mut signal = Some(signal2);
             key.with(|f| {
-                *f.get() = Some(Foo(signal.take().unwrap()));
+                *f.get() = Some(NotifyOnDrop(signal.take().unwrap()));
             });
         });
         signal.wait();
@@ -187,13 +187,13 @@ fn self_referential() {
 fn dtors_in_dtors_in_dtors() {
     struct S1(Signal);
     thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
-    thread_local!(static K2: UnsafeCell<Option<Foo>> = UnsafeCell::new(None));
+    thread_local!(static K2: UnsafeCell<Option<NotifyOnDrop>> = UnsafeCell::new(None));
 
     impl Drop for S1 {
         fn drop(&mut self) {
             let S1(ref signal) = *self;
             unsafe {
-                let _ = K2.try_with(|s| *s.get() = Some(Foo(signal.clone())));
+                let _ = K2.try_with(|s| *s.get() = Some(NotifyOnDrop(signal.clone())));
             }
         }
     }
@@ -211,13 +211,13 @@ fn dtors_in_dtors_in_dtors() {
 fn dtors_in_dtors_in_dtors_const_init() {
     struct S1(Signal);
     thread_local!(static K1: UnsafeCell<Option<S1>> = const { UnsafeCell::new(None) });
-    thread_local!(static K2: UnsafeCell<Option<Foo>> = const { UnsafeCell::new(None) });
+    thread_local!(static K2: UnsafeCell<Option<NotifyOnDrop>> = const { UnsafeCell::new(None) });
 
     impl Drop for S1 {
         fn drop(&mut self) {
             let S1(ref signal) = *self;
             unsafe {
-                let _ = K2.try_with(|s| *s.get() = Some(Foo(signal.clone())));
+                let _ = K2.try_with(|s| *s.get() = Some(NotifyOnDrop(signal.clone())));
             }
         }
     }
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 34bdb8bd461..7acda8e98f1 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -173,7 +173,7 @@ use crate::sync::Arc;
 use crate::sys::thread as imp;
 use crate::sys_common::thread;
 use crate::sys_common::thread_info;
-use crate::sys_common::thread_parker::Parker;
+use crate::sys_common::thread_parking::Parker;
 use crate::sys_common::{AsInner, IntoInner};
 use crate::time::Duration;
 
@@ -1216,7 +1216,7 @@ impl Thread {
             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(addr_of_mut!((*ptr).parker));
+            Parker::new_in_place(addr_of_mut!((*ptr).parker));
             Pin::new_unchecked(arc.assume_init())
         };