about summary refs log tree commit diff
path: root/library/std/src/sys
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys')
-rw-r--r--library/std/src/sys/backtrace.rs100
-rw-r--r--library/std/src/sys/fs/unix.rs1
-rw-r--r--library/std/src/sys/net/connection/socket/windows.rs36
-rw-r--r--library/std/src/sys/net/connection/uefi/mod.rs41
-rw-r--r--library/std/src/sys/net/connection/uefi/tcp.rs13
-rw-r--r--library/std/src/sys/net/connection/uefi/tcp4.rs68
-rw-r--r--library/std/src/sys/pal/sgx/abi/usercalls/mod.rs4
-rw-r--r--library/std/src/sys/pal/unix/thread.rs2
-rw-r--r--library/std/src/sys/pal/windows/c.rs69
-rw-r--r--library/std/src/sys/process/unix/common.rs9
-rw-r--r--library/std/src/sys/process/unix/common/tests.rs58
-rw-r--r--library/std/src/sys/process/unix/unix.rs14
-rw-r--r--library/std/src/sys/random/mod.rs2
-rw-r--r--library/std/src/sys/sync/once/futex.rs10
-rw-r--r--library/std/src/sys/sync/once/queue.rs11
15 files changed, 277 insertions, 161 deletions
diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs
index efa6a896dad..272d0fa4d1a 100644
--- a/library/std/src/sys/backtrace.rs
+++ b/library/std/src/sys/backtrace.rs
@@ -68,61 +68,67 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
                 return false;
             }
 
-            let mut hit = false;
-            backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
-                hit = true;
-
-                // `__rust_end_short_backtrace` means we are done hiding symbols
-                // for now. Print until we see `__rust_begin_short_backtrace`.
-                if print_fmt == PrintFmt::Short {
-                    if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
-                        if sym.contains("__rust_end_short_backtrace") {
-                            print = true;
-                            return;
-                        }
-                        if print && sym.contains("__rust_begin_short_backtrace") {
-                            print = false;
-                            return;
-                        }
-                        if !print {
-                            omitted_count += 1;
+            if cfg!(feature = "backtrace-trace-only") {
+                const HEX_WIDTH: usize = 2 + 2 * size_of::<usize>();
+                let frame_ip = frame.ip();
+                res = writeln!(bt_fmt.formatter(), "{idx:4}: {frame_ip:HEX_WIDTH$?}");
+            } else {
+                let mut hit = false;
+                backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
+                    hit = true;
+
+                    // `__rust_end_short_backtrace` means we are done hiding symbols
+                    // for now. Print until we see `__rust_begin_short_backtrace`.
+                    if print_fmt == PrintFmt::Short {
+                        if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
+                            if sym.contains("__rust_end_short_backtrace") {
+                                print = true;
+                                return;
+                            }
+                            if print && sym.contains("__rust_begin_short_backtrace") {
+                                print = false;
+                                return;
+                            }
+                            if !print {
+                                omitted_count += 1;
+                            }
                         }
                     }
-                }
 
-                if print {
-                    if omitted_count > 0 {
-                        debug_assert!(print_fmt == PrintFmt::Short);
-                        // only print the message between the middle of frames
-                        if !first_omit {
-                            let _ = writeln!(
-                                bt_fmt.formatter(),
-                                "      [... omitted {} frame{} ...]",
-                                omitted_count,
-                                if omitted_count > 1 { "s" } else { "" }
-                            );
+                    if print {
+                        if omitted_count > 0 {
+                            debug_assert!(print_fmt == PrintFmt::Short);
+                            // only print the message between the middle of frames
+                            if !first_omit {
+                                let _ = writeln!(
+                                    bt_fmt.formatter(),
+                                    "      [... omitted {} frame{} ...]",
+                                    omitted_count,
+                                    if omitted_count > 1 { "s" } else { "" }
+                                );
+                            }
+                            first_omit = false;
+                            omitted_count = 0;
                         }
-                        first_omit = false;
-                        omitted_count = 0;
+                        res = bt_fmt.frame().symbol(frame, symbol);
                     }
-                    res = bt_fmt.frame().symbol(frame, symbol);
+                });
+                #[cfg(target_os = "nto")]
+                if libc::__my_thread_exit as *mut libc::c_void == frame.ip() {
+                    if !hit && print {
+                        use crate::backtrace_rs::SymbolName;
+                        res = bt_fmt.frame().print_raw(
+                            frame.ip(),
+                            Some(SymbolName::new("__my_thread_exit".as_bytes())),
+                            None,
+                            None,
+                        );
+                    }
+                    return false;
                 }
-            });
-            #[cfg(target_os = "nto")]
-            if libc::__my_thread_exit as *mut libc::c_void == frame.ip() {
                 if !hit && print {
-                    use crate::backtrace_rs::SymbolName;
-                    res = bt_fmt.frame().print_raw(
-                        frame.ip(),
-                        Some(SymbolName::new("__my_thread_exit".as_bytes())),
-                        None,
-                        None,
-                    );
+                    res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
                 }
-                return false;
-            }
-            if !hit && print {
-                res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
             }
 
             idx += 1;
diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs
index dc278274f00..b310db2dac4 100644
--- a/library/std/src/sys/fs/unix.rs
+++ b/library/std/src/sys/fs/unix.rs
@@ -1491,7 +1491,6 @@ impl File {
             target_os = "redox",
             target_os = "espidf",
             target_os = "horizon",
-            target_os = "vxworks",
             target_os = "nuttx",
         )))]
         let to_timespec = |time: Option<SystemTime>| match time {
diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs
index ce975bb2289..b71d8b1357b 100644
--- a/library/std/src/sys/net/connection/socket/windows.rs
+++ b/library/std/src/sys/net/connection/socket/windows.rs
@@ -8,7 +8,8 @@ use crate::net::{Shutdown, SocketAddr};
 use crate::os::windows::io::{
     AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket,
 };
-use crate::sync::OnceLock;
+use crate::sync::atomic::Atomic;
+use crate::sync::atomic::Ordering::{AcqRel, Relaxed};
 use crate::sys::c;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::time::Duration;
@@ -114,33 +115,38 @@ pub(super) mod netc {
 #[expect(missing_debug_implementations)]
 pub struct Socket(OwnedSocket);
 
-static WSA_CLEANUP: OnceLock<unsafe extern "system" fn() -> i32> = OnceLock::new();
+static WSA_INITIALIZED: Atomic<bool> = Atomic::<bool>::new(false);
 
 /// Checks whether the Windows socket interface has been started already, and
 /// if not, starts it.
+#[inline]
 pub fn init() {
-    let _ = WSA_CLEANUP.get_or_init(|| unsafe {
+    if !WSA_INITIALIZED.load(Relaxed) {
+        wsa_startup();
+    }
+}
+
+#[cold]
+fn wsa_startup() {
+    unsafe {
         let mut data: c::WSADATA = mem::zeroed();
         let ret = c::WSAStartup(
             0x202, // version 2.2
             &mut data,
         );
         assert_eq!(ret, 0);
-
-        // Only register `WSACleanup` if `WSAStartup` is actually ever called.
-        // Workaround to prevent linking to `WS2_32.dll` when no network functionality is used.
-        // See issue #85441.
-        c::WSACleanup
-    });
+        if WSA_INITIALIZED.swap(true, AcqRel) {
+            // If another thread raced with us and called WSAStartup first then call
+            // WSACleanup so it's as though WSAStartup was only called once.
+            c::WSACleanup();
+        }
+    }
 }
 
 pub fn cleanup() {
-    // only perform cleanup if network functionality was actually initialized
-    if let Some(cleanup) = WSA_CLEANUP.get() {
-        unsafe {
-            cleanup();
-        }
-    }
+    // We don't need to call WSACleanup here because exiting the process will cause
+    // the OS to clean everything for us, which is faster than doing it manually.
+    // See #141799.
 }
 
 /// Returns the last error from the Windows socket interface.
diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs
index 6835ba44ee2..884cbd4ac1d 100644
--- a/library/std/src/sys/net/connection/uefi/mod.rs
+++ b/library/std/src/sys/net/connection/uefi/mod.rs
@@ -1,37 +1,54 @@
 use crate::fmt;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
+use crate::sync::{Arc, Mutex};
 use crate::sys::unsupported;
 use crate::time::Duration;
 
 mod tcp;
 pub(crate) mod tcp4;
 
-pub struct TcpStream(tcp::Tcp);
+pub struct TcpStream {
+    inner: tcp::Tcp,
+    read_timeout: Arc<Mutex<Option<Duration>>>,
+    write_timeout: Arc<Mutex<Option<Duration>>>,
+}
 
 impl TcpStream {
     pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
-        tcp::Tcp::connect(addr?).map(Self)
+        let inner = tcp::Tcp::connect(addr?, None)?;
+        Ok(Self {
+            inner,
+            read_timeout: Arc::new(Mutex::new(None)),
+            write_timeout: Arc::new(Mutex::new(None)),
+        })
     }
 
-    pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
-        unsupported()
+    pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
+        let inner = tcp::Tcp::connect(addr, Some(timeout))?;
+        Ok(Self {
+            inner,
+            read_timeout: Arc::new(Mutex::new(None)),
+            write_timeout: Arc::new(Mutex::new(None)),
+        })
     }
 
-    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-        unsupported()
+    pub fn set_read_timeout(&self, t: Option<Duration>) -> io::Result<()> {
+        self.read_timeout.set(t).unwrap();
+        Ok(())
     }
 
-    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-        unsupported()
+    pub fn set_write_timeout(&self, t: Option<Duration>) -> io::Result<()> {
+        self.write_timeout.set(t).unwrap();
+        Ok(())
     }
 
     pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
-        unsupported()
+        Ok(self.read_timeout.get_cloned().unwrap())
     }
 
     pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
-        unsupported()
+        Ok(self.write_timeout.get_cloned().unwrap())
     }
 
     pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
@@ -39,7 +56,7 @@ impl TcpStream {
     }
 
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
-        self.0.read(buf)
+        self.inner.read(buf, self.read_timeout()?)
     }
 
     pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
@@ -56,7 +73,7 @@ impl TcpStream {
     }
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
-        self.0.write(buf)
+        self.inner.write(buf, self.write_timeout()?)
     }
 
     pub fn write_vectored(&self, buf: &[IoSlice<'_>]) -> io::Result<usize> {
diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs
index 55b6dbf2490..1152f69446e 100644
--- a/library/std/src/sys/net/connection/uefi/tcp.rs
+++ b/library/std/src/sys/net/connection/uefi/tcp.rs
@@ -1,33 +1,34 @@
 use super::tcp4;
 use crate::io;
 use crate::net::SocketAddr;
+use crate::time::Duration;
 
 pub(crate) enum Tcp {
     V4(tcp4::Tcp4),
 }
 
 impl Tcp {
-    pub(crate) fn connect(addr: &SocketAddr) -> io::Result<Self> {
+    pub(crate) fn connect(addr: &SocketAddr, timeout: Option<Duration>) -> io::Result<Self> {
         match addr {
             SocketAddr::V4(x) => {
                 let temp = tcp4::Tcp4::new()?;
                 temp.configure(true, Some(x), None)?;
-                temp.connect()?;
+                temp.connect(timeout)?;
                 Ok(Tcp::V4(temp))
             }
             SocketAddr::V6(_) => todo!(),
         }
     }
 
-    pub(crate) fn write(&self, buf: &[u8]) -> io::Result<usize> {
+    pub(crate) fn write(&self, buf: &[u8], timeout: Option<Duration>) -> io::Result<usize> {
         match self {
-            Self::V4(client) => client.write(buf),
+            Self::V4(client) => client.write(buf, timeout),
         }
     }
 
-    pub(crate) fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+    pub(crate) fn read(&self, buf: &mut [u8], timeout: Option<Duration>) -> io::Result<usize> {
         match self {
-            Self::V4(client) => client.read(buf),
+            Self::V4(client) => client.read(buf, timeout),
         }
     }
 }
diff --git a/library/std/src/sys/net/connection/uefi/tcp4.rs b/library/std/src/sys/net/connection/uefi/tcp4.rs
index af1ba2be47a..6342718929a 100644
--- a/library/std/src/sys/net/connection/uefi/tcp4.rs
+++ b/library/std/src/sys/net/connection/uefi/tcp4.rs
@@ -6,6 +6,7 @@ use crate::net::SocketAddrV4;
 use crate::ptr::NonNull;
 use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sys::pal::helpers;
+use crate::time::{Duration, Instant};
 
 const TYPE_OF_SERVICE: u8 = 8;
 const TIME_TO_LIVE: u8 = 255;
@@ -66,7 +67,7 @@ impl Tcp4 {
         if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
     }
 
-    pub(crate) fn connect(&self) -> io::Result<()> {
+    pub(crate) fn connect(&self, timeout: Option<Duration>) -> io::Result<()> {
         let evt = unsafe { self.create_evt() }?;
         let completion_token =
             tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS };
@@ -79,7 +80,7 @@ impl Tcp4 {
             return Err(io::Error::from_raw_os_error(r.as_usize()));
         }
 
-        self.wait_for_flag();
+        unsafe { self.wait_or_cancel(timeout, &mut conn_token.completion_token) }?;
 
         if completion_token.status.is_error() {
             Err(io::Error::from_raw_os_error(completion_token.status.as_usize()))
@@ -88,7 +89,7 @@ impl Tcp4 {
         }
     }
 
-    pub(crate) fn write(&self, buf: &[u8]) -> io::Result<usize> {
+    pub(crate) fn write(&self, buf: &[u8], timeout: Option<Duration>) -> io::Result<usize> {
         let evt = unsafe { self.create_evt() }?;
         let completion_token =
             tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS };
@@ -119,7 +120,7 @@ impl Tcp4 {
             return Err(io::Error::from_raw_os_error(r.as_usize()));
         }
 
-        self.wait_for_flag();
+        unsafe { self.wait_or_cancel(timeout, &mut token.completion_token) }?;
 
         if completion_token.status.is_error() {
             Err(io::Error::from_raw_os_error(completion_token.status.as_usize()))
@@ -128,7 +129,7 @@ impl Tcp4 {
         }
     }
 
-    pub(crate) fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+    pub(crate) fn read(&self, buf: &mut [u8], timeout: Option<Duration>) -> io::Result<usize> {
         let evt = unsafe { self.create_evt() }?;
         let completion_token =
             tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS };
@@ -158,7 +159,7 @@ impl Tcp4 {
             return Err(io::Error::from_raw_os_error(r.as_usize()));
         }
 
-        self.wait_for_flag();
+        unsafe { self.wait_or_cancel(timeout, &mut token.completion_token) }?;
 
         if completion_token.status.is_error() {
             Err(io::Error::from_raw_os_error(completion_token.status.as_usize()))
@@ -167,6 +168,50 @@ impl Tcp4 {
         }
     }
 
+    /// Wait for an event to finish. This is checked by an atomic boolean that is supposed to be set
+    /// to true in the event callback.
+    ///
+    /// Optionally, allow specifying a timeout.
+    ///
+    /// If a timeout is provided, the operation (specified by its `EFI_TCP4_COMPLETION_TOKEN`) is
+    /// canceled and Error of kind TimedOut is returned.
+    ///
+    /// # SAFETY
+    ///
+    /// Pointer to a valid `EFI_TCP4_COMPLETION_TOKEN`
+    unsafe fn wait_or_cancel(
+        &self,
+        timeout: Option<Duration>,
+        token: *mut tcp4::CompletionToken,
+    ) -> io::Result<()> {
+        if !self.wait_for_flag(timeout) {
+            let _ = unsafe { self.cancel(token) };
+            return Err(io::Error::new(io::ErrorKind::TimedOut, "Operation Timed out"));
+        }
+
+        Ok(())
+    }
+
+    /// Abort an asynchronous connection, listen, transmission or receive request.
+    ///
+    /// If token is NULL, then all pending tokens issued by EFI_TCP4_PROTOCOL.Connect(),
+    /// EFI_TCP4_PROTOCOL.Accept(), EFI_TCP4_PROTOCOL.Transmit() or EFI_TCP4_PROTOCOL.Receive() are
+    /// aborted.
+    ///
+    /// # SAFETY
+    ///
+    /// Pointer to a valid `EFI_TCP4_COMPLETION_TOKEN` or NULL
+    unsafe fn cancel(&self, token: *mut tcp4::CompletionToken) -> io::Result<()> {
+        let protocol = self.protocol.as_ptr();
+
+        let r = unsafe { ((*protocol).cancel)(protocol, token) };
+        if r.is_error() {
+            return Err(io::Error::from_raw_os_error(r.as_usize()));
+        } else {
+            Ok(())
+        }
+    }
+
     unsafe fn create_evt(&self) -> io::Result<helpers::OwnedEvent> {
         self.flag.store(false, Ordering::Relaxed);
         helpers::OwnedEvent::new(
@@ -177,10 +222,19 @@ impl Tcp4 {
         )
     }
 
-    fn wait_for_flag(&self) {
+    fn wait_for_flag(&self, timeout: Option<Duration>) -> bool {
+        let start = Instant::now();
+
         while !self.flag.load(Ordering::Relaxed) {
             let _ = self.poll();
+            if let Some(t) = timeout {
+                if Instant::now().duration_since(start) >= t {
+                    return false;
+                }
+            }
         }
+
+        true
     }
 
     fn poll(&self) -> io::Result<()> {
diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs
index cbdaf439b28..dea44124f45 100644
--- a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs
+++ b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs
@@ -2,7 +2,7 @@ use crate::cmp;
 use crate::io::{
     BorrowedCursor, Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult,
 };
-use crate::random::{DefaultRandomSource, Random};
+use crate::random::random;
 use crate::time::{Duration, Instant};
 
 pub(crate) mod alloc;
@@ -179,7 +179,7 @@ pub fn wait(event_mask: u64, mut timeout: u64) -> IoResult<u64> {
         // trusted to ensure accurate timeouts.
         if let Ok(timeout_signed) = i64::try_from(timeout) {
             let tenth = timeout_signed / 10;
-            let deviation = i64::random(&mut DefaultRandomSource).checked_rem(tenth).unwrap_or(0);
+            let deviation = random::<i64>(..).checked_rem(tenth).unwrap_or(0);
             timeout = timeout_signed.saturating_add(deviation) as _;
         }
     }
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index 53f0d1eeda5..e4f5520d8a3 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -222,7 +222,7 @@ impl Thread {
 
     #[cfg(target_os = "vxworks")]
     pub fn set_name(name: &CStr) {
-        let mut name = truncate_cstr::<{ libc::VX_TASK_RENAME_LENGTH - 1 }>(name);
+        let mut name = truncate_cstr::<{ (libc::VX_TASK_RENAME_LENGTH - 1) as usize }>(name);
         let res = unsafe { libc::taskNameSet(libc::taskIdSelf(), name.as_mut_ptr()) };
         debug_assert_eq!(res, libc::OK);
     }
diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
index eee169d410a..edac5262a4e 100644
--- a/library/std/src/sys/pal/windows/c.rs
+++ b/library/std/src/sys/pal/windows/c.rs
@@ -197,7 +197,7 @@ compat_fn_optional! {
     pub fn WakeByAddressSingle(address: *const c_void);
 }
 
-#[cfg(any(target_vendor = "win7", target_vendor = "uwp"))]
+#[cfg(any(target_vendor = "win7"))]
 compat_fn_with_fallback! {
     pub static NTDLL: &CStr = c"ntdll";
 
@@ -228,65 +228,14 @@ compat_fn_with_fallback! {
     ) -> NTSTATUS {
         panic!("keyed events not available")
     }
+}
 
-    // These functions are available on UWP when lazily loaded. They will fail WACK if loaded statically.
-    #[cfg(target_vendor = "uwp")]
-    pub fn NtCreateFile(
-        filehandle: *mut HANDLE,
-        desiredaccess: FILE_ACCESS_RIGHTS,
-        objectattributes: *const OBJECT_ATTRIBUTES,
-        iostatusblock: *mut IO_STATUS_BLOCK,
-        allocationsize: *const i64,
-        fileattributes: FILE_FLAGS_AND_ATTRIBUTES,
-        shareaccess: FILE_SHARE_MODE,
-        createdisposition: NTCREATEFILE_CREATE_DISPOSITION,
-        createoptions: NTCREATEFILE_CREATE_OPTIONS,
-        eabuffer: *const c_void,
-        ealength: u32
-    ) -> NTSTATUS {
-        STATUS_NOT_IMPLEMENTED
-    }
-    #[cfg(target_vendor = "uwp")]
-    pub fn NtOpenFile(
-        filehandle: *mut HANDLE,
-        desiredaccess: u32,
-        objectattributes: *const OBJECT_ATTRIBUTES,
-        iostatusblock: *mut IO_STATUS_BLOCK,
-        shareaccess: u32,
-        openoptions: u32
-    ) -> NTSTATUS {
-        STATUS_NOT_IMPLEMENTED
-    }
-    #[cfg(target_vendor = "uwp")]
-    pub fn NtReadFile(
-        filehandle: HANDLE,
-        event: HANDLE,
-        apcroutine: PIO_APC_ROUTINE,
-        apccontext: *const c_void,
-        iostatusblock: *mut IO_STATUS_BLOCK,
-        buffer: *mut c_void,
-        length: u32,
-        byteoffset: *const i64,
-        key: *const u32
-    ) -> NTSTATUS {
-        STATUS_NOT_IMPLEMENTED
-    }
-    #[cfg(target_vendor = "uwp")]
-    pub fn NtWriteFile(
-        filehandle: HANDLE,
-        event: HANDLE,
-        apcroutine: PIO_APC_ROUTINE,
-        apccontext: *const c_void,
-        iostatusblock: *mut IO_STATUS_BLOCK,
-        buffer: *const c_void,
-        length: u32,
-        byteoffset: *const i64,
-        key: *const u32
-    ) -> NTSTATUS {
-        STATUS_NOT_IMPLEMENTED
-    }
-    #[cfg(target_vendor = "uwp")]
-    pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> u32 {
-        Status as u32
+cfg_if::cfg_if! {
+    if #[cfg(target_vendor = "uwp")] {
+        windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS);
+        windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtOpenFile(filehandle : *mut HANDLE, desiredaccess : u32, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, shareaccess : u32, openoptions : u32) -> NTSTATUS);
+        windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
+        windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
+        windows_targets::link_raw_dylib!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32);
     }
 }
diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs
index b6777b76668..6219be60caf 100644
--- a/library/std/src/sys/process/unix/common.rs
+++ b/library/std/src/sys/process/unix/common.rs
@@ -98,6 +98,7 @@ pub struct Command {
     #[cfg(target_os = "linux")]
     create_pidfd: bool,
     pgroup: Option<pid_t>,
+    setsid: bool,
 }
 
 // passed back to std::process with the pipes connected to the child, if any
@@ -185,6 +186,7 @@ impl Command {
             #[cfg(target_os = "linux")]
             create_pidfd: false,
             pgroup: None,
+            setsid: false,
         }
     }
 
@@ -220,6 +222,9 @@ impl Command {
             self.cwd(&OsStr::new("/"));
         }
     }
+    pub fn setsid(&mut self, setsid: bool) {
+        self.setsid = setsid;
+    }
 
     #[cfg(target_os = "linux")]
     pub fn create_pidfd(&mut self, val: bool) {
@@ -298,6 +303,10 @@ impl Command {
     pub fn get_chroot(&self) -> Option<&CStr> {
         self.chroot.as_deref()
     }
+    #[allow(dead_code)]
+    pub fn get_setsid(&self) -> bool {
+        self.setsid
+    }
 
     pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
         &mut self.closures
diff --git a/library/std/src/sys/process/unix/common/tests.rs b/library/std/src/sys/process/unix/common/tests.rs
index e5c8dd6e341..5f71bf051f8 100644
--- a/library/std/src/sys/process/unix/common/tests.rs
+++ b/library/std/src/sys/process/unix/common/tests.rs
@@ -135,6 +135,64 @@ fn test_process_group_no_posix_spawn() {
 }
 
 #[test]
+#[cfg_attr(
+    any(
+        // See test_process_mask
+        target_os = "macos",
+        target_arch = "arm",
+        target_arch = "aarch64",
+        target_arch = "riscv64",
+    ),
+    ignore
+)]
+fn test_setsid_posix_spawn() {
+    // Spawn a cat subprocess that's just going to hang since there is no I/O.
+    let mut cmd = Command::new(OsStr::new("cat"));
+    cmd.setsid(true);
+    cmd.stdin(Stdio::MakePipe);
+    cmd.stdout(Stdio::MakePipe);
+    let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true));
+
+    unsafe {
+        // Setsid will create a new session and process group, so check that
+        // we can kill the process group, which means there *is* one.
+        t!(cvt(libc::kill(-(cat.id() as libc::pid_t), libc::SIGINT)));
+
+        t!(cat.wait());
+    }
+}
+
+#[test]
+#[cfg_attr(
+    any(
+        // See test_process_mask
+        target_os = "macos",
+        target_arch = "arm",
+        target_arch = "aarch64",
+        target_arch = "riscv64",
+    ),
+    ignore
+)]
+fn test_setsid_no_posix_spawn() {
+    let mut cmd = Command::new(OsStr::new("cat"));
+    cmd.setsid(true);
+    cmd.stdin(Stdio::MakePipe);
+    cmd.stdout(Stdio::MakePipe);
+
+    unsafe {
+        // Same as above, create hang-y cat. This time, force using the non-posix_spawn path.
+        cmd.pre_exec(Box::new(|| Ok(()))); // pre_exec forces fork + exec rather than posix spawn.
+        let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true));
+
+        // Setsid will create a new session and process group, so check that
+        // we can kill the process group, which means there *is* one.
+        t!(cvt(libc::kill(-(cat.id() as libc::pid_t), libc::SIGINT)));
+
+        t!(cat.wait());
+    }
+}
+
+#[test]
 fn test_program_kind() {
     let vectors = &[
         ("foo", ProgramKind::PathLookup),
diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs
index bbd03e2b0c4..5d13d6da185 100644
--- a/library/std/src/sys/process/unix/unix.rs
+++ b/library/std/src/sys/process/unix/unix.rs
@@ -340,6 +340,10 @@ impl Command {
             cvt(libc::setpgid(0, pgroup))?;
         }
 
+        if self.get_setsid() {
+            cvt(libc::setsid())?;
+        }
+
         // emscripten has no signal support.
         #[cfg(not(target_os = "emscripten"))]
         {
@@ -741,6 +745,16 @@ impl Command {
                 flags |= libc::POSIX_SPAWN_SETSIGDEF;
             }
 
+            if self.get_setsid() {
+                cfg_if::cfg_if! {
+                    if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
+                        flags |= libc::POSIX_SPAWN_SETSID;
+                    } else {
+                        return Ok(None);
+                    }
+                }
+            }
+
             cvt_nz(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?;
 
             // Make sure we synchronize access to the global `environ` resource
diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs
index 013e886a99b..fc85797dcc2 100644
--- a/library/std/src/sys/random/mod.rs
+++ b/library/std/src/sys/random/mod.rs
@@ -20,6 +20,7 @@ cfg_if::cfg_if! {
         target_os = "rtems",
         target_os = "solaris",
         target_os = "vita",
+        target_os = "nuttx",
     ))] {
         mod arc4random;
         pub use arc4random::fill_bytes;
@@ -44,7 +45,6 @@ cfg_if::cfg_if! {
         target_os = "hurd",
         target_os = "l4re",
         target_os = "nto",
-        target_os = "nuttx",
     ))] {
         mod unix_legacy;
         pub use unix_legacy::fill_bytes;
diff --git a/library/std/src/sys/sync/once/futex.rs b/library/std/src/sys/sync/once/futex.rs
index 539f0fe89ea..407fdcebcf5 100644
--- a/library/std/src/sys/sync/once/futex.rs
+++ b/library/std/src/sys/sync/once/futex.rs
@@ -8,16 +8,18 @@ use crate::sys::futex::{Futex, Primitive, futex_wait, futex_wake_all};
 // This means we only need one atomic value with 4 states:
 
 /// No initialization has run yet, and no thread is currently using the Once.
-const INCOMPLETE: Primitive = 0;
+const INCOMPLETE: Primitive = 3;
 /// Some thread has previously attempted to initialize the Once, but it panicked,
 /// so the Once is now poisoned. There are no other threads currently accessing
 /// this Once.
-const POISONED: Primitive = 1;
+const POISONED: Primitive = 2;
 /// Some thread is currently attempting to run initialization. It may succeed,
 /// so all future threads need to wait for it to finish.
-const RUNNING: Primitive = 2;
+const RUNNING: Primitive = 1;
 /// Initialization has completed and all future calls should finish immediately.
-const COMPLETE: Primitive = 3;
+/// By choosing this state as the all-zero state the `is_completed` check can be
+/// a bit faster on some platforms.
+const COMPLETE: Primitive = 0;
 
 // An additional bit indicates whether there are waiting threads:
 
diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs
index 6a2ab0dcf1b..49e15d65f25 100644
--- a/library/std/src/sys/sync/once/queue.rs
+++ b/library/std/src/sys/sync/once/queue.rs
@@ -74,11 +74,12 @@ pub struct OnceState {
 }
 
 // Four states that a Once can be in, encoded into the lower bits of
-// `state_and_queue` in the Once structure.
-const INCOMPLETE: usize = 0x0;
-const POISONED: usize = 0x1;
-const RUNNING: usize = 0x2;
-const COMPLETE: usize = 0x3;
+// `state_and_queue` in the Once structure. By choosing COMPLETE as the all-zero
+// state the `is_completed` check can be a bit faster on some platforms.
+const INCOMPLETE: usize = 0x3;
+const POISONED: usize = 0x2;
+const RUNNING: usize = 0x1;
+const COMPLETE: usize = 0x0;
 
 // Mask to learn about the state. All other bits are the queue of waiters if
 // this is in the RUNNING state.