about summary refs log tree commit diff
path: root/library/std/src/sys/pal
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys/pal')
-rw-r--r--library/std/src/sys/pal/hermit/mod.rs2
-rw-r--r--library/std/src/sys/pal/sgx/mod.rs2
-rw-r--r--library/std/src/sys/pal/solid/mod.rs2
-rw-r--r--library/std/src/sys/pal/teeos/mod.rs2
-rw-r--r--library/std/src/sys/pal/uefi/mod.rs1
-rw-r--r--library/std/src/sys/pal/uefi/process.rs786
-rw-r--r--library/std/src/sys/pal/unix/fuchsia.rs (renamed from library/std/src/sys/pal/unix/process/zircon.rs)0
-rw-r--r--library/std/src/sys/pal/unix/mod.rs5
-rw-r--r--library/std/src/sys/pal/unix/process/mod.rs27
-rw-r--r--library/std/src/sys/pal/unix/process/process_common.rs674
-rw-r--r--library/std/src/sys/pal/unix/process/process_common/tests.rs192
-rw-r--r--library/std/src/sys/pal/unix/process/process_fuchsia.rs326
-rw-r--r--library/std/src/sys/pal/unix/process/process_unix.rs1270
-rw-r--r--library/std/src/sys/pal/unix/process/process_unix/tests.rs75
-rw-r--r--library/std/src/sys/pal/unix/process/process_unsupported.rs72
-rw-r--r--library/std/src/sys/pal/unix/process/process_unsupported/wait_status.rs83
-rw-r--r--library/std/src/sys/pal/unix/process/process_unsupported/wait_status/tests.rs36
-rw-r--r--library/std/src/sys/pal/unix/process/process_vxworks.rs268
-rw-r--r--library/std/src/sys/pal/unsupported/mod.rs1
-rw-r--r--library/std/src/sys/pal/unsupported/process.rs322
-rw-r--r--library/std/src/sys/pal/wasi/mod.rs2
-rw-r--r--library/std/src/sys/pal/wasip2/mod.rs2
-rw-r--r--library/std/src/sys/pal/wasm/mod.rs2
-rw-r--r--library/std/src/sys/pal/windows/args.rs2
-rw-r--r--library/std/src/sys/pal/windows/mod.rs9
-rw-r--r--library/std/src/sys/pal/windows/process.rs929
-rw-r--r--library/std/src/sys/pal/windows/process/tests.rs223
-rw-r--r--library/std/src/sys/pal/xous/mod.rs2
-rw-r--r--library/std/src/sys/pal/zkvm/mod.rs2
29 files changed, 12 insertions, 5307 deletions
diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs
index 608245bd430..67eab96fa40 100644
--- a/library/std/src/sys/pal/hermit/mod.rs
+++ b/library/std/src/sys/pal/hermit/mod.rs
@@ -25,8 +25,6 @@ pub mod futex;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-#[path = "../unsupported/process.rs"]
-pub mod process;
 pub mod thread;
 pub mod time;
 
diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs
index bb419c2530e..fe43cfd2caf 100644
--- a/library/std/src/sys/pal/sgx/mod.rs
+++ b/library/std/src/sys/pal/sgx/mod.rs
@@ -16,8 +16,6 @@ mod libunwind_integration;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-#[path = "../unsupported/process.rs"]
-pub mod process;
 pub mod thread;
 pub mod thread_parking;
 pub mod time;
diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs
index e4a61fdcfe3..22052a168fd 100644
--- a/library/std/src/sys/pal/solid/mod.rs
+++ b/library/std/src/sys/pal/solid/mod.rs
@@ -25,8 +25,6 @@ pub(crate) mod error;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-#[path = "../unsupported/process.rs"]
-pub mod process;
 pub use self::itron::{thread, thread_parking};
 pub mod time;
 
diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs
index 41b25121592..c1921a2f40d 100644
--- a/library/std/src/sys/pal/teeos/mod.rs
+++ b/library/std/src/sys/pal/teeos/mod.rs
@@ -14,8 +14,6 @@ pub mod env;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-#[path = "../unsupported/process.rs"]
-pub mod process;
 pub mod thread;
 #[allow(non_upper_case_globals)]
 #[path = "../unix/time.rs"]
diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs
index 714dc392688..fc12ec63b5c 100644
--- a/library/std/src/sys/pal/uefi/mod.rs
+++ b/library/std/src/sys/pal/uefi/mod.rs
@@ -19,7 +19,6 @@ pub mod helpers;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-pub mod process;
 pub mod thread;
 pub mod time;
 
diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs
deleted file mode 100644
index 1203d51e531..00000000000
--- a/library/std/src/sys/pal/uefi/process.rs
+++ /dev/null
@@ -1,786 +0,0 @@
-use r_efi::protocols::simple_text_output;
-
-use super::helpers;
-use crate::collections::BTreeMap;
-pub use crate::ffi::OsString as EnvKey;
-use crate::ffi::{OsStr, OsString};
-use crate::num::{NonZero, NonZeroI32};
-use crate::path::Path;
-use crate::sys::fs::File;
-use crate::sys::pipe::AnonPipe;
-use crate::sys::unsupported;
-use crate::sys_common::process::{CommandEnv, CommandEnvs};
-use crate::{fmt, io};
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-#[derive(Debug)]
-pub struct Command {
-    prog: OsString,
-    args: Vec<OsString>,
-    stdout: Option<Stdio>,
-    stderr: Option<Stdio>,
-    env: CommandEnv,
-}
-
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
-    pub stdin: Option<AnonPipe>,
-    pub stdout: Option<AnonPipe>,
-    pub stderr: Option<AnonPipe>,
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum Stdio {
-    Inherit,
-    Null,
-    MakePipe,
-}
-
-impl Command {
-    pub fn new(program: &OsStr) -> Command {
-        Command {
-            prog: program.to_os_string(),
-            args: Vec::new(),
-            stdout: None,
-            stderr: None,
-            env: Default::default(),
-        }
-    }
-
-    pub fn arg(&mut self, arg: &OsStr) {
-        self.args.push(arg.to_os_string());
-    }
-
-    pub fn env_mut(&mut self) -> &mut CommandEnv {
-        &mut self.env
-    }
-
-    pub fn cwd(&mut self, _dir: &OsStr) {
-        panic!("unsupported")
-    }
-
-    pub fn stdin(&mut self, _stdin: Stdio) {
-        panic!("unsupported")
-    }
-
-    pub fn stdout(&mut self, stdout: Stdio) {
-        self.stdout = Some(stdout);
-    }
-
-    pub fn stderr(&mut self, stderr: Stdio) {
-        self.stderr = Some(stderr);
-    }
-
-    pub fn get_program(&self) -> &OsStr {
-        self.prog.as_ref()
-    }
-
-    pub fn get_args(&self) -> CommandArgs<'_> {
-        CommandArgs { iter: self.args.iter() }
-    }
-
-    pub fn get_envs(&self) -> CommandEnvs<'_> {
-        self.env.iter()
-    }
-
-    pub fn get_current_dir(&self) -> Option<&Path> {
-        None
-    }
-
-    pub fn spawn(
-        &mut self,
-        _default: Stdio,
-        _needs_stdin: bool,
-    ) -> io::Result<(Process, StdioPipes)> {
-        unsupported()
-    }
-
-    fn create_pipe(
-        s: Stdio,
-    ) -> io::Result<Option<helpers::OwnedProtocol<uefi_command_internal::PipeProtocol>>> {
-        match s {
-            Stdio::MakePipe => unsafe {
-                helpers::OwnedProtocol::create(
-                    uefi_command_internal::PipeProtocol::new(),
-                    simple_text_output::PROTOCOL_GUID,
-                )
-            }
-            .map(Some),
-            Stdio::Null => unsafe {
-                helpers::OwnedProtocol::create(
-                    uefi_command_internal::PipeProtocol::null(),
-                    simple_text_output::PROTOCOL_GUID,
-                )
-            }
-            .map(Some),
-            Stdio::Inherit => Ok(None),
-        }
-    }
-
-    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
-        let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;
-
-        // UEFI adds the bin name by default
-        if !self.args.is_empty() {
-            let args = uefi_command_internal::create_args(&self.prog, &self.args);
-            cmd.set_args(args);
-        }
-
-        // Setup Stdout
-        let stdout = self.stdout.unwrap_or(Stdio::MakePipe);
-        let stdout = Self::create_pipe(stdout)?;
-        if let Some(con) = stdout {
-            cmd.stdout_init(con)
-        } else {
-            cmd.stdout_inherit()
-        };
-
-        // Setup Stderr
-        let stderr = self.stderr.unwrap_or(Stdio::MakePipe);
-        let stderr = Self::create_pipe(stderr)?;
-        if let Some(con) = stderr {
-            cmd.stderr_init(con)
-        } else {
-            cmd.stderr_inherit()
-        };
-
-        let env = env_changes(&self.env);
-
-        // Set any new vars
-        if let Some(e) = &env {
-            for (k, (_, v)) in e {
-                match v {
-                    Some(v) => unsafe { crate::env::set_var(k, v) },
-                    None => unsafe { crate::env::remove_var(k) },
-                }
-            }
-        }
-
-        let stat = cmd.start_image()?;
-
-        // Rollback any env changes
-        if let Some(e) = env {
-            for (k, (v, _)) in e {
-                match v {
-                    Some(v) => unsafe { crate::env::set_var(k, v) },
-                    None => unsafe { crate::env::remove_var(k) },
-                }
-            }
-        }
-
-        let stdout = cmd.stdout()?;
-        let stderr = cmd.stderr()?;
-
-        Ok((ExitStatus(stat), stdout, stderr))
-    }
-}
-
-impl From<AnonPipe> for Stdio {
-    fn from(pipe: AnonPipe) -> Stdio {
-        pipe.diverge()
-    }
-}
-
-impl From<io::Stdout> for Stdio {
-    fn from(_: io::Stdout) -> Stdio {
-        // FIXME: This is wrong.
-        // Instead, the Stdio we have here should be a unit struct.
-        panic!("unsupported")
-    }
-}
-
-impl From<io::Stderr> for Stdio {
-    fn from(_: io::Stderr) -> Stdio {
-        // FIXME: This is wrong.
-        // Instead, the Stdio we have here should be a unit struct.
-        panic!("unsupported")
-    }
-}
-
-impl From<File> for Stdio {
-    fn from(_file: File) -> Stdio {
-        // FIXME: This is wrong.
-        // Instead, the Stdio we have here should be a unit struct.
-        panic!("unsupported")
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-#[non_exhaustive]
-pub struct ExitStatus(r_efi::efi::Status);
-
-impl ExitStatus {
-    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
-        if self.0 == r_efi::efi::Status::SUCCESS { Ok(()) } else { Err(ExitStatusError(self.0)) }
-    }
-
-    pub fn code(&self) -> Option<i32> {
-        Some(self.0.as_usize() as i32)
-    }
-}
-
-impl fmt::Display for ExitStatus {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let err_str = super::os::error_string(self.0.as_usize());
-        write!(f, "{}", err_str)
-    }
-}
-
-impl Default for ExitStatus {
-    fn default() -> Self {
-        ExitStatus(r_efi::efi::Status::SUCCESS)
-    }
-}
-
-#[derive(Clone, Copy, PartialEq, Eq)]
-pub struct ExitStatusError(r_efi::efi::Status);
-
-impl fmt::Debug for ExitStatusError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let err_str = super::os::error_string(self.0.as_usize());
-        write!(f, "{}", err_str)
-    }
-}
-
-impl Into<ExitStatus> for ExitStatusError {
-    fn into(self) -> ExitStatus {
-        ExitStatus(self.0)
-    }
-}
-
-impl ExitStatusError {
-    pub fn code(self) -> Option<NonZero<i32>> {
-        NonZeroI32::new(self.0.as_usize() as i32)
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitCode(bool);
-
-impl ExitCode {
-    pub const SUCCESS: ExitCode = ExitCode(false);
-    pub const FAILURE: ExitCode = ExitCode(true);
-
-    pub fn as_i32(&self) -> i32 {
-        self.0 as i32
-    }
-}
-
-impl From<u8> for ExitCode {
-    fn from(code: u8) -> Self {
-        match code {
-            0 => Self::SUCCESS,
-            1..=255 => Self::FAILURE,
-        }
-    }
-}
-
-pub struct Process(!);
-
-impl Process {
-    pub fn id(&self) -> u32 {
-        self.0
-    }
-
-    pub fn kill(&mut self) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn wait(&mut self) -> io::Result<ExitStatus> {
-        self.0
-    }
-
-    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
-        self.0
-    }
-}
-
-pub struct CommandArgs<'a> {
-    iter: crate::slice::Iter<'a, OsString>,
-}
-
-impl<'a> Iterator for CommandArgs<'a> {
-    type Item = &'a OsStr;
-
-    fn next(&mut self) -> Option<&'a OsStr> {
-        self.iter.next().map(|x| x.as_ref())
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-}
-
-impl<'a> ExactSizeIterator for CommandArgs<'a> {
-    fn len(&self) -> usize {
-        self.iter.len()
-    }
-
-    fn is_empty(&self) -> bool {
-        self.iter.is_empty()
-    }
-}
-
-impl<'a> fmt::Debug for CommandArgs<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_list().entries(self.iter.clone()).finish()
-    }
-}
-
-#[allow(dead_code)]
-mod uefi_command_internal {
-    use r_efi::protocols::{loaded_image, simple_text_output};
-
-    use super::super::helpers;
-    use crate::ffi::{OsStr, OsString};
-    use crate::io::{self, const_error};
-    use crate::mem::MaybeUninit;
-    use crate::os::uefi::env::{boot_services, image_handle, system_table};
-    use crate::os::uefi::ffi::{OsStrExt, OsStringExt};
-    use crate::ptr::NonNull;
-    use crate::slice;
-    use crate::sys::pal::uefi::helpers::OwnedTable;
-    use crate::sys_common::wstr::WStrUnits;
-
-    pub struct Image {
-        handle: NonNull<crate::ffi::c_void>,
-        stdout: Option<helpers::OwnedProtocol<PipeProtocol>>,
-        stderr: Option<helpers::OwnedProtocol<PipeProtocol>>,
-        st: OwnedTable<r_efi::efi::SystemTable>,
-        args: Option<(*mut u16, usize)>,
-    }
-
-    impl Image {
-        pub fn load_image(p: &OsStr) -> io::Result<Self> {
-            let path = helpers::OwnedDevicePath::from_text(p)?;
-            let boot_services: NonNull<r_efi::efi::BootServices> = boot_services()
-                .ok_or_else(|| const_error!(io::ErrorKind::NotFound, "Boot Services not found"))?
-                .cast();
-            let mut child_handle: MaybeUninit<r_efi::efi::Handle> = MaybeUninit::uninit();
-            let image_handle = image_handle();
-
-            let r = unsafe {
-                ((*boot_services.as_ptr()).load_image)(
-                    r_efi::efi::Boolean::FALSE,
-                    image_handle.as_ptr(),
-                    path.as_ptr(),
-                    crate::ptr::null_mut(),
-                    0,
-                    child_handle.as_mut_ptr(),
-                )
-            };
-
-            if r.is_error() {
-                Err(io::Error::from_raw_os_error(r.as_usize()))
-            } else {
-                let child_handle = unsafe { child_handle.assume_init() };
-                let child_handle = NonNull::new(child_handle).unwrap();
-
-                let loaded_image: NonNull<loaded_image::Protocol> =
-                    helpers::open_protocol(child_handle, loaded_image::PROTOCOL_GUID).unwrap();
-                let st = OwnedTable::from_table(unsafe { (*loaded_image.as_ptr()).system_table });
-
-                Ok(Self { handle: child_handle, stdout: None, stderr: None, st, args: None })
-            }
-        }
-
-        pub(crate) fn start_image(&mut self) -> io::Result<r_efi::efi::Status> {
-            self.update_st_crc32()?;
-
-            // Use our system table instead of the default one
-            let loaded_image: NonNull<loaded_image::Protocol> =
-                helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap();
-            unsafe {
-                (*loaded_image.as_ptr()).system_table = self.st.as_mut_ptr();
-            }
-
-            let boot_services: NonNull<r_efi::efi::BootServices> = boot_services()
-                .ok_or_else(|| const_error!(io::ErrorKind::NotFound, "Boot Services not found"))?
-                .cast();
-            let mut exit_data_size: usize = 0;
-            let mut exit_data: MaybeUninit<*mut u16> = MaybeUninit::uninit();
-
-            let r = unsafe {
-                ((*boot_services.as_ptr()).start_image)(
-                    self.handle.as_ptr(),
-                    &mut exit_data_size,
-                    exit_data.as_mut_ptr(),
-                )
-            };
-
-            // Drop exitdata
-            if exit_data_size != 0 {
-                unsafe {
-                    let exit_data = exit_data.assume_init();
-                    ((*boot_services.as_ptr()).free_pool)(exit_data as *mut crate::ffi::c_void);
-                }
-            }
-
-            Ok(r)
-        }
-
-        fn set_stdout(
-            &mut self,
-            handle: r_efi::efi::Handle,
-            protocol: *mut simple_text_output::Protocol,
-        ) {
-            unsafe {
-                (*self.st.as_mut_ptr()).console_out_handle = handle;
-                (*self.st.as_mut_ptr()).con_out = protocol;
-            }
-        }
-
-        fn set_stderr(
-            &mut self,
-            handle: r_efi::efi::Handle,
-            protocol: *mut simple_text_output::Protocol,
-        ) {
-            unsafe {
-                (*self.st.as_mut_ptr()).standard_error_handle = handle;
-                (*self.st.as_mut_ptr()).std_err = protocol;
-            }
-        }
-
-        pub fn stdout_init(&mut self, protocol: helpers::OwnedProtocol<PipeProtocol>) {
-            self.set_stdout(
-                protocol.handle().as_ptr(),
-                protocol.as_ref() as *const PipeProtocol as *mut simple_text_output::Protocol,
-            );
-            self.stdout = Some(protocol);
-        }
-
-        pub fn stdout_inherit(&mut self) {
-            let st: NonNull<r_efi::efi::SystemTable> = system_table().cast();
-            unsafe { self.set_stdout((*st.as_ptr()).console_out_handle, (*st.as_ptr()).con_out) }
-        }
-
-        pub fn stderr_init(&mut self, protocol: helpers::OwnedProtocol<PipeProtocol>) {
-            self.set_stderr(
-                protocol.handle().as_ptr(),
-                protocol.as_ref() as *const PipeProtocol as *mut simple_text_output::Protocol,
-            );
-            self.stderr = Some(protocol);
-        }
-
-        pub fn stderr_inherit(&mut self) {
-            let st: NonNull<r_efi::efi::SystemTable> = system_table().cast();
-            unsafe { self.set_stderr((*st.as_ptr()).standard_error_handle, (*st.as_ptr()).std_err) }
-        }
-
-        pub fn stderr(&self) -> io::Result<Vec<u8>> {
-            match &self.stderr {
-                Some(stderr) => stderr.as_ref().utf8(),
-                None => Ok(Vec::new()),
-            }
-        }
-
-        pub fn stdout(&self) -> io::Result<Vec<u8>> {
-            match &self.stdout {
-                Some(stdout) => stdout.as_ref().utf8(),
-                None => Ok(Vec::new()),
-            }
-        }
-
-        pub fn set_args(&mut self, args: Box<[u16]>) {
-            let loaded_image: NonNull<loaded_image::Protocol> =
-                helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap();
-
-            let len = args.len();
-            let args_size: u32 = (len * size_of::<u16>()).try_into().unwrap();
-            let ptr = Box::into_raw(args).as_mut_ptr();
-
-            unsafe {
-                (*loaded_image.as_ptr()).load_options = ptr as *mut crate::ffi::c_void;
-                (*loaded_image.as_ptr()).load_options_size = args_size;
-            }
-
-            self.args = Some((ptr, len));
-        }
-
-        fn update_st_crc32(&mut self) -> io::Result<()> {
-            let bt: NonNull<r_efi::efi::BootServices> = boot_services().unwrap().cast();
-            let st_size = unsafe { (*self.st.as_ptr()).hdr.header_size as usize };
-            let mut crc32: u32 = 0;
-
-            // Set crc to 0 before calculation
-            unsafe {
-                (*self.st.as_mut_ptr()).hdr.crc32 = 0;
-            }
-
-            let r = unsafe {
-                ((*bt.as_ptr()).calculate_crc32)(
-                    self.st.as_mut_ptr() as *mut crate::ffi::c_void,
-                    st_size,
-                    &mut crc32,
-                )
-            };
-
-            if r.is_error() {
-                Err(io::Error::from_raw_os_error(r.as_usize()))
-            } else {
-                unsafe {
-                    (*self.st.as_mut_ptr()).hdr.crc32 = crc32;
-                }
-                Ok(())
-            }
-        }
-    }
-
-    impl Drop for Image {
-        fn drop(&mut self) {
-            if let Some(bt) = boot_services() {
-                let bt: NonNull<r_efi::efi::BootServices> = bt.cast();
-                unsafe {
-                    ((*bt.as_ptr()).unload_image)(self.handle.as_ptr());
-                }
-            }
-
-            if let Some((ptr, len)) = self.args {
-                let _ = unsafe { Box::from_raw(crate::ptr::slice_from_raw_parts_mut(ptr, len)) };
-            }
-        }
-    }
-
-    #[repr(C)]
-    pub struct PipeProtocol {
-        reset: simple_text_output::ProtocolReset,
-        output_string: simple_text_output::ProtocolOutputString,
-        test_string: simple_text_output::ProtocolTestString,
-        query_mode: simple_text_output::ProtocolQueryMode,
-        set_mode: simple_text_output::ProtocolSetMode,
-        set_attribute: simple_text_output::ProtocolSetAttribute,
-        clear_screen: simple_text_output::ProtocolClearScreen,
-        set_cursor_position: simple_text_output::ProtocolSetCursorPosition,
-        enable_cursor: simple_text_output::ProtocolEnableCursor,
-        mode: *mut simple_text_output::Mode,
-        _buffer: Vec<u16>,
-    }
-
-    impl PipeProtocol {
-        pub fn new() -> Self {
-            let mode = Box::new(simple_text_output::Mode {
-                max_mode: 0,
-                mode: 0,
-                attribute: 0,
-                cursor_column: 0,
-                cursor_row: 0,
-                cursor_visible: r_efi::efi::Boolean::FALSE,
-            });
-            Self {
-                reset: Self::reset,
-                output_string: Self::output_string,
-                test_string: Self::test_string,
-                query_mode: Self::query_mode,
-                set_mode: Self::set_mode,
-                set_attribute: Self::set_attribute,
-                clear_screen: Self::clear_screen,
-                set_cursor_position: Self::set_cursor_position,
-                enable_cursor: Self::enable_cursor,
-                mode: Box::into_raw(mode),
-                _buffer: Vec::new(),
-            }
-        }
-
-        pub fn null() -> Self {
-            let mode = Box::new(simple_text_output::Mode {
-                max_mode: 0,
-                mode: 0,
-                attribute: 0,
-                cursor_column: 0,
-                cursor_row: 0,
-                cursor_visible: r_efi::efi::Boolean::FALSE,
-            });
-            Self {
-                reset: Self::reset_null,
-                output_string: Self::output_string_null,
-                test_string: Self::test_string,
-                query_mode: Self::query_mode,
-                set_mode: Self::set_mode,
-                set_attribute: Self::set_attribute,
-                clear_screen: Self::clear_screen,
-                set_cursor_position: Self::set_cursor_position,
-                enable_cursor: Self::enable_cursor,
-                mode: Box::into_raw(mode),
-                _buffer: Vec::new(),
-            }
-        }
-
-        pub fn utf8(&self) -> io::Result<Vec<u8>> {
-            OsString::from_wide(&self._buffer)
-                .into_string()
-                .map(Into::into)
-                .map_err(|_| const_error!(io::ErrorKind::Other, "UTF-8 conversion failed"))
-        }
-
-        extern "efiapi" fn reset(
-            proto: *mut simple_text_output::Protocol,
-            _: r_efi::efi::Boolean,
-        ) -> r_efi::efi::Status {
-            let proto: *mut PipeProtocol = proto.cast();
-            unsafe {
-                (*proto)._buffer.clear();
-            }
-            r_efi::efi::Status::SUCCESS
-        }
-
-        extern "efiapi" fn reset_null(
-            _: *mut simple_text_output::Protocol,
-            _: r_efi::efi::Boolean,
-        ) -> r_efi::efi::Status {
-            r_efi::efi::Status::SUCCESS
-        }
-
-        extern "efiapi" fn output_string(
-            proto: *mut simple_text_output::Protocol,
-            buf: *mut r_efi::efi::Char16,
-        ) -> r_efi::efi::Status {
-            let proto: *mut PipeProtocol = proto.cast();
-            let buf_len = unsafe {
-                if let Some(x) = WStrUnits::new(buf) {
-                    x.count()
-                } else {
-                    return r_efi::efi::Status::INVALID_PARAMETER;
-                }
-            };
-            let buf_slice = unsafe { slice::from_raw_parts(buf, buf_len) };
-
-            unsafe {
-                (*proto)._buffer.extend_from_slice(buf_slice);
-            };
-
-            r_efi::efi::Status::SUCCESS
-        }
-
-        extern "efiapi" fn output_string_null(
-            _: *mut simple_text_output::Protocol,
-            _: *mut r_efi::efi::Char16,
-        ) -> r_efi::efi::Status {
-            r_efi::efi::Status::SUCCESS
-        }
-
-        extern "efiapi" fn test_string(
-            _: *mut simple_text_output::Protocol,
-            _: *mut r_efi::efi::Char16,
-        ) -> r_efi::efi::Status {
-            r_efi::efi::Status::SUCCESS
-        }
-
-        extern "efiapi" fn query_mode(
-            _: *mut simple_text_output::Protocol,
-            _: usize,
-            _: *mut usize,
-            _: *mut usize,
-        ) -> r_efi::efi::Status {
-            r_efi::efi::Status::UNSUPPORTED
-        }
-
-        extern "efiapi" fn set_mode(
-            _: *mut simple_text_output::Protocol,
-            _: usize,
-        ) -> r_efi::efi::Status {
-            r_efi::efi::Status::UNSUPPORTED
-        }
-
-        extern "efiapi" fn set_attribute(
-            _: *mut simple_text_output::Protocol,
-            _: usize,
-        ) -> r_efi::efi::Status {
-            r_efi::efi::Status::UNSUPPORTED
-        }
-
-        extern "efiapi" fn clear_screen(
-            _: *mut simple_text_output::Protocol,
-        ) -> r_efi::efi::Status {
-            r_efi::efi::Status::UNSUPPORTED
-        }
-
-        extern "efiapi" fn set_cursor_position(
-            _: *mut simple_text_output::Protocol,
-            _: usize,
-            _: usize,
-        ) -> r_efi::efi::Status {
-            r_efi::efi::Status::UNSUPPORTED
-        }
-
-        extern "efiapi" fn enable_cursor(
-            _: *mut simple_text_output::Protocol,
-            _: r_efi::efi::Boolean,
-        ) -> r_efi::efi::Status {
-            r_efi::efi::Status::UNSUPPORTED
-        }
-    }
-
-    impl Drop for PipeProtocol {
-        fn drop(&mut self) {
-            unsafe {
-                let _ = Box::from_raw(self.mode);
-            }
-        }
-    }
-
-    pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> {
-        const QUOTE: u16 = 0x0022;
-        const SPACE: u16 = 0x0020;
-        const CARET: u16 = 0x005e;
-        const NULL: u16 = 0;
-
-        // This is the lower bound on the final length under the assumption that
-        // the arguments only contain ASCII characters.
-        let mut res = Vec::with_capacity(args.iter().map(|arg| arg.len() + 3).sum());
-
-        // Wrap program name in quotes to avoid any problems
-        res.push(QUOTE);
-        res.extend(prog.encode_wide());
-        res.push(QUOTE);
-
-        for arg in args {
-            res.push(SPACE);
-
-            // Wrap the argument in quotes to be treat as single arg
-            res.push(QUOTE);
-            for c in arg.encode_wide() {
-                // CARET in quotes is used to escape CARET or QUOTE
-                if c == QUOTE || c == CARET {
-                    res.push(CARET);
-                }
-                res.push(c);
-            }
-            res.push(QUOTE);
-        }
-
-        res.into_boxed_slice()
-    }
-}
-
-/// Create a map of environment variable changes. Allows efficient setting and rolling back of
-/// environment variable changes.
-///
-/// Entry: (Old Value, New Value)
-fn env_changes(env: &CommandEnv) -> Option<BTreeMap<EnvKey, (Option<OsString>, Option<OsString>)>> {
-    if env.is_unchanged() {
-        return None;
-    }
-
-    let mut result = BTreeMap::<EnvKey, (Option<OsString>, Option<OsString>)>::new();
-
-    // Check if we want to clear all prior variables
-    if env.does_clear() {
-        for (k, v) in crate::env::vars_os() {
-            result.insert(k.into(), (Some(v), None));
-        }
-    }
-
-    for (k, v) in env.iter() {
-        let v: Option<OsString> = v.map(Into::into);
-        result
-            .entry(k.into())
-            .and_modify(|cur| *cur = (cur.0.clone(), v.clone()))
-            .or_insert((crate::env::var_os(k), v));
-    }
-
-    Some(result)
-}
diff --git a/library/std/src/sys/pal/unix/process/zircon.rs b/library/std/src/sys/pal/unix/fuchsia.rs
index 7932bd26d76..7932bd26d76 100644
--- a/library/std/src/sys/pal/unix/process/zircon.rs
+++ b/library/std/src/sys/pal/unix/fuchsia.rs
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index e2e537b7bd3..413fda1d8d8 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -9,6 +9,8 @@ pub mod weak;
 pub mod args;
 pub mod env;
 pub mod fd;
+#[cfg(target_os = "fuchsia")]
+pub mod fuchsia;
 pub mod futex;
 #[cfg(any(target_os = "linux", target_os = "android"))]
 pub mod kernel_copy;
@@ -16,7 +18,6 @@ pub mod kernel_copy;
 pub mod linux;
 pub mod os;
 pub mod pipe;
-pub mod process;
 pub mod stack_overflow;
 pub mod sync;
 pub mod thread;
@@ -419,7 +420,7 @@ cfg_if::cfg_if! {
 }
 
 #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))]
-mod unsupported {
+pub mod unsupported {
     use crate::io;
 
     pub fn unsupported<T>() -> io::Result<T> {
diff --git a/library/std/src/sys/pal/unix/process/mod.rs b/library/std/src/sys/pal/unix/process/mod.rs
deleted file mode 100644
index 2751d51c44d..00000000000
--- a/library/std/src/sys/pal/unix/process/mod.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes};
-pub use self::process_inner::{ExitStatus, ExitStatusError, Process};
-pub use crate::ffi::OsString as EnvKey;
-
-#[cfg_attr(any(target_os = "espidf", target_os = "horizon", target_os = "nuttx"), allow(unused))]
-mod process_common;
-
-#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))]
-mod process_unsupported;
-
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "fuchsia")] {
-        #[path = "process_fuchsia.rs"]
-        mod process_inner;
-        mod zircon;
-    } else if #[cfg(target_os = "vxworks")] {
-        #[path = "process_vxworks.rs"]
-        mod process_inner;
-    } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] {
-        mod process_inner {
-            pub use super::process_unsupported::*;
-        }
-    } else {
-        #[path = "process_unix.rs"]
-        mod process_inner;
-    }
-}
diff --git a/library/std/src/sys/pal/unix/process/process_common.rs b/library/std/src/sys/pal/unix/process/process_common.rs
deleted file mode 100644
index a1c747c8df4..00000000000
--- a/library/std/src/sys/pal/unix/process/process_common.rs
+++ /dev/null
@@ -1,674 +0,0 @@
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod tests;
-
-use libc::{EXIT_FAILURE, EXIT_SUCCESS, c_char, c_int, gid_t, pid_t, uid_t};
-
-use crate::collections::BTreeMap;
-use crate::ffi::{CStr, CString, OsStr, OsString};
-use crate::os::unix::prelude::*;
-use crate::path::Path;
-use crate::sys::fd::FileDesc;
-use crate::sys::fs::File;
-#[cfg(not(target_os = "fuchsia"))]
-use crate::sys::fs::OpenOptions;
-use crate::sys::pipe::{self, AnonPipe};
-use crate::sys_common::process::{CommandEnv, CommandEnvs};
-use crate::sys_common::{FromInner, IntoInner};
-use crate::{fmt, io, ptr};
-
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "fuchsia")] {
-        // fuchsia doesn't have /dev/null
-    } else if #[cfg(target_os = "vxworks")] {
-        const DEV_NULL: &CStr = c"/null";
-    } else {
-        const DEV_NULL: &CStr = c"/dev/null";
-    }
-}
-
-// Android with api less than 21 define sig* functions inline, so it is not
-// available for dynamic link. Implementing sigemptyset and sigaddset allow us
-// to support older Android version (independent of libc version).
-// The following implementations are based on
-// https://github.com/aosp-mirror/platform_bionic/blob/ad8dcd6023294b646e5a8288c0ed431b0845da49/libc/include/android/legacy_signal_inlines.h
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "android")] {
-        #[allow(dead_code)]
-        pub unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int {
-            set.write_bytes(0u8, 1);
-            return 0;
-        }
-
-        #[allow(dead_code)]
-        pub unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int {
-            use crate::slice;
-            use libc::{c_ulong, sigset_t};
-
-            // The implementations from bionic (android libc) type pun `sigset_t` as an
-            // array of `c_ulong`. This works, but lets add a smoke check to make sure
-            // that doesn't change.
-            const _: () = assert!(
-                align_of::<c_ulong>() == align_of::<sigset_t>()
-                    && (size_of::<sigset_t>() % size_of::<c_ulong>()) == 0
-            );
-
-            let bit = (signum - 1) as usize;
-            if set.is_null() || bit >= (8 * size_of::<sigset_t>()) {
-                crate::sys::pal::unix::os::set_errno(libc::EINVAL);
-                return -1;
-            }
-            let raw = slice::from_raw_parts_mut(
-                set as *mut c_ulong,
-                size_of::<sigset_t>() / size_of::<c_ulong>(),
-            );
-            const LONG_BIT: usize = size_of::<c_ulong>() * 8;
-            raw[bit / LONG_BIT] |= 1 << (bit % LONG_BIT);
-            return 0;
-        }
-    } else {
-        #[allow(unused_imports)]
-        pub use libc::{sigemptyset, sigaddset};
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-pub struct Command {
-    program: CString,
-    args: Vec<CString>,
-    /// Exactly what will be passed to `execvp`.
-    ///
-    /// First element is a pointer to `program`, followed by pointers to
-    /// `args`, followed by a `null`. Be careful when modifying `program` or
-    /// `args` to properly update this as well.
-    argv: Argv,
-    env: CommandEnv,
-
-    program_kind: ProgramKind,
-    cwd: Option<CString>,
-    uid: Option<uid_t>,
-    gid: Option<gid_t>,
-    saw_nul: bool,
-    closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
-    groups: Option<Box<[gid_t]>>,
-    stdin: Option<Stdio>,
-    stdout: Option<Stdio>,
-    stderr: Option<Stdio>,
-    #[cfg(target_os = "linux")]
-    create_pidfd: bool,
-    pgroup: Option<pid_t>,
-}
-
-// Create a new type for argv, so that we can make it `Send` and `Sync`
-struct Argv(Vec<*const c_char>);
-
-// It is safe to make `Argv` `Send` and `Sync`, because it contains
-// pointers to memory owned by `Command.args`
-unsafe impl Send for Argv {}
-unsafe impl Sync for Argv {}
-
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
-    pub stdin: Option<AnonPipe>,
-    pub stdout: Option<AnonPipe>,
-    pub stderr: Option<AnonPipe>,
-}
-
-// passed to do_exec() with configuration of what the child stdio should look
-// like
-#[cfg_attr(target_os = "vita", allow(dead_code))]
-pub struct ChildPipes {
-    pub stdin: ChildStdio,
-    pub stdout: ChildStdio,
-    pub stderr: ChildStdio,
-}
-
-pub enum ChildStdio {
-    Inherit,
-    Explicit(c_int),
-    Owned(FileDesc),
-
-    // On Fuchsia, null stdio is the default, so we simply don't specify
-    // any actions at the time of spawning.
-    #[cfg(target_os = "fuchsia")]
-    Null,
-}
-
-#[derive(Debug)]
-pub enum Stdio {
-    Inherit,
-    Null,
-    MakePipe,
-    Fd(FileDesc),
-    StaticFd(BorrowedFd<'static>),
-}
-
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub enum ProgramKind {
-    /// A program that would be looked up on the PATH (e.g. `ls`)
-    PathLookup,
-    /// A relative path (e.g. `my-dir/foo`, `../foo`, `./foo`)
-    Relative,
-    /// An absolute path.
-    Absolute,
-}
-
-impl ProgramKind {
-    fn new(program: &OsStr) -> Self {
-        if program.as_encoded_bytes().starts_with(b"/") {
-            Self::Absolute
-        } else if program.as_encoded_bytes().contains(&b'/') {
-            // If the program has more than one component in it, it is a relative path.
-            Self::Relative
-        } else {
-            Self::PathLookup
-        }
-    }
-}
-
-impl Command {
-    #[cfg(not(target_os = "linux"))]
-    pub fn new(program: &OsStr) -> Command {
-        let mut saw_nul = false;
-        let program_kind = ProgramKind::new(program.as_ref());
-        let program = os2c(program, &mut saw_nul);
-        Command {
-            argv: Argv(vec![program.as_ptr(), ptr::null()]),
-            args: vec![program.clone()],
-            program,
-            program_kind,
-            env: Default::default(),
-            cwd: None,
-            uid: None,
-            gid: None,
-            saw_nul,
-            closures: Vec::new(),
-            groups: None,
-            stdin: None,
-            stdout: None,
-            stderr: None,
-            pgroup: None,
-        }
-    }
-
-    #[cfg(target_os = "linux")]
-    pub fn new(program: &OsStr) -> Command {
-        let mut saw_nul = false;
-        let program_kind = ProgramKind::new(program.as_ref());
-        let program = os2c(program, &mut saw_nul);
-        Command {
-            argv: Argv(vec![program.as_ptr(), ptr::null()]),
-            args: vec![program.clone()],
-            program,
-            program_kind,
-            env: Default::default(),
-            cwd: None,
-            uid: None,
-            gid: None,
-            saw_nul,
-            closures: Vec::new(),
-            groups: None,
-            stdin: None,
-            stdout: None,
-            stderr: None,
-            create_pidfd: false,
-            pgroup: None,
-        }
-    }
-
-    pub fn set_arg_0(&mut self, arg: &OsStr) {
-        // Set a new arg0
-        let arg = os2c(arg, &mut self.saw_nul);
-        debug_assert!(self.argv.0.len() > 1);
-        self.argv.0[0] = arg.as_ptr();
-        self.args[0] = arg;
-    }
-
-    pub fn arg(&mut self, arg: &OsStr) {
-        // Overwrite the trailing null pointer in `argv` and then add a new null
-        // pointer.
-        let arg = os2c(arg, &mut self.saw_nul);
-        self.argv.0[self.args.len()] = arg.as_ptr();
-        self.argv.0.push(ptr::null());
-
-        // Also make sure we keep track of the owned value to schedule a
-        // destructor for this memory.
-        self.args.push(arg);
-    }
-
-    pub fn cwd(&mut self, dir: &OsStr) {
-        self.cwd = Some(os2c(dir, &mut self.saw_nul));
-    }
-    pub fn uid(&mut self, id: uid_t) {
-        self.uid = Some(id);
-    }
-    pub fn gid(&mut self, id: gid_t) {
-        self.gid = Some(id);
-    }
-    pub fn groups(&mut self, groups: &[gid_t]) {
-        self.groups = Some(Box::from(groups));
-    }
-    pub fn pgroup(&mut self, pgroup: pid_t) {
-        self.pgroup = Some(pgroup);
-    }
-
-    #[cfg(target_os = "linux")]
-    pub fn create_pidfd(&mut self, val: bool) {
-        self.create_pidfd = val;
-    }
-
-    #[cfg(not(target_os = "linux"))]
-    #[allow(dead_code)]
-    pub fn get_create_pidfd(&self) -> bool {
-        false
-    }
-
-    #[cfg(target_os = "linux")]
-    pub fn get_create_pidfd(&self) -> bool {
-        self.create_pidfd
-    }
-
-    pub fn saw_nul(&self) -> bool {
-        self.saw_nul
-    }
-
-    pub fn get_program(&self) -> &OsStr {
-        OsStr::from_bytes(self.program.as_bytes())
-    }
-
-    #[allow(dead_code)]
-    pub fn get_program_kind(&self) -> ProgramKind {
-        self.program_kind
-    }
-
-    pub fn get_args(&self) -> CommandArgs<'_> {
-        let mut iter = self.args.iter();
-        iter.next();
-        CommandArgs { iter }
-    }
-
-    pub fn get_envs(&self) -> CommandEnvs<'_> {
-        self.env.iter()
-    }
-
-    pub fn get_current_dir(&self) -> Option<&Path> {
-        self.cwd.as_ref().map(|cs| Path::new(OsStr::from_bytes(cs.as_bytes())))
-    }
-
-    pub fn get_argv(&self) -> &Vec<*const c_char> {
-        &self.argv.0
-    }
-
-    pub fn get_program_cstr(&self) -> &CStr {
-        &*self.program
-    }
-
-    #[allow(dead_code)]
-    pub fn get_cwd(&self) -> Option<&CStr> {
-        self.cwd.as_deref()
-    }
-    #[allow(dead_code)]
-    pub fn get_uid(&self) -> Option<uid_t> {
-        self.uid
-    }
-    #[allow(dead_code)]
-    pub fn get_gid(&self) -> Option<gid_t> {
-        self.gid
-    }
-    #[allow(dead_code)]
-    pub fn get_groups(&self) -> Option<&[gid_t]> {
-        self.groups.as_deref()
-    }
-    #[allow(dead_code)]
-    pub fn get_pgroup(&self) -> Option<pid_t> {
-        self.pgroup
-    }
-
-    pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
-        &mut self.closures
-    }
-
-    pub unsafe fn pre_exec(&mut self, f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>) {
-        self.closures.push(f);
-    }
-
-    pub fn stdin(&mut self, stdin: Stdio) {
-        self.stdin = Some(stdin);
-    }
-
-    pub fn stdout(&mut self, stdout: Stdio) {
-        self.stdout = Some(stdout);
-    }
-
-    pub fn stderr(&mut self, stderr: Stdio) {
-        self.stderr = Some(stderr);
-    }
-
-    pub fn env_mut(&mut self) -> &mut CommandEnv {
-        &mut self.env
-    }
-
-    pub fn capture_env(&mut self) -> Option<CStringArray> {
-        let maybe_env = self.env.capture_if_changed();
-        maybe_env.map(|env| construct_envp(env, &mut self.saw_nul))
-    }
-
-    #[allow(dead_code)]
-    pub fn env_saw_path(&self) -> bool {
-        self.env.have_changed_path()
-    }
-
-    #[allow(dead_code)]
-    pub fn program_is_path(&self) -> bool {
-        self.program.to_bytes().contains(&b'/')
-    }
-
-    pub fn setup_io(
-        &self,
-        default: Stdio,
-        needs_stdin: bool,
-    ) -> io::Result<(StdioPipes, ChildPipes)> {
-        let null = Stdio::Null;
-        let default_stdin = if needs_stdin { &default } else { &null };
-        let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
-        let stdout = self.stdout.as_ref().unwrap_or(&default);
-        let stderr = self.stderr.as_ref().unwrap_or(&default);
-        let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
-        let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
-        let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
-        let ours = StdioPipes { stdin: our_stdin, stdout: our_stdout, stderr: our_stderr };
-        let theirs = ChildPipes { stdin: their_stdin, stdout: their_stdout, stderr: their_stderr };
-        Ok((ours, theirs))
-    }
-}
-
-fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
-    CString::new(s.as_bytes()).unwrap_or_else(|_e| {
-        *saw_nul = true;
-        c"<string-with-nul>".to_owned()
-    })
-}
-
-// Helper type to manage ownership of the strings within a C-style array.
-pub struct CStringArray {
-    items: Vec<CString>,
-    ptrs: Vec<*const c_char>,
-}
-
-impl CStringArray {
-    pub fn with_capacity(capacity: usize) -> Self {
-        let mut result = CStringArray {
-            items: Vec::with_capacity(capacity),
-            ptrs: Vec::with_capacity(capacity + 1),
-        };
-        result.ptrs.push(ptr::null());
-        result
-    }
-    pub fn push(&mut self, item: CString) {
-        let l = self.ptrs.len();
-        self.ptrs[l - 1] = item.as_ptr();
-        self.ptrs.push(ptr::null());
-        self.items.push(item);
-    }
-    pub fn as_ptr(&self) -> *const *const c_char {
-        self.ptrs.as_ptr()
-    }
-}
-
-fn construct_envp(env: BTreeMap<OsString, OsString>, saw_nul: &mut bool) -> CStringArray {
-    let mut result = CStringArray::with_capacity(env.len());
-    for (mut k, v) in env {
-        // Reserve additional space for '=' and null terminator
-        k.reserve_exact(v.len() + 2);
-        k.push("=");
-        k.push(&v);
-
-        // Add the new entry into the array
-        if let Ok(item) = CString::new(k.into_vec()) {
-            result.push(item);
-        } else {
-            *saw_nul = true;
-        }
-    }
-
-    result
-}
-
-impl Stdio {
-    pub fn to_child_stdio(&self, readable: bool) -> io::Result<(ChildStdio, Option<AnonPipe>)> {
-        match *self {
-            Stdio::Inherit => Ok((ChildStdio::Inherit, None)),
-
-            // Make sure that the source descriptors are not an stdio
-            // descriptor, otherwise the order which we set the child's
-            // descriptors may blow away a descriptor which we are hoping to
-            // save. For example, suppose we want the child's stderr to be the
-            // parent's stdout, and the child's stdout to be the parent's
-            // stderr. No matter which we dup first, the second will get
-            // overwritten prematurely.
-            Stdio::Fd(ref fd) => {
-                if fd.as_raw_fd() >= 0 && fd.as_raw_fd() <= libc::STDERR_FILENO {
-                    Ok((ChildStdio::Owned(fd.duplicate()?), None))
-                } else {
-                    Ok((ChildStdio::Explicit(fd.as_raw_fd()), None))
-                }
-            }
-
-            Stdio::StaticFd(fd) => {
-                let fd = FileDesc::from_inner(fd.try_clone_to_owned()?);
-                Ok((ChildStdio::Owned(fd), None))
-            }
-
-            Stdio::MakePipe => {
-                let (reader, writer) = pipe::anon_pipe()?;
-                let (ours, theirs) = if readable { (writer, reader) } else { (reader, writer) };
-                Ok((ChildStdio::Owned(theirs.into_inner()), Some(ours)))
-            }
-
-            #[cfg(not(target_os = "fuchsia"))]
-            Stdio::Null => {
-                let mut opts = OpenOptions::new();
-                opts.read(readable);
-                opts.write(!readable);
-                let fd = File::open_c(DEV_NULL, &opts)?;
-                Ok((ChildStdio::Owned(fd.into_inner()), None))
-            }
-
-            #[cfg(target_os = "fuchsia")]
-            Stdio::Null => Ok((ChildStdio::Null, None)),
-        }
-    }
-}
-
-impl From<AnonPipe> for Stdio {
-    fn from(pipe: AnonPipe) -> Stdio {
-        Stdio::Fd(pipe.into_inner())
-    }
-}
-
-impl From<FileDesc> for Stdio {
-    fn from(fd: FileDesc) -> Stdio {
-        Stdio::Fd(fd)
-    }
-}
-
-impl From<File> for Stdio {
-    fn from(file: File) -> Stdio {
-        Stdio::Fd(file.into_inner())
-    }
-}
-
-impl From<io::Stdout> for Stdio {
-    fn from(_: io::Stdout) -> Stdio {
-        // This ought really to be is Stdio::StaticFd(input_argument.as_fd()).
-        // But AsFd::as_fd takes its argument by reference, and yields
-        // a bounded lifetime, so it's no use here. There is no AsStaticFd.
-        //
-        // Additionally AsFd is only implemented for the *locked* versions.
-        // We don't want to lock them here.  (The implications of not locking
-        // are the same as those for process::Stdio::inherit().)
-        //
-        // Arguably the hypothetical AsStaticFd and AsFd<'static>
-        // should be implemented for io::Stdout, not just for StdoutLocked.
-        Stdio::StaticFd(unsafe { BorrowedFd::borrow_raw(libc::STDOUT_FILENO) })
-    }
-}
-
-impl From<io::Stderr> for Stdio {
-    fn from(_: io::Stderr) -> Stdio {
-        Stdio::StaticFd(unsafe { BorrowedFd::borrow_raw(libc::STDERR_FILENO) })
-    }
-}
-
-impl ChildStdio {
-    pub fn fd(&self) -> Option<c_int> {
-        match *self {
-            ChildStdio::Inherit => None,
-            ChildStdio::Explicit(fd) => Some(fd),
-            ChildStdio::Owned(ref fd) => Some(fd.as_raw_fd()),
-
-            #[cfg(target_os = "fuchsia")]
-            ChildStdio::Null => None,
-        }
-    }
-}
-
-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 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);
-            }
-
-            debug_command.finish()
-        } else {
-            if let Some(ref cwd) = self.cwd {
-                write!(f, "cd {cwd:?} && ")?;
-            }
-            if self.env.does_clear() {
-                write!(f, "env -i ")?;
-                // Altered env vars will be printed next, that should exactly work as expected.
-            } else {
-                // Removed env vars need the command to be wrapped in `env`.
-                let mut any_removed = false;
-                for (key, value_opt) in self.get_envs() {
-                    if value_opt.is_none() {
-                        if !any_removed {
-                            write!(f, "env ")?;
-                            any_removed = true;
-                        }
-                        write!(f, "-u {} ", key.to_string_lossy())?;
-                    }
-                }
-            }
-            // Altered env vars can just be added in front of the program.
-            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(())
-        }
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy)]
-pub struct ExitCode(u8);
-
-impl fmt::Debug for ExitCode {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("unix_exit_status").field(&self.0).finish()
-    }
-}
-
-impl ExitCode {
-    pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
-    pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);
-
-    #[inline]
-    pub fn as_i32(&self) -> i32 {
-        self.0 as i32
-    }
-}
-
-impl From<u8> for ExitCode {
-    fn from(code: u8) -> Self {
-        Self(code)
-    }
-}
-
-pub struct CommandArgs<'a> {
-    iter: crate::slice::Iter<'a, CString>,
-}
-
-impl<'a> Iterator for CommandArgs<'a> {
-    type Item = &'a OsStr;
-    fn next(&mut self) -> Option<&'a OsStr> {
-        self.iter.next().map(|cs| OsStr::from_bytes(cs.as_bytes()))
-    }
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-}
-
-impl<'a> ExactSizeIterator for CommandArgs<'a> {
-    fn len(&self) -> usize {
-        self.iter.len()
-    }
-    fn is_empty(&self) -> bool {
-        self.iter.is_empty()
-    }
-}
-
-impl<'a> fmt::Debug for CommandArgs<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_list().entries(self.iter.clone()).finish()
-    }
-}
diff --git a/library/std/src/sys/pal/unix/process/process_common/tests.rs b/library/std/src/sys/pal/unix/process/process_common/tests.rs
deleted file mode 100644
index e5c8dd6e341..00000000000
--- a/library/std/src/sys/pal/unix/process/process_common/tests.rs
+++ /dev/null
@@ -1,192 +0,0 @@
-use super::*;
-use crate::ffi::OsStr;
-use crate::sys::{cvt, cvt_nz};
-use crate::{mem, ptr};
-
-macro_rules! t {
-    ($e:expr) => {
-        match $e {
-            Ok(t) => t,
-            Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
-        }
-    };
-}
-
-#[test]
-#[cfg_attr(
-    any(
-        // See #14232 for more information, but it appears that signal delivery to a
-        // newly spawned process may just be raced in the macOS, so to prevent this
-        // test from being flaky we ignore it on macOS.
-        target_os = "macos",
-        // When run under our current QEMU emulation test suite this test fails,
-        // although the reason isn't very clear as to why. For now this test is
-        // ignored there.
-        target_arch = "arm",
-        target_arch = "aarch64",
-        target_arch = "riscv64",
-    ),
-    ignore
-)]
-fn test_process_mask() {
-    // Test to make sure that a signal mask *does* get inherited.
-    fn test_inner(mut cmd: Command) {
-        unsafe {
-            let mut set = mem::MaybeUninit::<libc::sigset_t>::uninit();
-            let mut old_set = mem::MaybeUninit::<libc::sigset_t>::uninit();
-            t!(cvt(sigemptyset(set.as_mut_ptr())));
-            t!(cvt(sigaddset(set.as_mut_ptr(), libc::SIGINT)));
-            t!(cvt_nz(libc::pthread_sigmask(
-                libc::SIG_SETMASK,
-                set.as_ptr(),
-                old_set.as_mut_ptr()
-            )));
-
-            cmd.stdin(Stdio::MakePipe);
-            cmd.stdout(Stdio::MakePipe);
-
-            let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true));
-            let stdin_write = pipes.stdin.take().unwrap();
-            let stdout_read = pipes.stdout.take().unwrap();
-
-            t!(cvt_nz(libc::pthread_sigmask(libc::SIG_SETMASK, old_set.as_ptr(), ptr::null_mut())));
-
-            t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT)));
-            // We need to wait until SIGINT is definitely delivered. The
-            // easiest way is to write something to cat, and try to read it
-            // back: if SIGINT is unmasked, it'll get delivered when cat is
-            // next scheduled.
-            let _ = stdin_write.write(b"Hello");
-            drop(stdin_write);
-
-            // Exactly 5 bytes should be read.
-            let mut buf = [0; 5];
-            let ret = t!(stdout_read.read(&mut buf));
-            assert_eq!(ret, 5);
-            assert_eq!(&buf, b"Hello");
-
-            t!(cat.wait());
-        }
-    }
-
-    // A plain `Command::new` uses the posix_spawn path on many platforms.
-    let cmd = Command::new(OsStr::new("cat"));
-    test_inner(cmd);
-
-    // Specifying `pre_exec` forces the fork/exec path.
-    let mut cmd = Command::new(OsStr::new("cat"));
-    unsafe { cmd.pre_exec(Box::new(|| Ok(()))) };
-    test_inner(cmd);
-}
-
-#[test]
-#[cfg_attr(
-    any(
-        // See test_process_mask
-        target_os = "macos",
-        target_arch = "arm",
-        target_arch = "aarch64",
-        target_arch = "riscv64",
-    ),
-    ignore
-)]
-fn test_process_group_posix_spawn() {
-    unsafe {
-        // 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.pgroup(0);
-        cmd.stdin(Stdio::MakePipe);
-        cmd.stdout(Stdio::MakePipe);
-        let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true));
-
-        // Check that we can kill its 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_process_group_no_posix_spawn() {
-    unsafe {
-        // Same as above, create hang-y cat. This time, force using the non-posix_spawnp path.
-        let mut cmd = Command::new(OsStr::new("cat"));
-        cmd.pgroup(0);
-        cmd.pre_exec(Box::new(|| Ok(()))); // pre_exec forces fork + exec
-        cmd.stdin(Stdio::MakePipe);
-        cmd.stdout(Stdio::MakePipe);
-        let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true));
-
-        // Check that we can kill its 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),
-        ("foo.out", ProgramKind::PathLookup),
-        ("./foo", ProgramKind::Relative),
-        ("../foo", ProgramKind::Relative),
-        ("dir/foo", ProgramKind::Relative),
-        // Note that paths on Unix can't contain / in them, so this is actually the directory "fo\\"
-        // followed by the file "o".
-        ("fo\\/o", ProgramKind::Relative),
-        ("/foo", ProgramKind::Absolute),
-        ("/dir/../foo", ProgramKind::Absolute),
-    ];
-
-    for (program, expected_kind) in vectors {
-        assert_eq!(
-            ProgramKind::new(program.as_ref()),
-            *expected_kind,
-            "actual != expected program kind for input {program}",
-        );
-    }
-}
-
-// Test that Rust std handles wait status values (`ExitStatus`) the way that Unix does,
-// at least for the values which represent a Unix exit status (`ExitCode`).
-// Should work on every #[cfg(unix)] platform.  However:
-#[cfg(not(any(
-    // Fuchsia is not Unix and has totally broken std::os::unix.
-    // https://github.com/rust-lang/rust/issues/58590#issuecomment-836535609
-    target_os = "fuchsia",
-)))]
-#[test]
-fn unix_exit_statuses() {
-    use crate::num::NonZero;
-    use crate::os::unix::process::ExitStatusExt;
-    use crate::process::*;
-
-    for exit_code in 0..=0xff {
-        // FIXME impl From<ExitCode> for ExitStatus and then test that here too;
-        // the two ExitStatus values should be the same
-        let raw_wait_status = exit_code << 8;
-        let exit_status = ExitStatus::from_raw(raw_wait_status);
-
-        assert_eq!(exit_status.code(), Some(exit_code));
-
-        if let Ok(nz) = NonZero::try_from(exit_code) {
-            assert!(!exit_status.success());
-            let es_error = exit_status.exit_ok().unwrap_err();
-            assert_eq!(es_error.code().unwrap(), i32::from(nz));
-        } else {
-            assert!(exit_status.success());
-            assert_eq!(exit_status.exit_ok(), Ok(()));
-        }
-    }
-}
diff --git a/library/std/src/sys/pal/unix/process/process_fuchsia.rs b/library/std/src/sys/pal/unix/process/process_fuchsia.rs
deleted file mode 100644
index 05c9ace470e..00000000000
--- a/library/std/src/sys/pal/unix/process/process_fuchsia.rs
+++ /dev/null
@@ -1,326 +0,0 @@
-use libc::{c_int, size_t};
-
-use crate::num::NonZero;
-use crate::sys::process::process_common::*;
-use crate::sys::process::zircon::{Handle, zx_handle_t};
-use crate::{fmt, io, mem, ptr};
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-impl Command {
-    pub fn spawn(
-        &mut self,
-        default: Stdio,
-        needs_stdin: bool,
-    ) -> io::Result<(Process, StdioPipes)> {
-        let envp = self.capture_env();
-
-        if self.saw_nul() {
-            return Err(io::const_error!(
-                io::ErrorKind::InvalidInput,
-                "nul byte found in provided data",
-            ));
-        }
-
-        let (ours, theirs) = self.setup_io(default, needs_stdin)?;
-
-        let process_handle = unsafe { self.do_exec(theirs, envp.as_ref())? };
-
-        Ok((Process { handle: Handle::new(process_handle) }, ours))
-    }
-
-    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
-        let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
-        crate::sys_common::process::wait_with_output(proc, pipes)
-    }
-
-    pub fn exec(&mut self, default: Stdio) -> io::Error {
-        if self.saw_nul() {
-            return io::const_error!(
-                io::ErrorKind::InvalidInput,
-                "nul byte found in provided data",
-            );
-        }
-
-        match self.setup_io(default, true) {
-            Ok((_, _)) => {
-                // FIXME: This is tough because we don't support the exec syscalls
-                unimplemented!();
-            }
-            Err(e) => e,
-        }
-    }
-
-    unsafe fn do_exec(
-        &mut self,
-        stdio: ChildPipes,
-        maybe_envp: Option<&CStringArray>,
-    ) -> io::Result<zx_handle_t> {
-        use crate::sys::process::zircon::*;
-
-        let envp = match maybe_envp {
-            // None means to clone the current environment, which is done in the
-            // flags below.
-            None => ptr::null(),
-            Some(envp) => envp.as_ptr(),
-        };
-
-        let make_action = |local_io: &ChildStdio, target_fd| -> io::Result<fdio_spawn_action_t> {
-            if let Some(local_fd) = local_io.fd() {
-                Ok(fdio_spawn_action_t {
-                    action: FDIO_SPAWN_ACTION_TRANSFER_FD,
-                    local_fd,
-                    target_fd,
-                    ..Default::default()
-                })
-            } else {
-                if let ChildStdio::Null = local_io {
-                    // acts as no-op
-                    return Ok(Default::default());
-                }
-
-                let mut handle = ZX_HANDLE_INVALID;
-                let status = fdio_fd_clone(target_fd, &mut handle);
-                if status == ERR_INVALID_ARGS || status == ERR_NOT_SUPPORTED {
-                    // This descriptor is closed; skip it rather than generating an
-                    // error.
-                    return Ok(Default::default());
-                }
-                zx_cvt(status)?;
-
-                let mut cloned_fd = 0;
-                zx_cvt(fdio_fd_create(handle, &mut cloned_fd))?;
-
-                Ok(fdio_spawn_action_t {
-                    action: FDIO_SPAWN_ACTION_TRANSFER_FD,
-                    local_fd: cloned_fd as i32,
-                    target_fd,
-                    ..Default::default()
-                })
-            }
-        };
-
-        // Clone stdin, stdout, and stderr
-        let action1 = make_action(&stdio.stdin, 0)?;
-        let action2 = make_action(&stdio.stdout, 1)?;
-        let action3 = make_action(&stdio.stderr, 2)?;
-        let actions = [action1, action2, action3];
-
-        // We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc
-        // always consumes transferred file descriptors.
-        mem::forget(stdio);
-
-        for callback in self.get_closures().iter_mut() {
-            callback()?;
-        }
-
-        let mut process_handle: zx_handle_t = 0;
-        zx_cvt(fdio_spawn_etc(
-            ZX_HANDLE_INVALID,
-            FDIO_SPAWN_CLONE_JOB
-                | FDIO_SPAWN_CLONE_LDSVC
-                | FDIO_SPAWN_CLONE_NAMESPACE
-                | FDIO_SPAWN_CLONE_ENVIRON // this is ignored when envp is non-null
-                | FDIO_SPAWN_CLONE_UTC_CLOCK,
-            self.get_program_cstr().as_ptr(),
-            self.get_argv().as_ptr(),
-            envp,
-            actions.len() as size_t,
-            actions.as_ptr(),
-            &mut process_handle,
-            ptr::null_mut(),
-        ))?;
-        // FIXME: See if we want to do something with that err_msg
-
-        Ok(process_handle)
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Processes
-////////////////////////////////////////////////////////////////////////////////
-
-pub struct Process {
-    handle: Handle,
-}
-
-impl Process {
-    pub fn id(&self) -> u32 {
-        self.handle.raw() as u32
-    }
-
-    pub fn kill(&mut self) -> io::Result<()> {
-        use crate::sys::process::zircon::*;
-
-        unsafe {
-            zx_cvt(zx_task_kill(self.handle.raw()))?;
-        }
-
-        Ok(())
-    }
-
-    pub fn wait(&mut self) -> io::Result<ExitStatus> {
-        use crate::sys::process::zircon::*;
-
-        let mut proc_info: zx_info_process_t = Default::default();
-        let mut actual: size_t = 0;
-        let mut avail: size_t = 0;
-
-        unsafe {
-            zx_cvt(zx_object_wait_one(
-                self.handle.raw(),
-                ZX_TASK_TERMINATED,
-                ZX_TIME_INFINITE,
-                ptr::null_mut(),
-            ))?;
-            zx_cvt(zx_object_get_info(
-                self.handle.raw(),
-                ZX_INFO_PROCESS,
-                (&raw mut proc_info) as *mut libc::c_void,
-                size_of::<zx_info_process_t>(),
-                &mut actual,
-                &mut avail,
-            ))?;
-        }
-        if actual != 1 {
-            return Err(io::const_error!(
-                io::ErrorKind::InvalidData,
-                "failed to get exit status of process",
-            ));
-        }
-        Ok(ExitStatus(proc_info.return_code))
-    }
-
-    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
-        use crate::sys::process::zircon::*;
-
-        let mut proc_info: zx_info_process_t = Default::default();
-        let mut actual: size_t = 0;
-        let mut avail: size_t = 0;
-
-        unsafe {
-            let status =
-                zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED, 0, ptr::null_mut());
-            match status {
-                0 => {} // Success
-                x if x == ERR_TIMED_OUT => {
-                    return Ok(None);
-                }
-                _ => {
-                    panic!("Failed to wait on process handle: {status}");
-                }
-            }
-            zx_cvt(zx_object_get_info(
-                self.handle.raw(),
-                ZX_INFO_PROCESS,
-                (&raw mut proc_info) as *mut libc::c_void,
-                size_of::<zx_info_process_t>(),
-                &mut actual,
-                &mut avail,
-            ))?;
-        }
-        if actual != 1 {
-            return Err(io::const_error!(
-                io::ErrorKind::InvalidData,
-                "failed to get exit status of process",
-            ));
-        }
-        Ok(Some(ExitStatus(proc_info.return_code)))
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
-pub struct ExitStatus(i64);
-
-impl ExitStatus {
-    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
-        match NonZero::try_from(self.0) {
-            /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)),
-            /* was zero, couldn't convert */ Err(_) => Ok(()),
-        }
-    }
-
-    pub fn code(&self) -> Option<i32> {
-        // FIXME: support extracting return code as an i64
-        self.0.try_into().ok()
-    }
-
-    pub fn signal(&self) -> Option<i32> {
-        None
-    }
-
-    // FIXME: The actually-Unix implementation in process_unix.rs uses WSTOPSIG, WCOREDUMP et al.
-    // I infer from the implementation of `success`, `code` and `signal` above that these are not
-    // available on Fuchsia.
-    //
-    // It does not appear that Fuchsia is Unix-like enough to implement ExitStatus (or indeed many
-    // other things from std::os::unix) properly. This veneer is always going to be a bodge. So
-    // while I don't know if these implementations are actually correct, I think they will do for
-    // now at least.
-    pub fn core_dumped(&self) -> bool {
-        false
-    }
-    pub fn stopped_signal(&self) -> Option<i32> {
-        None
-    }
-    pub fn continued(&self) -> bool {
-        false
-    }
-
-    pub fn into_raw(&self) -> c_int {
-        // We don't know what someone who calls into_raw() will do with this value, but it should
-        // have the conventional Unix representation. Despite the fact that this is not
-        // standardised in SuS or POSIX, all Unix systems encode the signal and exit status the
-        // same way. (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behavior on every
-        // Unix.)
-        //
-        // The caller of `std::os::unix::into_raw` is probably wanting a Unix exit status, and may
-        // do their own shifting and masking, or even pass the status to another computer running a
-        // different Unix variant.
-        //
-        // The other view would be to say that the caller on Fuchsia ought to know that `into_raw`
-        // will give a raw Fuchsia status (whatever that is - I don't know, personally). That is
-        // not possible here because we must return a c_int because that's what Unix (including
-        // SuS and POSIX) say a wait status is, but Fuchsia apparently uses a u64, so it won't
-        // necessarily fit.
-        //
-        // It seems to me that the right answer would be to provide std::os::fuchsia with its
-        // own ExitStatusExt, rather that trying to provide a not very convincing imitation of
-        // Unix. Ie, std::os::unix::process:ExitStatusExt ought not to exist on Fuchsia. But
-        // fixing this up that is beyond the scope of my efforts now.
-        let exit_status_as_if_unix: u8 = self.0.try_into().expect("Fuchsia process return code bigger than 8 bits, but std::os::unix::ExitStatusExt::into_raw() was called to try to convert the value into a traditional Unix-style wait status, which cannot represent values greater than 255.");
-        let wait_status_as_if_unix = (exit_status_as_if_unix as c_int) << 8;
-        wait_status_as_if_unix
-    }
-}
-
-/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying.
-impl From<c_int> for ExitStatus {
-    fn from(a: c_int) -> ExitStatus {
-        ExitStatus(a as i64)
-    }
-}
-
-impl fmt::Display for ExitStatus {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "exit code: {}", self.0)
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitStatusError(NonZero<i64>);
-
-impl Into<ExitStatus> for ExitStatusError {
-    fn into(self) -> ExitStatus {
-        ExitStatus(self.0.into())
-    }
-}
-
-impl ExitStatusError {
-    pub fn code(self) -> Option<NonZero<i32>> {
-        // fixme: affected by the same bug as ExitStatus::code()
-        ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap())
-    }
-}
diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs
deleted file mode 100644
index f19512233d8..00000000000
--- a/library/std/src/sys/pal/unix/process/process_unix.rs
+++ /dev/null
@@ -1,1270 +0,0 @@
-#[cfg(target_os = "vxworks")]
-use libc::RTP_ID as pid_t;
-#[cfg(not(target_os = "vxworks"))]
-use libc::{c_int, pid_t};
-#[cfg(not(any(
-    target_os = "vxworks",
-    target_os = "l4re",
-    target_os = "tvos",
-    target_os = "watchos",
-)))]
-use libc::{gid_t, uid_t};
-
-use crate::io::{self, Error, ErrorKind};
-use crate::num::NonZero;
-use crate::sys::cvt;
-#[cfg(target_os = "linux")]
-use crate::sys::pal::unix::linux::pidfd::PidFd;
-use crate::sys::process::process_common::*;
-use crate::{fmt, mem, sys};
-
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "nto")] {
-        use crate::thread;
-        use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t};
-        use crate::time::Duration;
-        use crate::sync::LazyLock;
-        // Get smallest amount of time we can sleep.
-        // Return a common value if it cannot be determined.
-        fn get_clock_resolution() -> Duration {
-            static MIN_DELAY: LazyLock<Duration, fn() -> Duration> = LazyLock::new(|| {
-                let mut mindelay = libc::timespec { tv_sec: 0, tv_nsec: 0 };
-                if unsafe { libc::clock_getres(libc::CLOCK_MONOTONIC, &mut mindelay) } == 0
-                {
-                    Duration::from_nanos(mindelay.tv_nsec as u64)
-                } else {
-                    Duration::from_millis(1)
-                }
-            });
-            *MIN_DELAY
-        }
-        // Arbitrary minimum sleep duration for retrying fork/spawn
-        const MIN_FORKSPAWN_SLEEP: Duration = Duration::from_nanos(1);
-        // Maximum duration of sleeping before giving up and returning an error
-        const MAX_FORKSPAWN_SLEEP: Duration = Duration::from_millis(1000);
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-impl Command {
-    pub fn spawn(
-        &mut self,
-        default: Stdio,
-        needs_stdin: bool,
-    ) -> io::Result<(Process, StdioPipes)> {
-        const CLOEXEC_MSG_FOOTER: [u8; 4] = *b"NOEX";
-
-        let envp = self.capture_env();
-
-        if self.saw_nul() {
-            return Err(io::const_error!(
-                ErrorKind::InvalidInput,
-                "nul byte found in provided data",
-            ));
-        }
-
-        let (ours, theirs) = self.setup_io(default, needs_stdin)?;
-
-        if let Some(ret) = self.posix_spawn(&theirs, envp.as_ref())? {
-            return Ok((ret, ours));
-        }
-
-        #[cfg(target_os = "linux")]
-        let (input, output) = sys::net::Socket::new_pair(libc::AF_UNIX, libc::SOCK_SEQPACKET)?;
-
-        #[cfg(not(target_os = "linux"))]
-        let (input, output) = sys::pipe::anon_pipe()?;
-
-        // Whatever happens after the fork is almost for sure going to touch or
-        // look at the environment in one way or another (PATH in `execvp` or
-        // accessing the `environ` pointer ourselves). Make sure no other thread
-        // is accessing the environment when we do the fork itself.
-        //
-        // Note that as soon as we're done with the fork there's no need to hold
-        // a lock any more because the parent won't do anything and the child is
-        // in its own process. Thus the parent drops the lock guard immediately.
-        // The child calls `mem::forget` to leak the lock, which is crucial because
-        // releasing a lock is not async-signal-safe.
-        let env_lock = sys::os::env_read_lock();
-        let pid = unsafe { self.do_fork()? };
-
-        if pid == 0 {
-            crate::panic::always_abort();
-            mem::forget(env_lock); // avoid non-async-signal-safe unlocking
-            drop(input);
-            #[cfg(target_os = "linux")]
-            if self.get_create_pidfd() {
-                self.send_pidfd(&output);
-            }
-            let Err(err) = unsafe { self.do_exec(theirs, envp.as_ref()) };
-            let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32;
-            let errno = errno.to_be_bytes();
-            let bytes = [
-                errno[0],
-                errno[1],
-                errno[2],
-                errno[3],
-                CLOEXEC_MSG_FOOTER[0],
-                CLOEXEC_MSG_FOOTER[1],
-                CLOEXEC_MSG_FOOTER[2],
-                CLOEXEC_MSG_FOOTER[3],
-            ];
-            // pipe I/O up to PIPE_BUF bytes should be atomic, and then
-            // we want to be sure we *don't* run at_exit destructors as
-            // we're being torn down regardless
-            rtassert!(output.write(&bytes).is_ok());
-            unsafe { libc::_exit(1) }
-        }
-
-        drop(env_lock);
-        drop(output);
-
-        #[cfg(target_os = "linux")]
-        let pidfd = if self.get_create_pidfd() { self.recv_pidfd(&input) } else { -1 };
-
-        #[cfg(not(target_os = "linux"))]
-        let pidfd = -1;
-
-        // Safety: We obtained the pidfd (on Linux) using SOCK_SEQPACKET, so it's valid.
-        let mut p = unsafe { Process::new(pid, pidfd) };
-        let mut bytes = [0; 8];
-
-        // loop to handle EINTR
-        loop {
-            match input.read(&mut bytes) {
-                Ok(0) => return Ok((p, ours)),
-                Ok(8) => {
-                    let (errno, footer) = bytes.split_at(4);
-                    assert_eq!(
-                        CLOEXEC_MSG_FOOTER, footer,
-                        "Validation on the CLOEXEC pipe failed: {:?}",
-                        bytes
-                    );
-                    let errno = i32::from_be_bytes(errno.try_into().unwrap());
-                    assert!(p.wait().is_ok(), "wait() should either return Ok or panic");
-                    return Err(Error::from_raw_os_error(errno));
-                }
-                Err(ref e) if e.is_interrupted() => {}
-                Err(e) => {
-                    assert!(p.wait().is_ok(), "wait() should either return Ok or panic");
-                    panic!("the CLOEXEC pipe failed: {e:?}")
-                }
-                Ok(..) => {
-                    // pipe I/O up to PIPE_BUF bytes should be atomic
-                    // similarly SOCK_SEQPACKET messages should arrive whole
-                    assert!(p.wait().is_ok(), "wait() should either return Ok or panic");
-                    panic!("short read on the CLOEXEC pipe")
-                }
-            }
-        }
-    }
-
-    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
-        let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
-        crate::sys_common::process::wait_with_output(proc, pipes)
-    }
-
-    // WatchOS and TVOS headers mark the `fork`/`exec*` functions with
-    // `__WATCHOS_PROHIBITED __TVOS_PROHIBITED`, and indicate that the
-    // `posix_spawn*` functions should be used instead. It isn't entirely clear
-    // what `PROHIBITED` means here (e.g. if calls to these functions are
-    // allowed to exist in dead code), but it sounds bad, so we go out of our
-    // way to avoid that all-together.
-    #[cfg(any(target_os = "tvos", target_os = "watchos"))]
-    const ERR_APPLE_TV_WATCH_NO_FORK_EXEC: Error = io::const_error!(
-        ErrorKind::Unsupported,
-        "`fork`+`exec`-based process spawning is not supported on this target",
-    );
-
-    #[cfg(any(target_os = "tvos", target_os = "watchos"))]
-    unsafe fn do_fork(&mut self) -> Result<pid_t, io::Error> {
-        return Err(Self::ERR_APPLE_TV_WATCH_NO_FORK_EXEC);
-    }
-
-    // Attempts to fork the process. If successful, returns Ok((0, -1))
-    // in the child, and Ok((child_pid, -1)) in the parent.
-    #[cfg(not(any(target_os = "watchos", target_os = "tvos", target_os = "nto")))]
-    unsafe fn do_fork(&mut self) -> Result<pid_t, io::Error> {
-        cvt(libc::fork())
-    }
-
-    // On QNX Neutrino, fork can fail with EBADF in case "another thread might have opened
-    // or closed a file descriptor while the fork() was occurring".
-    // Documentation says "... or try calling fork() again". This is what we do here.
-    // See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html
-    #[cfg(target_os = "nto")]
-    unsafe fn do_fork(&mut self) -> Result<pid_t, io::Error> {
-        use crate::sys::os::errno;
-
-        let mut delay = MIN_FORKSPAWN_SLEEP;
-
-        loop {
-            let r = libc::fork();
-            if r == -1 as libc::pid_t && errno() as libc::c_int == libc::EBADF {
-                if delay < get_clock_resolution() {
-                    // We cannot sleep this short (it would be longer).
-                    // Yield instead.
-                    thread::yield_now();
-                } else if delay < MAX_FORKSPAWN_SLEEP {
-                    thread::sleep(delay);
-                } else {
-                    return Err(io::const_error!(
-                        ErrorKind::WouldBlock,
-                        "forking returned EBADF too often",
-                    ));
-                }
-                delay *= 2;
-                continue;
-            } else {
-                return cvt(r);
-            }
-        }
-    }
-
-    pub fn exec(&mut self, default: Stdio) -> io::Error {
-        let envp = self.capture_env();
-
-        if self.saw_nul() {
-            return io::const_error!(ErrorKind::InvalidInput, "nul byte found in provided data");
-        }
-
-        match self.setup_io(default, true) {
-            Ok((_, theirs)) => {
-                unsafe {
-                    // Similar to when forking, we want to ensure that access to
-                    // the environment is synchronized, so make sure to grab the
-                    // environment lock before we try to exec.
-                    let _lock = sys::os::env_read_lock();
-
-                    let Err(e) = self.do_exec(theirs, envp.as_ref());
-                    e
-                }
-            }
-            Err(e) => e,
-        }
-    }
-
-    // And at this point we've reached a special time in the life of the
-    // child. The child must now be considered hamstrung and unable to
-    // do anything other than syscalls really. Consider the following
-    // scenario:
-    //
-    //      1. Thread A of process 1 grabs the malloc() mutex
-    //      2. Thread B of process 1 forks(), creating thread C
-    //      3. Thread C of process 2 then attempts to malloc()
-    //      4. The memory of process 2 is the same as the memory of
-    //         process 1, so the mutex is locked.
-    //
-    // This situation looks a lot like deadlock, right? It turns out
-    // that this is what pthread_atfork() takes care of, which is
-    // presumably implemented across platforms. The first thing that
-    // threads to *before* forking is to do things like grab the malloc
-    // mutex, and then after the fork they unlock it.
-    //
-    // Despite this information, libnative's spawn has been witnessed to
-    // deadlock on both macOS and FreeBSD. I'm not entirely sure why, but
-    // all collected backtraces point at malloc/free traffic in the
-    // child spawned process.
-    //
-    // For this reason, the block of code below should contain 0
-    // invocations of either malloc of free (or their related friends).
-    //
-    // As an example of not having malloc/free traffic, we don't close
-    // this file descriptor by dropping the FileDesc (which contains an
-    // allocation). Instead we just close it manually. This will never
-    // have the drop glue anyway because this code never returns (the
-    // child will either exec() or invoke libc::exit)
-    #[cfg(not(any(target_os = "tvos", target_os = "watchos")))]
-    unsafe fn do_exec(
-        &mut self,
-        stdio: ChildPipes,
-        maybe_envp: Option<&CStringArray>,
-    ) -> Result<!, io::Error> {
-        use crate::sys::{self, cvt_r};
-
-        if let Some(fd) = stdio.stdin.fd() {
-            cvt_r(|| libc::dup2(fd, libc::STDIN_FILENO))?;
-        }
-        if let Some(fd) = stdio.stdout.fd() {
-            cvt_r(|| libc::dup2(fd, libc::STDOUT_FILENO))?;
-        }
-        if let Some(fd) = stdio.stderr.fd() {
-            cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO))?;
-        }
-
-        #[cfg(not(target_os = "l4re"))]
-        {
-            if let Some(_g) = self.get_groups() {
-                //FIXME: Redox kernel does not support setgroups yet
-                #[cfg(not(target_os = "redox"))]
-                cvt(libc::setgroups(_g.len().try_into().unwrap(), _g.as_ptr()))?;
-            }
-            if let Some(u) = self.get_gid() {
-                cvt(libc::setgid(u as gid_t))?;
-            }
-            if let Some(u) = self.get_uid() {
-                // When dropping privileges from root, the `setgroups` call
-                // will remove any extraneous groups. We only drop groups
-                // if we have CAP_SETGID and we weren't given an explicit
-                // set of groups. If we don't call this, then even though our
-                // uid has dropped, we may still have groups that enable us to
-                // do super-user things.
-                //FIXME: Redox kernel does not support setgroups yet
-                #[cfg(not(target_os = "redox"))]
-                if self.get_groups().is_none() {
-                    let res = cvt(libc::setgroups(0, crate::ptr::null()));
-                    if let Err(e) = res {
-                        // Here we ignore the case of not having CAP_SETGID.
-                        // An alternative would be to require CAP_SETGID (in
-                        // addition to CAP_SETUID) for setting the UID.
-                        if e.raw_os_error() != Some(libc::EPERM) {
-                            return Err(e.into());
-                        }
-                    }
-                }
-                cvt(libc::setuid(u as uid_t))?;
-            }
-        }
-        if let Some(cwd) = self.get_cwd() {
-            cvt(libc::chdir(cwd.as_ptr()))?;
-        }
-
-        if let Some(pgroup) = self.get_pgroup() {
-            cvt(libc::setpgid(0, pgroup))?;
-        }
-
-        // emscripten has no signal support.
-        #[cfg(not(target_os = "emscripten"))]
-        {
-            // Inherit the signal mask from the parent rather than resetting it (i.e. do not call
-            // pthread_sigmask).
-
-            // If -Zon-broken-pipe is used, don't reset SIGPIPE to SIG_DFL.
-            // If -Zon-broken-pipe is not used, reset SIGPIPE to SIG_DFL for backward compatibility.
-            //
-            // -Zon-broken-pipe is an opportunity to change the default here.
-            if !crate::sys::pal::on_broken_pipe_flag_used() {
-                #[cfg(target_os = "android")] // see issue #88585
-                {
-                    let mut action: libc::sigaction = mem::zeroed();
-                    action.sa_sigaction = libc::SIG_DFL;
-                    cvt(libc::sigaction(libc::SIGPIPE, &action, crate::ptr::null_mut()))?;
-                }
-                #[cfg(not(target_os = "android"))]
-                {
-                    let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL);
-                    if ret == libc::SIG_ERR {
-                        return Err(io::Error::last_os_error());
-                    }
-                }
-                #[cfg(target_os = "hurd")]
-                {
-                    let ret = sys::signal(libc::SIGLOST, libc::SIG_DFL);
-                    if ret == libc::SIG_ERR {
-                        return Err(io::Error::last_os_error());
-                    }
-                }
-            }
-        }
-
-        for callback in self.get_closures().iter_mut() {
-            callback()?;
-        }
-
-        // Although we're performing an exec here we may also return with an
-        // error from this function (without actually exec'ing) in which case we
-        // want to be sure to restore the global environment back to what it
-        // once was, ensuring that our temporary override, when free'd, doesn't
-        // corrupt our process's environment.
-        let mut _reset = None;
-        if let Some(envp) = maybe_envp {
-            struct Reset(*const *const libc::c_char);
-
-            impl Drop for Reset {
-                fn drop(&mut self) {
-                    unsafe {
-                        *sys::os::environ() = self.0;
-                    }
-                }
-            }
-
-            _reset = Some(Reset(*sys::os::environ()));
-            *sys::os::environ() = envp.as_ptr();
-        }
-
-        libc::execvp(self.get_program_cstr().as_ptr(), self.get_argv().as_ptr());
-        Err(io::Error::last_os_error())
-    }
-
-    #[cfg(any(target_os = "tvos", target_os = "watchos"))]
-    unsafe fn do_exec(
-        &mut self,
-        _stdio: ChildPipes,
-        _maybe_envp: Option<&CStringArray>,
-    ) -> Result<!, io::Error> {
-        return Err(Self::ERR_APPLE_TV_WATCH_NO_FORK_EXEC);
-    }
-
-    #[cfg(not(any(
-        target_os = "freebsd",
-        target_os = "illumos",
-        all(target_os = "linux", target_env = "gnu"),
-        all(target_os = "linux", target_env = "musl"),
-        target_os = "nto",
-        target_vendor = "apple",
-    )))]
-    fn posix_spawn(
-        &mut self,
-        _: &ChildPipes,
-        _: Option<&CStringArray>,
-    ) -> io::Result<Option<Process>> {
-        Ok(None)
-    }
-
-    // Only support platforms for which posix_spawn() can return ENOENT
-    // directly.
-    #[cfg(any(
-        target_os = "freebsd",
-        target_os = "illumos",
-        all(target_os = "linux", target_env = "gnu"),
-        all(target_os = "linux", target_env = "musl"),
-        target_os = "nto",
-        target_vendor = "apple",
-    ))]
-    // FIXME(#115199): Rust currently omits weak function definitions
-    // and its metadata from LLVM IR.
-    #[cfg_attr(target_os = "linux", no_sanitize(cfi))]
-    fn posix_spawn(
-        &mut self,
-        stdio: &ChildPipes,
-        envp: Option<&CStringArray>,
-    ) -> io::Result<Option<Process>> {
-        #[cfg(target_os = "linux")]
-        use core::sync::atomic::{AtomicU8, Ordering};
-
-        use crate::mem::MaybeUninit;
-        use crate::sys::{self, cvt_nz, on_broken_pipe_flag_used};
-
-        if self.get_gid().is_some()
-            || self.get_uid().is_some()
-            || (self.env_saw_path() && !self.program_is_path())
-            || !self.get_closures().is_empty()
-            || self.get_groups().is_some()
-        {
-            return Ok(None);
-        }
-
-        cfg_if::cfg_if! {
-            if #[cfg(target_os = "linux")] {
-                use crate::sys::weak::weak;
-
-                weak! {
-                    fn pidfd_spawnp(
-                        *mut libc::c_int,
-                        *const libc::c_char,
-                        *const libc::posix_spawn_file_actions_t,
-                        *const libc::posix_spawnattr_t,
-                        *const *mut libc::c_char,
-                        *const *mut libc::c_char
-                    ) -> libc::c_int
-                }
-
-                weak! { fn pidfd_getpid(libc::c_int) -> libc::c_int }
-
-                static PIDFD_SUPPORTED: AtomicU8 = AtomicU8::new(0);
-                const UNKNOWN: u8 = 0;
-                const SPAWN: u8 = 1;
-                // Obtaining a pidfd via the fork+exec path might work
-                const FORK_EXEC: u8 = 2;
-                // Neither pidfd_spawn nor fork/exec will get us a pidfd.
-                // Instead we'll just posix_spawn if the other preconditions are met.
-                const NO: u8 = 3;
-
-                if self.get_create_pidfd() {
-                    let mut support = PIDFD_SUPPORTED.load(Ordering::Relaxed);
-                    if support == FORK_EXEC {
-                        return Ok(None);
-                    }
-                    if support == UNKNOWN {
-                        support = NO;
-                        let our_pid = crate::process::id();
-                        let pidfd = cvt(unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) } as c_int);
-                        match pidfd {
-                            Ok(pidfd) => {
-                                support = FORK_EXEC;
-                                if let Some(Ok(pid)) = pidfd_getpid.get().map(|f| cvt(unsafe { f(pidfd) } as i32)) {
-                                    if pidfd_spawnp.get().is_some() && pid as u32 == our_pid {
-                                        support = SPAWN
-                                    }
-                                }
-                                unsafe { libc::close(pidfd) };
-                            }
-                            Err(e) if e.raw_os_error() == Some(libc::EMFILE) => {
-                                // We're temporarily(?) out of file descriptors.  In this case obtaining a pidfd would also fail
-                                // Don't update the support flag so we can probe again later.
-                                return Err(e)
-                            }
-                            _ => {}
-                        }
-                        PIDFD_SUPPORTED.store(support, Ordering::Relaxed);
-                        if support == FORK_EXEC {
-                            return Ok(None);
-                        }
-                    }
-                    core::assert_matches::debug_assert_matches!(support, SPAWN | NO);
-                }
-            } else {
-                if self.get_create_pidfd() {
-                    unreachable!("only implemented on linux")
-                }
-            }
-        }
-
-        // Only glibc 2.24+ posix_spawn() supports returning ENOENT directly.
-        #[cfg(all(target_os = "linux", target_env = "gnu"))]
-        {
-            if let Some(version) = sys::os::glibc_version() {
-                if version < (2, 24) {
-                    return Ok(None);
-                }
-            } else {
-                return Ok(None);
-            }
-        }
-
-        // On QNX Neutrino, posix_spawnp can fail with EBADF in case "another thread might have opened
-        // or closed a file descriptor while the posix_spawn() was occurring".
-        // Documentation says "... or try calling posix_spawn() again". This is what we do here.
-        // See also http://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/p/posix_spawn.html
-        #[cfg(target_os = "nto")]
-        unsafe fn retrying_libc_posix_spawnp(
-            pid: *mut pid_t,
-            file: *const c_char,
-            file_actions: *const posix_spawn_file_actions_t,
-            attrp: *const posix_spawnattr_t,
-            argv: *const *mut c_char,
-            envp: *const *mut c_char,
-        ) -> io::Result<i32> {
-            let mut delay = MIN_FORKSPAWN_SLEEP;
-            loop {
-                match libc::posix_spawnp(pid, file, file_actions, attrp, argv, envp) {
-                    libc::EBADF => {
-                        if delay < get_clock_resolution() {
-                            // We cannot sleep this short (it would be longer).
-                            // Yield instead.
-                            thread::yield_now();
-                        } else if delay < MAX_FORKSPAWN_SLEEP {
-                            thread::sleep(delay);
-                        } else {
-                            return Err(io::const_error!(
-                                ErrorKind::WouldBlock,
-                                "posix_spawnp returned EBADF too often",
-                            ));
-                        }
-                        delay *= 2;
-                        continue;
-                    }
-                    r => {
-                        return Ok(r);
-                    }
-                }
-            }
-        }
-
-        type PosixSpawnAddChdirFn = unsafe extern "C" fn(
-            *mut libc::posix_spawn_file_actions_t,
-            *const libc::c_char,
-        ) -> libc::c_int;
-
-        /// Get the function pointer for adding a chdir action to a
-        /// `posix_spawn_file_actions_t`, if available, assuming a dynamic libc.
-        ///
-        /// Some platforms can set a new working directory for a spawned process in the
-        /// `posix_spawn` path. This function looks up the function pointer for adding
-        /// such an action to a `posix_spawn_file_actions_t` struct.
-        #[cfg(not(all(target_os = "linux", target_env = "musl")))]
-        fn get_posix_spawn_addchdir() -> Option<PosixSpawnAddChdirFn> {
-            use crate::sys::weak::weak;
-
-            // POSIX.1-2024 standardizes this function:
-            // https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn_file_actions_addchdir.html.
-            // The _np version is more widely available, though, so try that first.
-
-            weak! {
-                fn posix_spawn_file_actions_addchdir_np(
-                    *mut libc::posix_spawn_file_actions_t,
-                    *const libc::c_char
-                ) -> libc::c_int
-            }
-
-            weak! {
-                fn posix_spawn_file_actions_addchdir(
-                    *mut libc::posix_spawn_file_actions_t,
-                    *const libc::c_char
-                ) -> libc::c_int
-            }
-
-            posix_spawn_file_actions_addchdir_np
-                .get()
-                .or_else(|| posix_spawn_file_actions_addchdir.get())
-        }
-
-        /// Get the function pointer for adding a chdir action to a
-        /// `posix_spawn_file_actions_t`, if available, on platforms where the function
-        /// is known to exist.
-        ///
-        /// Weak symbol lookup doesn't work with statically linked libcs, so in cases
-        /// where static linking is possible we need to either check for the presence
-        /// of the symbol at compile time or know about it upfront.
-        #[cfg(all(target_os = "linux", target_env = "musl"))]
-        fn get_posix_spawn_addchdir() -> Option<PosixSpawnAddChdirFn> {
-            // Our minimum required musl supports this function, so we can just use it.
-            Some(libc::posix_spawn_file_actions_addchdir_np)
-        }
-
-        let addchdir = match self.get_cwd() {
-            Some(cwd) => {
-                if cfg!(target_vendor = "apple") {
-                    // There is a bug in macOS where a relative executable
-                    // path like "../myprogram" will cause `posix_spawn` to
-                    // successfully launch the program, but erroneously return
-                    // ENOENT when used with posix_spawn_file_actions_addchdir_np
-                    // which was introduced in macOS 10.15.
-                    if self.get_program_kind() == ProgramKind::Relative {
-                        return Ok(None);
-                    }
-                }
-                // Check for the availability of the posix_spawn addchdir
-                // function now. If it isn't available, bail and use the
-                // fork/exec path.
-                match get_posix_spawn_addchdir() {
-                    Some(f) => Some((f, cwd)),
-                    None => return Ok(None),
-                }
-            }
-            None => None,
-        };
-
-        let pgroup = self.get_pgroup();
-
-        struct PosixSpawnFileActions<'a>(&'a mut MaybeUninit<libc::posix_spawn_file_actions_t>);
-
-        impl Drop for PosixSpawnFileActions<'_> {
-            fn drop(&mut self) {
-                unsafe {
-                    libc::posix_spawn_file_actions_destroy(self.0.as_mut_ptr());
-                }
-            }
-        }
-
-        struct PosixSpawnattr<'a>(&'a mut MaybeUninit<libc::posix_spawnattr_t>);
-
-        impl Drop for PosixSpawnattr<'_> {
-            fn drop(&mut self) {
-                unsafe {
-                    libc::posix_spawnattr_destroy(self.0.as_mut_ptr());
-                }
-            }
-        }
-
-        unsafe {
-            let mut attrs = MaybeUninit::uninit();
-            cvt_nz(libc::posix_spawnattr_init(attrs.as_mut_ptr()))?;
-            let attrs = PosixSpawnattr(&mut attrs);
-
-            let mut flags = 0;
-
-            let mut file_actions = MaybeUninit::uninit();
-            cvt_nz(libc::posix_spawn_file_actions_init(file_actions.as_mut_ptr()))?;
-            let file_actions = PosixSpawnFileActions(&mut file_actions);
-
-            if let Some(fd) = stdio.stdin.fd() {
-                cvt_nz(libc::posix_spawn_file_actions_adddup2(
-                    file_actions.0.as_mut_ptr(),
-                    fd,
-                    libc::STDIN_FILENO,
-                ))?;
-            }
-            if let Some(fd) = stdio.stdout.fd() {
-                cvt_nz(libc::posix_spawn_file_actions_adddup2(
-                    file_actions.0.as_mut_ptr(),
-                    fd,
-                    libc::STDOUT_FILENO,
-                ))?;
-            }
-            if let Some(fd) = stdio.stderr.fd() {
-                cvt_nz(libc::posix_spawn_file_actions_adddup2(
-                    file_actions.0.as_mut_ptr(),
-                    fd,
-                    libc::STDERR_FILENO,
-                ))?;
-            }
-            if let Some((f, cwd)) = addchdir {
-                cvt_nz(f(file_actions.0.as_mut_ptr(), cwd.as_ptr()))?;
-            }
-
-            if let Some(pgroup) = pgroup {
-                flags |= libc::POSIX_SPAWN_SETPGROUP;
-                cvt_nz(libc::posix_spawnattr_setpgroup(attrs.0.as_mut_ptr(), pgroup))?;
-            }
-
-            // Inherit the signal mask from this process rather than resetting it (i.e. do not call
-            // posix_spawnattr_setsigmask).
-
-            // If -Zon-broken-pipe is used, don't reset SIGPIPE to SIG_DFL.
-            // If -Zon-broken-pipe is not used, reset SIGPIPE to SIG_DFL for backward compatibility.
-            //
-            // -Zon-broken-pipe is an opportunity to change the default here.
-            if !on_broken_pipe_flag_used() {
-                let mut default_set = MaybeUninit::<libc::sigset_t>::uninit();
-                cvt(sigemptyset(default_set.as_mut_ptr()))?;
-                cvt(sigaddset(default_set.as_mut_ptr(), libc::SIGPIPE))?;
-                #[cfg(target_os = "hurd")]
-                {
-                    cvt(sigaddset(default_set.as_mut_ptr(), libc::SIGLOST))?;
-                }
-                cvt_nz(libc::posix_spawnattr_setsigdefault(
-                    attrs.0.as_mut_ptr(),
-                    default_set.as_ptr(),
-                ))?;
-                flags |= libc::POSIX_SPAWN_SETSIGDEF;
-            }
-
-            cvt_nz(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?;
-
-            // Make sure we synchronize access to the global `environ` resource
-            let _env_lock = sys::os::env_read_lock();
-            let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _);
-
-            #[cfg(not(target_os = "nto"))]
-            let spawn_fn = libc::posix_spawnp;
-            #[cfg(target_os = "nto")]
-            let spawn_fn = retrying_libc_posix_spawnp;
-
-            #[cfg(target_os = "linux")]
-            if self.get_create_pidfd() && PIDFD_SUPPORTED.load(Ordering::Relaxed) == SPAWN {
-                let mut pidfd: libc::c_int = -1;
-                let spawn_res = pidfd_spawnp.get().unwrap()(
-                    &mut pidfd,
-                    self.get_program_cstr().as_ptr(),
-                    file_actions.0.as_ptr(),
-                    attrs.0.as_ptr(),
-                    self.get_argv().as_ptr() as *const _,
-                    envp as *const _,
-                );
-
-                let spawn_res = cvt_nz(spawn_res);
-                if let Err(ref e) = spawn_res
-                    && e.raw_os_error() == Some(libc::ENOSYS)
-                {
-                    PIDFD_SUPPORTED.store(FORK_EXEC, Ordering::Relaxed);
-                    return Ok(None);
-                }
-                spawn_res?;
-
-                let pid = match cvt(pidfd_getpid.get().unwrap()(pidfd)) {
-                    Ok(pid) => pid,
-                    Err(e) => {
-                        // The child has been spawned and we are holding its pidfd.
-                        // But we cannot obtain its pid even though pidfd_getpid support was verified earlier.
-                        // This might happen if libc can't open procfs because the file descriptor limit has been reached.
-                        libc::close(pidfd);
-                        return Err(Error::new(
-                            e.kind(),
-                            "pidfd_spawnp succeeded but the child's PID could not be obtained",
-                        ));
-                    }
-                };
-
-                return Ok(Some(Process::new(pid, pidfd)));
-            }
-
-            // Safety: -1 indicates we don't have a pidfd.
-            let mut p = Process::new(0, -1);
-
-            let spawn_res = spawn_fn(
-                &mut p.pid,
-                self.get_program_cstr().as_ptr(),
-                file_actions.0.as_ptr(),
-                attrs.0.as_ptr(),
-                self.get_argv().as_ptr() as *const _,
-                envp as *const _,
-            );
-
-            #[cfg(target_os = "nto")]
-            let spawn_res = spawn_res?;
-
-            cvt_nz(spawn_res)?;
-            Ok(Some(p))
-        }
-    }
-
-    #[cfg(target_os = "linux")]
-    fn send_pidfd(&self, sock: &crate::sys::net::Socket) {
-        use libc::{CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_SPACE, SCM_RIGHTS, SOL_SOCKET};
-
-        use crate::io::IoSlice;
-        use crate::os::fd::RawFd;
-        use crate::sys::cvt_r;
-
-        unsafe {
-            let child_pid = libc::getpid();
-            // pidfd_open sets CLOEXEC by default
-            let pidfd = libc::syscall(libc::SYS_pidfd_open, child_pid, 0);
-
-            let fds: [c_int; 1] = [pidfd as RawFd];
-
-            const SCM_MSG_LEN: usize = size_of::<[c_int; 1]>();
-
-            #[repr(C)]
-            union Cmsg {
-                buf: [u8; unsafe { CMSG_SPACE(SCM_MSG_LEN as u32) as usize }],
-                _align: libc::cmsghdr,
-            }
-
-            let mut cmsg: Cmsg = mem::zeroed();
-
-            // 0-length message to send through the socket so we can pass along the fd
-            let mut iov = [IoSlice::new(b"")];
-            let mut msg: libc::msghdr = mem::zeroed();
-
-            msg.msg_iov = (&raw mut iov) as *mut _;
-            msg.msg_iovlen = 1;
-
-            // only attach cmsg if we successfully acquired the pidfd
-            if pidfd >= 0 {
-                msg.msg_controllen = size_of_val(&cmsg.buf) as _;
-                msg.msg_control = (&raw mut cmsg.buf) as *mut _;
-
-                let hdr = CMSG_FIRSTHDR((&raw mut msg) as *mut _);
-                (*hdr).cmsg_level = SOL_SOCKET;
-                (*hdr).cmsg_type = SCM_RIGHTS;
-                (*hdr).cmsg_len = CMSG_LEN(SCM_MSG_LEN as _) as _;
-                let data = CMSG_DATA(hdr);
-                crate::ptr::copy_nonoverlapping(
-                    fds.as_ptr().cast::<u8>(),
-                    data as *mut _,
-                    SCM_MSG_LEN,
-                );
-            }
-
-            // we send the 0-length message even if we failed to acquire the pidfd
-            // so we get a consistent SEQPACKET order
-            match cvt_r(|| libc::sendmsg(sock.as_raw(), &msg, 0)) {
-                Ok(0) => {}
-                other => rtabort!("failed to communicate with parent process. {:?}", other),
-            }
-        }
-    }
-
-    #[cfg(target_os = "linux")]
-    fn recv_pidfd(&self, sock: &crate::sys::net::Socket) -> pid_t {
-        use libc::{CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_SPACE, SCM_RIGHTS, SOL_SOCKET};
-
-        use crate::io::IoSliceMut;
-        use crate::sys::cvt_r;
-
-        unsafe {
-            const SCM_MSG_LEN: usize = size_of::<[c_int; 1]>();
-
-            #[repr(C)]
-            union Cmsg {
-                _buf: [u8; unsafe { CMSG_SPACE(SCM_MSG_LEN as u32) as usize }],
-                _align: libc::cmsghdr,
-            }
-            let mut cmsg: Cmsg = mem::zeroed();
-            // 0-length read to get the fd
-            let mut iov = [IoSliceMut::new(&mut [])];
-
-            let mut msg: libc::msghdr = mem::zeroed();
-
-            msg.msg_iov = (&raw mut iov) as *mut _;
-            msg.msg_iovlen = 1;
-            msg.msg_controllen = size_of::<Cmsg>() as _;
-            msg.msg_control = (&raw mut cmsg) as *mut _;
-
-            match cvt_r(|| libc::recvmsg(sock.as_raw(), &mut msg, libc::MSG_CMSG_CLOEXEC)) {
-                Err(_) => return -1,
-                Ok(_) => {}
-            }
-
-            let hdr = CMSG_FIRSTHDR((&raw mut msg) as *mut _);
-            if hdr.is_null()
-                || (*hdr).cmsg_level != SOL_SOCKET
-                || (*hdr).cmsg_type != SCM_RIGHTS
-                || (*hdr).cmsg_len != CMSG_LEN(SCM_MSG_LEN as _) as _
-            {
-                return -1;
-            }
-            let data = CMSG_DATA(hdr);
-
-            let mut fds = [-1 as c_int];
-
-            crate::ptr::copy_nonoverlapping(
-                data as *const _,
-                fds.as_mut_ptr().cast::<u8>(),
-                SCM_MSG_LEN,
-            );
-
-            fds[0]
-        }
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Processes
-////////////////////////////////////////////////////////////////////////////////
-
-/// The unique ID of the process (this should never be negative).
-pub struct Process {
-    pid: pid_t,
-    status: Option<ExitStatus>,
-    // On Linux, stores the pidfd created for this child.
-    // This is None if the user did not request pidfd creation,
-    // or if the pidfd could not be created for some reason
-    // (e.g. the `pidfd_open` syscall was not available).
-    #[cfg(target_os = "linux")]
-    pidfd: Option<PidFd>,
-}
-
-impl Process {
-    #[cfg(target_os = "linux")]
-    /// # Safety
-    ///
-    /// `pidfd` must either be -1 (representing no file descriptor) or a valid, exclusively owned file
-    /// descriptor (See [I/O Safety]).
-    ///
-    /// [I/O Safety]: crate::io#io-safety
-    unsafe fn new(pid: pid_t, pidfd: pid_t) -> Self {
-        use crate::os::unix::io::FromRawFd;
-        use crate::sys_common::FromInner;
-        // Safety: If `pidfd` is nonnegative, we assume it's valid and otherwise unowned.
-        let pidfd = (pidfd >= 0).then(|| PidFd::from_inner(sys::fd::FileDesc::from_raw_fd(pidfd)));
-        Process { pid, status: None, pidfd }
-    }
-
-    #[cfg(not(target_os = "linux"))]
-    unsafe fn new(pid: pid_t, _pidfd: pid_t) -> Self {
-        Process { pid, status: None }
-    }
-
-    pub fn id(&self) -> u32 {
-        self.pid as u32
-    }
-
-    pub fn kill(&mut self) -> io::Result<()> {
-        // If we've already waited on this process then the pid can be recycled
-        // and used for another process, and we probably shouldn't be killing
-        // random processes, so return Ok because the process has exited already.
-        if self.status.is_some() {
-            return Ok(());
-        }
-        #[cfg(target_os = "linux")]
-        if let Some(pid_fd) = self.pidfd.as_ref() {
-            // pidfd_send_signal predates pidfd_open. so if we were able to get an fd then sending signals will work too
-            return pid_fd.kill();
-        }
-        cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
-    }
-
-    pub fn wait(&mut self) -> io::Result<ExitStatus> {
-        use crate::sys::cvt_r;
-        if let Some(status) = self.status {
-            return Ok(status);
-        }
-        #[cfg(target_os = "linux")]
-        if let Some(pid_fd) = self.pidfd.as_ref() {
-            let status = pid_fd.wait()?;
-            self.status = Some(status);
-            return Ok(status);
-        }
-        let mut status = 0 as c_int;
-        cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?;
-        self.status = Some(ExitStatus::new(status));
-        Ok(ExitStatus::new(status))
-    }
-
-    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
-        if let Some(status) = self.status {
-            return Ok(Some(status));
-        }
-        #[cfg(target_os = "linux")]
-        if let Some(pid_fd) = self.pidfd.as_ref() {
-            let status = pid_fd.try_wait()?;
-            if let Some(status) = status {
-                self.status = Some(status)
-            }
-            return Ok(status);
-        }
-        let mut status = 0 as c_int;
-        let pid = cvt(unsafe { libc::waitpid(self.pid, &mut status, libc::WNOHANG) })?;
-        if pid == 0 {
-            Ok(None)
-        } else {
-            self.status = Some(ExitStatus::new(status));
-            Ok(Some(ExitStatus::new(status)))
-        }
-    }
-}
-
-/// Unix exit statuses
-//
-// This is not actually an "exit status" in Unix terminology.  Rather, it is a "wait status".
-// See the discussion in comments and doc comments for `std::process::ExitStatus`.
-#[derive(PartialEq, Eq, Clone, Copy, Default)]
-pub struct ExitStatus(c_int);
-
-impl fmt::Debug for ExitStatus {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("unix_wait_status").field(&self.0).finish()
-    }
-}
-
-impl ExitStatus {
-    pub fn new(status: c_int) -> ExitStatus {
-        ExitStatus(status)
-    }
-
-    #[cfg(target_os = "linux")]
-    pub fn from_waitid_siginfo(siginfo: libc::siginfo_t) -> ExitStatus {
-        let status = unsafe { siginfo.si_status() };
-
-        match siginfo.si_code {
-            libc::CLD_EXITED => ExitStatus((status & 0xff) << 8),
-            libc::CLD_KILLED => ExitStatus(status),
-            libc::CLD_DUMPED => ExitStatus(status | 0x80),
-            libc::CLD_CONTINUED => ExitStatus(0xffff),
-            libc::CLD_STOPPED | libc::CLD_TRAPPED => ExitStatus(((status & 0xff) << 8) | 0x7f),
-            _ => unreachable!("waitid() should only return the above codes"),
-        }
-    }
-
-    fn exited(&self) -> bool {
-        libc::WIFEXITED(self.0)
-    }
-
-    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
-        // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
-        // true on all actual versions of Unix, is widely assumed, and is specified in SuS
-        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not
-        // true for a platform pretending to be Unix, the tests (our doctests, and also
-        // process_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
-        match NonZero::try_from(self.0) {
-            /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)),
-            /* was zero, couldn't convert */ Err(_) => Ok(()),
-        }
-    }
-
-    pub fn code(&self) -> Option<i32> {
-        self.exited().then(|| libc::WEXITSTATUS(self.0))
-    }
-
-    pub fn signal(&self) -> Option<i32> {
-        libc::WIFSIGNALED(self.0).then(|| libc::WTERMSIG(self.0))
-    }
-
-    pub fn core_dumped(&self) -> bool {
-        libc::WIFSIGNALED(self.0) && libc::WCOREDUMP(self.0)
-    }
-
-    pub fn stopped_signal(&self) -> Option<i32> {
-        libc::WIFSTOPPED(self.0).then(|| libc::WSTOPSIG(self.0))
-    }
-
-    pub fn continued(&self) -> bool {
-        libc::WIFCONTINUED(self.0)
-    }
-
-    pub fn into_raw(&self) -> c_int {
-        self.0
-    }
-}
-
-/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying.
-impl From<c_int> for ExitStatus {
-    fn from(a: c_int) -> ExitStatus {
-        ExitStatus(a)
-    }
-}
-
-/// Converts a signal number to a readable, searchable name.
-///
-/// This string should be displayed right after the signal number.
-/// If a signal is unrecognized, it returns the empty string, so that
-/// you just get the number like "0". If it is recognized, you'll get
-/// something like "9 (SIGKILL)".
-fn signal_string(signal: i32) -> &'static str {
-    match signal {
-        libc::SIGHUP => " (SIGHUP)",
-        libc::SIGINT => " (SIGINT)",
-        libc::SIGQUIT => " (SIGQUIT)",
-        libc::SIGILL => " (SIGILL)",
-        libc::SIGTRAP => " (SIGTRAP)",
-        libc::SIGABRT => " (SIGABRT)",
-        #[cfg(not(target_os = "l4re"))]
-        libc::SIGBUS => " (SIGBUS)",
-        libc::SIGFPE => " (SIGFPE)",
-        libc::SIGKILL => " (SIGKILL)",
-        #[cfg(not(target_os = "l4re"))]
-        libc::SIGUSR1 => " (SIGUSR1)",
-        libc::SIGSEGV => " (SIGSEGV)",
-        #[cfg(not(target_os = "l4re"))]
-        libc::SIGUSR2 => " (SIGUSR2)",
-        libc::SIGPIPE => " (SIGPIPE)",
-        libc::SIGALRM => " (SIGALRM)",
-        libc::SIGTERM => " (SIGTERM)",
-        #[cfg(not(target_os = "l4re"))]
-        libc::SIGCHLD => " (SIGCHLD)",
-        #[cfg(not(target_os = "l4re"))]
-        libc::SIGCONT => " (SIGCONT)",
-        #[cfg(not(target_os = "l4re"))]
-        libc::SIGSTOP => " (SIGSTOP)",
-        #[cfg(not(target_os = "l4re"))]
-        libc::SIGTSTP => " (SIGTSTP)",
-        #[cfg(not(target_os = "l4re"))]
-        libc::SIGTTIN => " (SIGTTIN)",
-        #[cfg(not(target_os = "l4re"))]
-        libc::SIGTTOU => " (SIGTTOU)",
-        #[cfg(not(target_os = "l4re"))]
-        libc::SIGURG => " (SIGURG)",
-        #[cfg(not(target_os = "l4re"))]
-        libc::SIGXCPU => " (SIGXCPU)",
-        #[cfg(not(any(target_os = "l4re", target_os = "rtems")))]
-        libc::SIGXFSZ => " (SIGXFSZ)",
-        #[cfg(not(any(target_os = "l4re", target_os = "rtems")))]
-        libc::SIGVTALRM => " (SIGVTALRM)",
-        #[cfg(not(target_os = "l4re"))]
-        libc::SIGPROF => " (SIGPROF)",
-        #[cfg(not(any(target_os = "l4re", target_os = "rtems")))]
-        libc::SIGWINCH => " (SIGWINCH)",
-        #[cfg(not(any(target_os = "haiku", target_os = "l4re")))]
-        libc::SIGIO => " (SIGIO)",
-        #[cfg(target_os = "haiku")]
-        libc::SIGPOLL => " (SIGPOLL)",
-        #[cfg(not(target_os = "l4re"))]
-        libc::SIGSYS => " (SIGSYS)",
-        // For information on Linux signals, run `man 7 signal`
-        #[cfg(all(
-            target_os = "linux",
-            any(
-                target_arch = "x86_64",
-                target_arch = "x86",
-                target_arch = "arm",
-                target_arch = "aarch64"
-            )
-        ))]
-        libc::SIGSTKFLT => " (SIGSTKFLT)",
-        #[cfg(any(target_os = "linux", target_os = "nto", target_os = "cygwin"))]
-        libc::SIGPWR => " (SIGPWR)",
-        #[cfg(any(
-            target_os = "freebsd",
-            target_os = "netbsd",
-            target_os = "openbsd",
-            target_os = "dragonfly",
-            target_os = "nto",
-            target_vendor = "apple",
-            target_os = "cygwin",
-        ))]
-        libc::SIGEMT => " (SIGEMT)",
-        #[cfg(any(
-            target_os = "freebsd",
-            target_os = "netbsd",
-            target_os = "openbsd",
-            target_os = "dragonfly",
-            target_vendor = "apple",
-        ))]
-        libc::SIGINFO => " (SIGINFO)",
-        #[cfg(target_os = "hurd")]
-        libc::SIGLOST => " (SIGLOST)",
-        #[cfg(target_os = "freebsd")]
-        libc::SIGTHR => " (SIGTHR)",
-        #[cfg(target_os = "freebsd")]
-        libc::SIGLIBRT => " (SIGLIBRT)",
-        _ => "",
-    }
-}
-
-impl fmt::Display for ExitStatus {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if let Some(code) = self.code() {
-            write!(f, "exit status: {code}")
-        } else if let Some(signal) = self.signal() {
-            let signal_string = signal_string(signal);
-            if self.core_dumped() {
-                write!(f, "signal: {signal}{signal_string} (core dumped)")
-            } else {
-                write!(f, "signal: {signal}{signal_string}")
-            }
-        } else if let Some(signal) = self.stopped_signal() {
-            let signal_string = signal_string(signal);
-            write!(f, "stopped (not terminated) by signal: {signal}{signal_string}")
-        } else if self.continued() {
-            write!(f, "continued (WIFCONTINUED)")
-        } else {
-            write!(f, "unrecognised wait status: {} {:#x}", self.0, self.0)
-        }
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy)]
-pub struct ExitStatusError(NonZero<c_int>);
-
-impl Into<ExitStatus> for ExitStatusError {
-    fn into(self) -> ExitStatus {
-        ExitStatus(self.0.into())
-    }
-}
-
-impl fmt::Debug for ExitStatusError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("unix_wait_status").field(&self.0).finish()
-    }
-}
-
-impl ExitStatusError {
-    pub fn code(self) -> Option<NonZero<i32>> {
-        ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap())
-    }
-}
-
-#[cfg(target_os = "linux")]
-mod linux_child_ext {
-
-    use crate::os::linux::process as os;
-    use crate::sys::pal::unix::ErrorKind;
-    use crate::sys::pal::unix::linux::pidfd as imp;
-    use crate::sys_common::FromInner;
-    use crate::{io, mem};
-
-    #[unstable(feature = "linux_pidfd", issue = "82971")]
-    impl crate::os::linux::process::ChildExt for crate::process::Child {
-        fn pidfd(&self) -> io::Result<&os::PidFd> {
-            self.handle
-                .pidfd
-                .as_ref()
-                // SAFETY: The os type is a transparent wrapper, therefore we can transmute references
-                .map(|fd| unsafe { mem::transmute::<&imp::PidFd, &os::PidFd>(fd) })
-                .ok_or_else(|| io::const_error!(ErrorKind::Uncategorized, "no pidfd was created."))
-        }
-
-        fn into_pidfd(mut self) -> Result<os::PidFd, Self> {
-            self.handle
-                .pidfd
-                .take()
-                .map(|fd| <os::PidFd as FromInner<imp::PidFd>>::from_inner(fd))
-                .ok_or_else(|| self)
-        }
-    }
-}
-
-#[cfg(test)]
-#[path = "process_unix/tests.rs"]
-mod tests;
-
-// See [`process_unsupported_wait_status::compare_with_linux`];
-#[cfg(all(test, target_os = "linux"))]
-#[path = "process_unsupported/wait_status.rs"]
-mod process_unsupported_wait_status;
diff --git a/library/std/src/sys/pal/unix/process/process_unix/tests.rs b/library/std/src/sys/pal/unix/process/process_unix/tests.rs
deleted file mode 100644
index f4d6ac6b4e3..00000000000
--- a/library/std/src/sys/pal/unix/process/process_unix/tests.rs
+++ /dev/null
@@ -1,75 +0,0 @@
-use crate::os::unix::process::{CommandExt, ExitStatusExt};
-use crate::panic::catch_unwind;
-use crate::process::Command;
-
-// Many of the other aspects of this situation, including heap alloc concurrency
-// safety etc., are tested in tests/ui/process/process-panic-after-fork.rs
-
-#[test]
-fn exitstatus_display_tests() {
-    // In practice this is the same on every Unix.
-    // If some weird platform turns out to be different, and this test fails, use #[cfg].
-    use crate::os::unix::process::ExitStatusExt;
-    use crate::process::ExitStatus;
-
-    let t = |v, s| assert_eq!(s, format!("{}", <ExitStatus as ExitStatusExt>::from_raw(v)));
-
-    t(0x0000f, "signal: 15 (SIGTERM)");
-    t(0x0008b, "signal: 11 (SIGSEGV) (core dumped)");
-    t(0x00000, "exit status: 0");
-    t(0x0ff00, "exit status: 255");
-
-    // On MacOS, 0x0137f is WIFCONTINUED, not WIFSTOPPED. Probably *BSD is similar.
-    //   https://github.com/rust-lang/rust/pull/82749#issuecomment-790525956
-    // The purpose of this test is to test our string formatting, not our understanding of the wait
-    // status magic numbers. So restrict these to Linux.
-    if cfg!(target_os = "linux") {
-        #[cfg(any(target_arch = "mips", target_arch = "mips64"))]
-        t(0x0137f, "stopped (not terminated) by signal: 19 (SIGPWR)");
-
-        #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))]
-        t(0x0137f, "stopped (not terminated) by signal: 19 (SIGCONT)");
-
-        #[cfg(not(any(
-            target_arch = "mips",
-            target_arch = "mips64",
-            target_arch = "sparc",
-            target_arch = "sparc64"
-        )))]
-        t(0x0137f, "stopped (not terminated) by signal: 19 (SIGSTOP)");
-
-        t(0x0ffff, "continued (WIFCONTINUED)");
-    }
-
-    // Testing "unrecognised wait status" is hard because the wait.h macros typically
-    // assume that the value came from wait and isn't mad. With the glibc I have here
-    // this works:
-    if cfg!(all(target_os = "linux", target_env = "gnu")) {
-        t(0x000ff, "unrecognised wait status: 255 0xff");
-    }
-}
-
-#[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
-fn test_command_fork_no_unwind() {
-    let got = catch_unwind(|| {
-        let mut c = Command::new("echo");
-        c.arg("hi");
-        unsafe {
-            c.pre_exec(|| panic!("{}", "crash now!"));
-        }
-        let st = c.status().expect("failed to get command status");
-        dbg!(st);
-        st
-    });
-    dbg!(&got);
-    let status = got.expect("panic unexpectedly propagated");
-    dbg!(status);
-    let signal = status.signal().expect("expected child process to die of signal");
-    assert!(
-        signal == libc::SIGABRT
-            || signal == libc::SIGILL
-            || signal == libc::SIGTRAP
-            || signal == libc::SIGSEGV
-    );
-}
diff --git a/library/std/src/sys/pal/unix/process/process_unsupported.rs b/library/std/src/sys/pal/unix/process/process_unsupported.rs
deleted file mode 100644
index c58548835ff..00000000000
--- a/library/std/src/sys/pal/unix/process/process_unsupported.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-use libc::{c_int, pid_t};
-
-use crate::io;
-use crate::num::NonZero;
-use crate::sys::pal::unix::unsupported::*;
-use crate::sys::process::process_common::*;
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-impl Command {
-    pub fn spawn(
-        &mut self,
-        _default: Stdio,
-        _needs_stdin: bool,
-    ) -> io::Result<(Process, StdioPipes)> {
-        unsupported()
-    }
-
-    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
-        unsupported()
-    }
-
-    pub fn exec(&mut self, _default: Stdio) -> io::Error {
-        unsupported_err()
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Processes
-////////////////////////////////////////////////////////////////////////////////
-
-pub struct Process {
-    _handle: pid_t,
-}
-
-impl Process {
-    pub fn id(&self) -> u32 {
-        0
-    }
-
-    pub fn kill(&mut self) -> io::Result<()> {
-        unsupported()
-    }
-
-    pub fn wait(&mut self) -> io::Result<ExitStatus> {
-        unsupported()
-    }
-
-    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
-        unsupported()
-    }
-}
-
-mod wait_status;
-pub use wait_status::ExitStatus;
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitStatusError(NonZero<c_int>);
-
-impl Into<ExitStatus> for ExitStatusError {
-    fn into(self) -> ExitStatus {
-        ExitStatus::from(c_int::from(self.0))
-    }
-}
-
-impl ExitStatusError {
-    pub fn code(self) -> Option<NonZero<i32>> {
-        ExitStatus::from(c_int::from(self.0)).code().map(|st| st.try_into().unwrap())
-    }
-}
diff --git a/library/std/src/sys/pal/unix/process/process_unsupported/wait_status.rs b/library/std/src/sys/pal/unix/process/process_unsupported/wait_status.rs
deleted file mode 100644
index f04036bde49..00000000000
--- a/library/std/src/sys/pal/unix/process/process_unsupported/wait_status.rs
+++ /dev/null
@@ -1,83 +0,0 @@
-//! Emulated wait status for non-Unix #[cfg(unix) platforms
-//!
-//! Separate module to facilitate testing against a real Unix implementation.
-
-use super::ExitStatusError;
-use crate::ffi::c_int;
-use crate::fmt;
-use crate::num::NonZero;
-
-/// Emulated wait status for use by `process_unsupported.rs`
-///
-/// Uses the "traditional unix" encoding.  For use on platfors which are `#[cfg(unix)]`
-/// but do not actually support subprocesses at all.
-///
-/// These platforms aren't Unix, but are simply pretending to be for porting convenience.
-/// So, we provide a faithful pretence here.
-#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
-pub struct ExitStatus {
-    wait_status: c_int,
-}
-
-/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it
-impl From<c_int> for ExitStatus {
-    fn from(wait_status: c_int) -> ExitStatus {
-        ExitStatus { wait_status }
-    }
-}
-
-impl fmt::Display for ExitStatus {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "emulated wait status: {}", self.wait_status)
-    }
-}
-
-impl ExitStatus {
-    pub fn code(&self) -> Option<i32> {
-        // Linux and FreeBSD both agree that values linux 0x80
-        // count as "WIFEXITED" even though this is quite mad.
-        // Likewise the macros disregard all the high bits, so are happy to declare
-        // out-of-range values to be WIFEXITED, WIFSTOPPED, etc.
-        let w = self.wait_status;
-        if (w & 0x7f) == 0 { Some((w & 0xff00) >> 8) } else { None }
-    }
-
-    #[allow(unused)]
-    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
-        // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
-        // true on all actual versions of Unix, is widely assumed, and is specified in SuS
-        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not
-        // true for a platform pretending to be Unix, the tests (our doctests, and also
-        // process_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
-        match NonZero::try_from(self.wait_status) {
-            /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)),
-            /* was zero, couldn't convert */ Err(_) => Ok(()),
-        }
-    }
-
-    pub fn signal(&self) -> Option<i32> {
-        let signal = self.wait_status & 0x007f;
-        if signal > 0 && signal < 0x7f { Some(signal) } else { None }
-    }
-
-    pub fn core_dumped(&self) -> bool {
-        self.signal().is_some() && (self.wait_status & 0x80) != 0
-    }
-
-    pub fn stopped_signal(&self) -> Option<i32> {
-        let w = self.wait_status;
-        if (w & 0xff) == 0x7f { Some((w & 0xff00) >> 8) } else { None }
-    }
-
-    pub fn continued(&self) -> bool {
-        self.wait_status == 0xffff
-    }
-
-    pub fn into_raw(&self) -> c_int {
-        self.wait_status
-    }
-}
-
-#[cfg(test)]
-#[path = "wait_status/tests.rs"] // needed because of strange layout of process_unsupported
-mod tests;
diff --git a/library/std/src/sys/pal/unix/process/process_unsupported/wait_status/tests.rs b/library/std/src/sys/pal/unix/process/process_unsupported/wait_status/tests.rs
deleted file mode 100644
index 5132eab10a1..00000000000
--- a/library/std/src/sys/pal/unix/process/process_unsupported/wait_status/tests.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-// Note that tests in this file are run on Linux as well as on platforms using process_unsupported
-
-// Test that our emulation exactly matches Linux
-//
-// This test runs *on Linux* but it tests
-// the implementation used on non-Unix `#[cfg(unix)]` platforms.
-//
-// I.e. we're using Linux as a proxy for "trad unix".
-#[cfg(target_os = "linux")]
-#[test]
-fn compare_with_linux() {
-    use super::ExitStatus as Emulated;
-    use crate::os::unix::process::ExitStatusExt as _;
-    use crate::process::ExitStatus as Real;
-
-    // Check that we handle out-of-range values similarly, too.
-    for wstatus in -0xf_ffff..0xf_ffff {
-        let emulated = Emulated::from(wstatus);
-        let real = Real::from_raw(wstatus);
-
-        macro_rules! compare { { $method:ident } => {
-            assert_eq!(
-                emulated.$method(),
-                real.$method(),
-                "{wstatus:#x}.{}()",
-                stringify!($method),
-            );
-        } }
-        compare!(code);
-        compare!(signal);
-        compare!(core_dumped);
-        compare!(stopped_signal);
-        compare!(continued);
-        compare!(into_raw);
-    }
-}
diff --git a/library/std/src/sys/pal/unix/process/process_vxworks.rs b/library/std/src/sys/pal/unix/process/process_vxworks.rs
deleted file mode 100644
index e2c1b6a0326..00000000000
--- a/library/std/src/sys/pal/unix/process/process_vxworks.rs
+++ /dev/null
@@ -1,268 +0,0 @@
-#![forbid(unsafe_op_in_unsafe_fn)]
-use libc::{self, RTP_ID, c_char, c_int};
-
-use crate::io::{self, ErrorKind};
-use crate::num::NonZero;
-use crate::sys::cvt;
-use crate::sys::pal::unix::thread;
-use crate::sys::process::process_common::*;
-use crate::{fmt, sys};
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-impl Command {
-    pub fn spawn(
-        &mut self,
-        default: Stdio,
-        needs_stdin: bool,
-    ) -> io::Result<(Process, StdioPipes)> {
-        use crate::sys::cvt_r;
-        let envp = self.capture_env();
-
-        if self.saw_nul() {
-            return Err(io::const_error!(
-                ErrorKind::InvalidInput,
-                "nul byte found in provided data",
-            ));
-        }
-        let (ours, theirs) = self.setup_io(default, needs_stdin)?;
-        let mut p = Process { pid: 0, status: None };
-
-        unsafe {
-            macro_rules! t {
-                ($e:expr) => {
-                    match $e {
-                        Ok(e) => e,
-                        Err(e) => return Err(e.into()),
-                    }
-                };
-            }
-
-            let mut orig_stdin = libc::STDIN_FILENO;
-            let mut orig_stdout = libc::STDOUT_FILENO;
-            let mut orig_stderr = libc::STDERR_FILENO;
-
-            if let Some(fd) = theirs.stdin.fd() {
-                orig_stdin = t!(cvt_r(|| libc::dup(libc::STDIN_FILENO)));
-                t!(cvt_r(|| libc::dup2(fd, libc::STDIN_FILENO)));
-            }
-            if let Some(fd) = theirs.stdout.fd() {
-                orig_stdout = t!(cvt_r(|| libc::dup(libc::STDOUT_FILENO)));
-                t!(cvt_r(|| libc::dup2(fd, libc::STDOUT_FILENO)));
-            }
-            if let Some(fd) = theirs.stderr.fd() {
-                orig_stderr = t!(cvt_r(|| libc::dup(libc::STDERR_FILENO)));
-                t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO)));
-            }
-
-            if let Some(cwd) = self.get_cwd() {
-                t!(cvt(libc::chdir(cwd.as_ptr())));
-            }
-
-            // pre_exec closures are ignored on VxWorks
-            let _ = self.get_closures();
-
-            let c_envp = envp
-                .as_ref()
-                .map(|c| c.as_ptr())
-                .unwrap_or_else(|| *sys::os::environ() as *const _);
-            let stack_size = crate::cmp::max(
-                crate::env::var_os("RUST_MIN_STACK")
-                    .and_then(|s| s.to_str().and_then(|s| s.parse().ok()))
-                    .unwrap_or(thread::DEFAULT_MIN_STACK_SIZE),
-                libc::PTHREAD_STACK_MIN,
-            );
-
-            // ensure that access to the environment is synchronized
-            let _lock = sys::os::env_read_lock();
-
-            let ret = libc::rtpSpawn(
-                self.get_program_cstr().as_ptr(),
-                self.get_argv().as_ptr() as *mut *const c_char, // argv
-                c_envp as *mut *const c_char,
-                100 as c_int, // initial priority
-                stack_size,   // initial stack size.
-                0,            // options
-                0,            // task options
-            );
-
-            // Because FileDesc was not used, each duplicated file descriptor
-            // needs to be closed manually
-            if orig_stdin != libc::STDIN_FILENO {
-                t!(cvt_r(|| libc::dup2(orig_stdin, libc::STDIN_FILENO)));
-                libc::close(orig_stdin);
-            }
-            if orig_stdout != libc::STDOUT_FILENO {
-                t!(cvt_r(|| libc::dup2(orig_stdout, libc::STDOUT_FILENO)));
-                libc::close(orig_stdout);
-            }
-            if orig_stderr != libc::STDERR_FILENO {
-                t!(cvt_r(|| libc::dup2(orig_stderr, libc::STDERR_FILENO)));
-                libc::close(orig_stderr);
-            }
-
-            if ret != libc::RTP_ID_ERROR {
-                p.pid = ret;
-                Ok((p, ours))
-            } else {
-                Err(io::Error::last_os_error())
-            }
-        }
-    }
-
-    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
-        let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
-        crate::sys_common::process::wait_with_output(proc, pipes)
-    }
-
-    pub fn exec(&mut self, default: Stdio) -> io::Error {
-        let ret = Command::spawn(self, default, false);
-        match ret {
-            Ok(t) => unsafe {
-                let mut status = 0 as c_int;
-                libc::waitpid(t.0.pid, &mut status, 0);
-                libc::exit(0);
-            },
-            Err(e) => e,
-        }
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Processes
-////////////////////////////////////////////////////////////////////////////////
-
-/// The unique id of the process (this should never be negative).
-pub struct Process {
-    pid: RTP_ID,
-    status: Option<ExitStatus>,
-}
-
-impl Process {
-    pub fn id(&self) -> u32 {
-        self.pid as u32
-    }
-
-    pub fn kill(&mut self) -> io::Result<()> {
-        // If we've already waited on this process then the pid can be recycled
-        // and used for another process, and we probably shouldn't be killing
-        // random processes, so return Ok because the process has exited already.
-        if self.status.is_some() {
-            Ok(())
-        } else {
-            cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
-        }
-    }
-
-    pub fn wait(&mut self) -> io::Result<ExitStatus> {
-        use crate::sys::cvt_r;
-        if let Some(status) = self.status {
-            return Ok(status);
-        }
-        let mut status = 0 as c_int;
-        cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?;
-        self.status = Some(ExitStatus::new(status));
-        Ok(ExitStatus::new(status))
-    }
-
-    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
-        if let Some(status) = self.status {
-            return Ok(Some(status));
-        }
-        let mut status = 0 as c_int;
-        let pid = cvt(unsafe { libc::waitpid(self.pid, &mut status, libc::WNOHANG) })?;
-        if pid == 0 {
-            Ok(None)
-        } else {
-            self.status = Some(ExitStatus::new(status));
-            Ok(Some(ExitStatus::new(status)))
-        }
-    }
-}
-
-/// Unix exit statuses
-#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
-pub struct ExitStatus(c_int);
-
-impl ExitStatus {
-    pub fn new(status: c_int) -> ExitStatus {
-        ExitStatus(status)
-    }
-
-    fn exited(&self) -> bool {
-        libc::WIFEXITED(self.0)
-    }
-
-    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
-        // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
-        // true on all actual versions of Unix, is widely assumed, and is specified in SuS
-        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not
-        // true for a platform pretending to be Unix, the tests (our doctests, and also
-        // process_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
-        match NonZero::try_from(self.0) {
-            Ok(failure) => Err(ExitStatusError(failure)),
-            Err(_) => Ok(()),
-        }
-    }
-
-    pub fn code(&self) -> Option<i32> {
-        if self.exited() { Some(libc::WEXITSTATUS(self.0)) } else { None }
-    }
-
-    pub fn signal(&self) -> Option<i32> {
-        if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None }
-    }
-
-    pub fn core_dumped(&self) -> bool {
-        // This method is not yet properly implemented on VxWorks
-        false
-    }
-
-    pub fn stopped_signal(&self) -> Option<i32> {
-        if libc::WIFSTOPPED(self.0) { Some(libc::WSTOPSIG(self.0)) } else { None }
-    }
-
-    pub fn continued(&self) -> bool {
-        // This method is not yet properly implemented on VxWorks
-        false
-    }
-
-    pub fn into_raw(&self) -> c_int {
-        self.0
-    }
-}
-
-/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying.
-impl From<c_int> for ExitStatus {
-    fn from(a: c_int) -> ExitStatus {
-        ExitStatus(a)
-    }
-}
-
-impl fmt::Display for ExitStatus {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if let Some(code) = self.code() {
-            write!(f, "exit code: {code}")
-        } else {
-            let signal = self.signal().unwrap();
-            write!(f, "signal: {signal}")
-        }
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitStatusError(NonZero<c_int>);
-
-impl Into<ExitStatus> for ExitStatusError {
-    fn into(self) -> ExitStatus {
-        ExitStatus(self.0.into())
-    }
-}
-
-impl ExitStatusError {
-    pub fn code(self) -> Option<NonZero<i32>> {
-        ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap())
-    }
-}
diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs
index bcea699f3b2..38838b915b5 100644
--- a/library/std/src/sys/pal/unsupported/mod.rs
+++ b/library/std/src/sys/pal/unsupported/mod.rs
@@ -4,7 +4,6 @@ pub mod args;
 pub mod env;
 pub mod os;
 pub mod pipe;
-pub mod process;
 pub mod thread;
 pub mod time;
 
diff --git a/library/std/src/sys/pal/unsupported/process.rs b/library/std/src/sys/pal/unsupported/process.rs
deleted file mode 100644
index fee81744f09..00000000000
--- a/library/std/src/sys/pal/unsupported/process.rs
+++ /dev/null
@@ -1,322 +0,0 @@
-pub use crate::ffi::OsString as EnvKey;
-use crate::ffi::{OsStr, OsString};
-use crate::num::NonZero;
-use crate::path::Path;
-use crate::sys::fs::File;
-use crate::sys::pipe::AnonPipe;
-use crate::sys::unsupported;
-use crate::sys_common::process::{CommandEnv, CommandEnvs};
-use crate::{fmt, io};
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-pub struct Command {
-    program: OsString,
-    args: Vec<OsString>,
-    env: CommandEnv,
-
-    cwd: Option<OsString>,
-    stdin: Option<Stdio>,
-    stdout: Option<Stdio>,
-    stderr: Option<Stdio>,
-}
-
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
-    pub stdin: Option<AnonPipe>,
-    pub stdout: Option<AnonPipe>,
-    pub stderr: Option<AnonPipe>,
-}
-
-#[derive(Debug)]
-pub enum Stdio {
-    Inherit,
-    Null,
-    MakePipe,
-    ParentStdout,
-    ParentStderr,
-    #[allow(dead_code)] // This variant exists only for the Debug impl
-    InheritFile(File),
-}
-
-impl Command {
-    pub fn new(program: &OsStr) -> Command {
-        Command {
-            program: program.to_owned(),
-            args: vec![program.to_owned()],
-            env: Default::default(),
-            cwd: None,
-            stdin: None,
-            stdout: None,
-            stderr: None,
-        }
-    }
-
-    pub fn arg(&mut self, arg: &OsStr) {
-        self.args.push(arg.to_owned());
-    }
-
-    pub fn env_mut(&mut self) -> &mut CommandEnv {
-        &mut self.env
-    }
-
-    pub fn cwd(&mut self, dir: &OsStr) {
-        self.cwd = Some(dir.to_owned());
-    }
-
-    pub fn stdin(&mut self, stdin: Stdio) {
-        self.stdin = Some(stdin);
-    }
-
-    pub fn stdout(&mut self, stdout: Stdio) {
-        self.stdout = Some(stdout);
-    }
-
-    pub fn stderr(&mut self, stderr: Stdio) {
-        self.stderr = Some(stderr);
-    }
-
-    pub fn get_program(&self) -> &OsStr {
-        &self.program
-    }
-
-    pub fn get_args(&self) -> CommandArgs<'_> {
-        let mut iter = self.args.iter();
-        iter.next();
-        CommandArgs { iter }
-    }
-
-    pub fn get_envs(&self) -> CommandEnvs<'_> {
-        self.env.iter()
-    }
-
-    pub fn get_current_dir(&self) -> Option<&Path> {
-        self.cwd.as_ref().map(|cs| Path::new(cs))
-    }
-
-    pub fn spawn(
-        &mut self,
-        _default: Stdio,
-        _needs_stdin: bool,
-    ) -> io::Result<(Process, StdioPipes)> {
-        unsupported()
-    }
-
-    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
-        unsupported()
-    }
-}
-
-impl From<AnonPipe> for Stdio {
-    fn from(pipe: AnonPipe) -> Stdio {
-        pipe.diverge()
-    }
-}
-
-impl From<io::Stdout> for Stdio {
-    fn from(_: io::Stdout) -> Stdio {
-        Stdio::ParentStdout
-    }
-}
-
-impl From<io::Stderr> for Stdio {
-    fn from(_: io::Stderr) -> Stdio {
-        Stdio::ParentStderr
-    }
-}
-
-impl From<File> for Stdio {
-    fn from(file: File) -> Stdio {
-        Stdio::InheritFile(file)
-    }
-}
-
-impl fmt::Debug for Command {
-    // show all attributes
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        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.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);
-            }
-
-            debug_command.finish()
-        } else {
-            if let Some(ref cwd) = self.cwd {
-                write!(f, "cd {cwd:?} && ")?;
-            }
-            if self.env.does_clear() {
-                write!(f, "env -i ")?;
-                // Altered env vars will be printed next, that should exactly work as expected.
-            } else {
-                // Removed env vars need the command to be wrapped in `env`.
-                let mut any_removed = false;
-                for (key, value_opt) in self.get_envs() {
-                    if value_opt.is_none() {
-                        if !any_removed {
-                            write!(f, "env ")?;
-                            any_removed = true;
-                        }
-                        write!(f, "-u {} ", key.to_string_lossy())?;
-                    }
-                }
-            }
-            // Altered env vars can just be added in front of the program.
-            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(())
-        }
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
-#[non_exhaustive]
-pub struct ExitStatus();
-
-impl ExitStatus {
-    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
-        Ok(())
-    }
-
-    pub fn code(&self) -> Option<i32> {
-        Some(0)
-    }
-}
-
-impl fmt::Display for ExitStatus {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "<dummy exit status>")
-    }
-}
-
-pub struct ExitStatusError(!);
-
-impl Clone for ExitStatusError {
-    fn clone(&self) -> ExitStatusError {
-        self.0
-    }
-}
-
-impl Copy for ExitStatusError {}
-
-impl PartialEq for ExitStatusError {
-    fn eq(&self, _other: &ExitStatusError) -> bool {
-        self.0
-    }
-}
-
-impl Eq for ExitStatusError {}
-
-impl fmt::Debug for ExitStatusError {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.0
-    }
-}
-
-impl Into<ExitStatus> for ExitStatusError {
-    fn into(self) -> ExitStatus {
-        self.0
-    }
-}
-
-impl ExitStatusError {
-    pub fn code(self) -> Option<NonZero<i32>> {
-        self.0
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitCode(u8);
-
-impl ExitCode {
-    pub const SUCCESS: ExitCode = ExitCode(0);
-    pub const FAILURE: ExitCode = ExitCode(1);
-
-    pub fn as_i32(&self) -> i32 {
-        self.0 as i32
-    }
-}
-
-impl From<u8> for ExitCode {
-    fn from(code: u8) -> Self {
-        Self(code)
-    }
-}
-
-pub struct Process(!);
-
-impl Process {
-    pub fn id(&self) -> u32 {
-        self.0
-    }
-
-    pub fn kill(&mut self) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn wait(&mut self) -> io::Result<ExitStatus> {
-        self.0
-    }
-
-    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
-        self.0
-    }
-}
-
-pub struct CommandArgs<'a> {
-    iter: crate::slice::Iter<'a, OsString>,
-}
-
-impl<'a> Iterator for CommandArgs<'a> {
-    type Item = &'a OsStr;
-    fn next(&mut self) -> Option<&'a OsStr> {
-        self.iter.next().map(|os| &**os)
-    }
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-}
-
-impl<'a> ExactSizeIterator for CommandArgs<'a> {
-    fn len(&self) -> usize {
-        self.iter.len()
-    }
-    fn is_empty(&self) -> bool {
-        self.iter.is_empty()
-    }
-}
-
-impl<'a> fmt::Debug for CommandArgs<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_list().entries(self.iter.clone()).finish()
-    }
-}
diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs
index c89832857dd..cdd613f76b6 100644
--- a/library/std/src/sys/pal/wasi/mod.rs
+++ b/library/std/src/sys/pal/wasi/mod.rs
@@ -23,8 +23,6 @@ pub mod futex;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-#[path = "../unsupported/process.rs"]
-pub mod process;
 pub mod thread;
 pub mod time;
 
diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs
index 3008ba88753..6ac28f1bf4f 100644
--- a/library/std/src/sys/pal/wasip2/mod.rs
+++ b/library/std/src/sys/pal/wasip2/mod.rs
@@ -20,8 +20,6 @@ pub mod futex;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-#[path = "../unsupported/process.rs"]
-pub mod process;
 #[path = "../wasi/thread.rs"]
 pub mod thread;
 #[path = "../wasi/time.rs"]
diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs
index 175fe75357f..8d39b70d039 100644
--- a/library/std/src/sys/pal/wasm/mod.rs
+++ b/library/std/src/sys/pal/wasm/mod.rs
@@ -23,8 +23,6 @@ pub mod env;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-#[path = "../unsupported/process.rs"]
-pub mod process;
 #[path = "../unsupported/time.rs"]
 pub mod time;
 
diff --git a/library/std/src/sys/pal/windows/args.rs b/library/std/src/sys/pal/windows/args.rs
index 3447a0157e4..d973743639a 100644
--- a/library/std/src/sys/pal/windows/args.rs
+++ b/library/std/src/sys/pal/windows/args.rs
@@ -6,13 +6,13 @@
 #[cfg(test)]
 mod tests;
 
+use super::ensure_no_nuls;
 use super::os::current_exe;
 use crate::ffi::{OsStr, OsString};
 use crate::num::NonZero;
 use crate::os::windows::prelude::*;
 use crate::path::{Path, PathBuf};
 use crate::sys::path::get_long_path;
-use crate::sys::process::ensure_no_nuls;
 use crate::sys::{c, to_u16s};
 use crate::sys_common::AsInner;
 use crate::sys_common::wstr::WStrUnits;
diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs
index 6eb68f3a3bc..bdf0cc2c59c 100644
--- a/library/std/src/sys/pal/windows/mod.rs
+++ b/library/std/src/sys/pal/windows/mod.rs
@@ -22,7 +22,6 @@ pub mod futex;
 pub mod handle;
 pub mod os;
 pub mod pipe;
-pub mod process;
 pub mod thread;
 pub mod time;
 cfg_if::cfg_if! {
@@ -287,6 +286,14 @@ pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] {
     }
 }
 
+pub fn ensure_no_nuls<T: AsRef<OsStr>>(s: T) -> crate::io::Result<T> {
+    if s.as_ref().encode_wide().any(|b| b == 0) {
+        Err(crate::io::const_error!(ErrorKind::InvalidInput, "nul byte found in provided data"))
+    } else {
+        Ok(s)
+    }
+}
+
 pub trait IsZero {
     fn is_zero(&self) -> bool;
 }
diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs
deleted file mode 100644
index 50e4baba607..00000000000
--- a/library/std/src/sys/pal/windows/process.rs
+++ /dev/null
@@ -1,929 +0,0 @@
-#![unstable(feature = "process_internals", issue = "none")]
-
-#[cfg(test)]
-mod tests;
-
-use core::ffi::c_void;
-
-use super::api::{self, WinError};
-use crate::collections::BTreeMap;
-use crate::env::consts::{EXE_EXTENSION, EXE_SUFFIX};
-use crate::ffi::{OsStr, OsString};
-use crate::io::{self, Error, ErrorKind};
-use crate::num::NonZero;
-use crate::os::windows::ffi::{OsStrExt, OsStringExt};
-use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle};
-use crate::os::windows::process::ProcThreadAttributeList;
-use crate::path::{Path, PathBuf};
-use crate::sync::Mutex;
-use crate::sys::args::{self, Arg};
-use crate::sys::c::{self, EXIT_FAILURE, EXIT_SUCCESS};
-use crate::sys::fs::{File, OpenOptions};
-use crate::sys::handle::Handle;
-use crate::sys::pipe::{self, AnonPipe};
-use crate::sys::{cvt, path, stdio};
-use crate::sys_common::IntoInner;
-use crate::sys_common::process::{CommandEnv, CommandEnvs};
-use crate::{cmp, env, fmt, ptr};
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-#[derive(Clone, Debug, Eq)]
-#[doc(hidden)]
-pub struct EnvKey {
-    os_string: OsString,
-    // This stores a UTF-16 encoded string to workaround the mismatch between
-    // Rust's OsString (WTF-8) and the Windows API string type (UTF-16).
-    // Normally converting on every API call is acceptable but here
-    // `c::CompareStringOrdinal` will be called for every use of `==`.
-    utf16: Vec<u16>,
-}
-
-impl EnvKey {
-    fn new<T: Into<OsString>>(key: T) -> Self {
-        EnvKey::from(key.into())
-    }
-}
-
-// Comparing Windows environment variable keys[1] are behaviorally the
-// composition of two operations[2]:
-//
-// 1. Case-fold both strings. This is done using a language-independent
-// uppercase mapping that's unique to Windows (albeit based on data from an
-// older Unicode spec). It only operates on individual UTF-16 code units so
-// surrogates are left unchanged. This uppercase mapping can potentially change
-// between Windows versions.
-//
-// 2. Perform an ordinal comparison of the strings. A comparison using ordinal
-// is just a comparison based on the numerical value of each UTF-16 code unit[3].
-//
-// Because the case-folding mapping is unique to Windows and not guaranteed to
-// be stable, we ask the OS to compare the strings for us. This is done by
-// calling `CompareStringOrdinal`[4] with `bIgnoreCase` set to `TRUE`.
-//
-// [1] https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices-strings#choosing-a-stringcomparison-member-for-your-method-call
-// [2] https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices-strings#stringtoupper-and-stringtolower
-// [3] https://docs.microsoft.com/en-us/dotnet/api/system.stringcomparison?view=net-5.0#System_StringComparison_Ordinal
-// [4] https://docs.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-comparestringordinal
-impl Ord for EnvKey {
-    fn cmp(&self, other: &Self) -> cmp::Ordering {
-        unsafe {
-            let result = c::CompareStringOrdinal(
-                self.utf16.as_ptr(),
-                self.utf16.len() as _,
-                other.utf16.as_ptr(),
-                other.utf16.len() as _,
-                c::TRUE,
-            );
-            match result {
-                c::CSTR_LESS_THAN => cmp::Ordering::Less,
-                c::CSTR_EQUAL => cmp::Ordering::Equal,
-                c::CSTR_GREATER_THAN => cmp::Ordering::Greater,
-                // `CompareStringOrdinal` should never fail so long as the parameters are correct.
-                _ => panic!("comparing environment keys failed: {}", Error::last_os_error()),
-            }
-        }
-    }
-}
-impl PartialOrd for EnvKey {
-    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
-        Some(self.cmp(other))
-    }
-}
-impl PartialEq for EnvKey {
-    fn eq(&self, other: &Self) -> bool {
-        if self.utf16.len() != other.utf16.len() {
-            false
-        } else {
-            self.cmp(other) == cmp::Ordering::Equal
-        }
-    }
-}
-impl PartialOrd<str> for EnvKey {
-    fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
-        Some(self.cmp(&EnvKey::new(other)))
-    }
-}
-impl PartialEq<str> for EnvKey {
-    fn eq(&self, other: &str) -> bool {
-        if self.os_string.len() != other.len() {
-            false
-        } else {
-            self.cmp(&EnvKey::new(other)) == cmp::Ordering::Equal
-        }
-    }
-}
-
-// Environment variable keys should preserve their original case even though
-// they are compared using a caseless string mapping.
-impl From<OsString> for EnvKey {
-    fn from(k: OsString) -> Self {
-        EnvKey { utf16: k.encode_wide().collect(), os_string: k }
-    }
-}
-
-impl From<EnvKey> for OsString {
-    fn from(k: EnvKey) -> Self {
-        k.os_string
-    }
-}
-
-impl From<&OsStr> for EnvKey {
-    fn from(k: &OsStr) -> Self {
-        Self::from(k.to_os_string())
-    }
-}
-
-impl AsRef<OsStr> for EnvKey {
-    fn as_ref(&self) -> &OsStr {
-        &self.os_string
-    }
-}
-
-pub(crate) fn ensure_no_nuls<T: AsRef<OsStr>>(s: T) -> io::Result<T> {
-    if s.as_ref().encode_wide().any(|b| b == 0) {
-        Err(io::const_error!(ErrorKind::InvalidInput, "nul byte found in provided data"))
-    } else {
-        Ok(s)
-    }
-}
-
-pub struct Command {
-    program: OsString,
-    args: Vec<Arg>,
-    env: CommandEnv,
-    cwd: Option<OsString>,
-    flags: u32,
-    show_window: Option<u16>,
-    detach: bool, // not currently exposed in std::process
-    stdin: Option<Stdio>,
-    stdout: Option<Stdio>,
-    stderr: Option<Stdio>,
-    force_quotes_enabled: bool,
-}
-
-pub enum Stdio {
-    Inherit,
-    InheritSpecific { from_stdio_id: u32 },
-    Null,
-    MakePipe,
-    Pipe(AnonPipe),
-    Handle(Handle),
-}
-
-pub struct StdioPipes {
-    pub stdin: Option<AnonPipe>,
-    pub stdout: Option<AnonPipe>,
-    pub stderr: Option<AnonPipe>,
-}
-
-impl Command {
-    pub fn new(program: &OsStr) -> Command {
-        Command {
-            program: program.to_os_string(),
-            args: Vec::new(),
-            env: Default::default(),
-            cwd: None,
-            flags: 0,
-            show_window: None,
-            detach: false,
-            stdin: None,
-            stdout: None,
-            stderr: None,
-            force_quotes_enabled: false,
-        }
-    }
-
-    pub fn arg(&mut self, arg: &OsStr) {
-        self.args.push(Arg::Regular(arg.to_os_string()))
-    }
-    pub fn env_mut(&mut self) -> &mut CommandEnv {
-        &mut self.env
-    }
-    pub fn cwd(&mut self, dir: &OsStr) {
-        self.cwd = Some(dir.to_os_string())
-    }
-    pub fn stdin(&mut self, stdin: Stdio) {
-        self.stdin = Some(stdin);
-    }
-    pub fn stdout(&mut self, stdout: Stdio) {
-        self.stdout = Some(stdout);
-    }
-    pub fn stderr(&mut self, stderr: Stdio) {
-        self.stderr = Some(stderr);
-    }
-    pub fn creation_flags(&mut self, flags: u32) {
-        self.flags = flags;
-    }
-    pub fn show_window(&mut self, cmd_show: Option<u16>) {
-        self.show_window = cmd_show;
-    }
-
-    pub fn force_quotes(&mut self, enabled: bool) {
-        self.force_quotes_enabled = enabled;
-    }
-
-    pub fn raw_arg(&mut self, command_str_to_append: &OsStr) {
-        self.args.push(Arg::Raw(command_str_to_append.to_os_string()))
-    }
-
-    pub fn get_program(&self) -> &OsStr {
-        &self.program
-    }
-
-    pub fn get_args(&self) -> CommandArgs<'_> {
-        let iter = self.args.iter();
-        CommandArgs { iter }
-    }
-
-    pub fn get_envs(&self) -> CommandEnvs<'_> {
-        self.env.iter()
-    }
-
-    pub fn get_current_dir(&self) -> Option<&Path> {
-        self.cwd.as_ref().map(Path::new)
-    }
-
-    pub fn spawn(
-        &mut self,
-        default: Stdio,
-        needs_stdin: bool,
-    ) -> io::Result<(Process, StdioPipes)> {
-        self.spawn_with_attributes(default, needs_stdin, None)
-    }
-
-    pub fn spawn_with_attributes(
-        &mut self,
-        default: Stdio,
-        needs_stdin: bool,
-        proc_thread_attribute_list: Option<&ProcThreadAttributeList<'_>>,
-    ) -> io::Result<(Process, StdioPipes)> {
-        let env_saw_path = self.env.have_changed_path();
-        let maybe_env = self.env.capture_if_changed();
-
-        let child_paths = if env_saw_path && let Some(env) = maybe_env.as_ref() {
-            env.get(&EnvKey::new("PATH")).map(|s| s.as_os_str())
-        } else {
-            None
-        };
-        let program = resolve_exe(&self.program, || env::var_os("PATH"), child_paths)?;
-        let has_bat_extension = |program: &[u16]| {
-            matches!(
-                // Case insensitive "ends_with" of UTF-16 encoded ".bat" or ".cmd"
-                program.len().checked_sub(4).and_then(|i| program.get(i..)),
-                Some([46, 98 | 66, 97 | 65, 116 | 84] | [46, 99 | 67, 109 | 77, 100 | 68])
-            )
-        };
-        let is_batch_file = if path::is_verbatim(&program) {
-            has_bat_extension(&program[..program.len() - 1])
-        } else {
-            super::fill_utf16_buf(
-                |buffer, size| unsafe {
-                    // resolve the path so we can test the final file name.
-                    c::GetFullPathNameW(program.as_ptr(), size, buffer, ptr::null_mut())
-                },
-                |program| has_bat_extension(program),
-            )?
-        };
-        let (program, mut cmd_str) = if is_batch_file {
-            (
-                command_prompt()?,
-                args::make_bat_command_line(&program, &self.args, self.force_quotes_enabled)?,
-            )
-        } else {
-            let cmd_str = make_command_line(&self.program, &self.args, self.force_quotes_enabled)?;
-            (program, cmd_str)
-        };
-        cmd_str.push(0); // add null terminator
-
-        // stolen from the libuv code.
-        let mut flags = self.flags | c::CREATE_UNICODE_ENVIRONMENT;
-        if self.detach {
-            flags |= c::DETACHED_PROCESS | c::CREATE_NEW_PROCESS_GROUP;
-        }
-
-        let (envp, _data) = make_envp(maybe_env)?;
-        let (dirp, _data) = make_dirp(self.cwd.as_ref())?;
-        let mut pi = zeroed_process_information();
-
-        // Prepare all stdio handles to be inherited by the child. This
-        // currently involves duplicating any existing ones with the ability to
-        // be inherited by child processes. Note, however, that once an
-        // inheritable handle is created, *any* spawned child will inherit that
-        // handle. We only want our own child to inherit this handle, so we wrap
-        // the remaining portion of this spawn in a mutex.
-        //
-        // For more information, msdn also has an article about this race:
-        // https://support.microsoft.com/kb/315939
-        static CREATE_PROCESS_LOCK: Mutex<()> = Mutex::new(());
-
-        let _guard = CREATE_PROCESS_LOCK.lock();
-
-        let mut pipes = StdioPipes { stdin: None, stdout: None, stderr: None };
-        let null = Stdio::Null;
-        let default_stdin = if needs_stdin { &default } else { &null };
-        let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
-        let stdout = self.stdout.as_ref().unwrap_or(&default);
-        let stderr = self.stderr.as_ref().unwrap_or(&default);
-        let stdin = stdin.to_handle(c::STD_INPUT_HANDLE, &mut pipes.stdin)?;
-        let stdout = stdout.to_handle(c::STD_OUTPUT_HANDLE, &mut pipes.stdout)?;
-        let stderr = stderr.to_handle(c::STD_ERROR_HANDLE, &mut pipes.stderr)?;
-
-        let mut si = zeroed_startupinfo();
-
-        // If at least one of stdin, stdout or stderr are set (i.e. are non null)
-        // then set the `hStd` fields in `STARTUPINFO`.
-        // Otherwise skip this and allow the OS to apply its default behavior.
-        // This provides more consistent behavior between Win7 and Win8+.
-        let is_set = |stdio: &Handle| !stdio.as_raw_handle().is_null();
-        if is_set(&stderr) || is_set(&stdout) || is_set(&stdin) {
-            si.dwFlags |= c::STARTF_USESTDHANDLES;
-            si.hStdInput = stdin.as_raw_handle();
-            si.hStdOutput = stdout.as_raw_handle();
-            si.hStdError = stderr.as_raw_handle();
-        }
-
-        if let Some(cmd_show) = self.show_window {
-            si.dwFlags |= c::STARTF_USESHOWWINDOW;
-            si.wShowWindow = cmd_show;
-        }
-
-        let si_ptr: *mut c::STARTUPINFOW;
-
-        let mut si_ex;
-
-        if let Some(proc_thread_attribute_list) = proc_thread_attribute_list {
-            si.cb = size_of::<c::STARTUPINFOEXW>() as u32;
-            flags |= c::EXTENDED_STARTUPINFO_PRESENT;
-
-            si_ex = c::STARTUPINFOEXW {
-                StartupInfo: si,
-                // SAFETY: Casting this `*const` pointer to a `*mut` pointer is "safe"
-                // here because windows does not internally mutate the attribute list.
-                // Ideally this should be reflected in the interface of the `windows-sys` crate.
-                lpAttributeList: proc_thread_attribute_list.as_ptr().cast::<c_void>().cast_mut(),
-            };
-            si_ptr = (&raw mut si_ex) as _;
-        } else {
-            si.cb = size_of::<c::STARTUPINFOW>() as u32;
-            si_ptr = (&raw mut si) as _;
-        }
-
-        unsafe {
-            cvt(c::CreateProcessW(
-                program.as_ptr(),
-                cmd_str.as_mut_ptr(),
-                ptr::null_mut(),
-                ptr::null_mut(),
-                c::TRUE,
-                flags,
-                envp,
-                dirp,
-                si_ptr,
-                &mut pi,
-            ))
-        }?;
-
-        unsafe {
-            Ok((
-                Process {
-                    handle: Handle::from_raw_handle(pi.hProcess),
-                    main_thread_handle: Handle::from_raw_handle(pi.hThread),
-                },
-                pipes,
-            ))
-        }
-    }
-
-    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
-        let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
-        crate::sys_common::process::wait_with_output(proc, pipes)
-    }
-}
-
-impl fmt::Debug for Command {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.program.fmt(f)?;
-        for arg in &self.args {
-            f.write_str(" ")?;
-            match arg {
-                Arg::Regular(s) => s.fmt(f),
-                Arg::Raw(s) => f.write_str(&s.to_string_lossy()),
-            }?;
-        }
-        Ok(())
-    }
-}
-
-// Resolve `exe_path` to the executable name.
-//
-// * If the path is simply a file name then use the paths given by `search_paths` to find the executable.
-// * Otherwise use the `exe_path` as given.
-//
-// This function may also append `.exe` to the name. The rationale for doing so is as follows:
-//
-// It is a very strong convention that Windows executables have the `exe` extension.
-// In Rust, it is common to omit this extension.
-// Therefore this functions first assumes `.exe` was intended.
-// It falls back to the plain file name if a full path is given and the extension is omitted
-// or if only a file name is given and it already contains an extension.
-fn resolve_exe<'a>(
-    exe_path: &'a OsStr,
-    parent_paths: impl FnOnce() -> Option<OsString>,
-    child_paths: Option<&OsStr>,
-) -> io::Result<Vec<u16>> {
-    // Early return if there is no filename.
-    if exe_path.is_empty() || path::has_trailing_slash(exe_path) {
-        return Err(io::const_error!(io::ErrorKind::InvalidInput, "program path has no file name"));
-    }
-    // Test if the file name has the `exe` extension.
-    // This does a case-insensitive `ends_with`.
-    let has_exe_suffix = if exe_path.len() >= EXE_SUFFIX.len() {
-        exe_path.as_encoded_bytes()[exe_path.len() - EXE_SUFFIX.len()..]
-            .eq_ignore_ascii_case(EXE_SUFFIX.as_bytes())
-    } else {
-        false
-    };
-
-    // If `exe_path` is an absolute path or a sub-path then don't search `PATH` for it.
-    if !path::is_file_name(exe_path) {
-        if has_exe_suffix {
-            // The application name is a path to a `.exe` file.
-            // Let `CreateProcessW` figure out if it exists or not.
-            return args::to_user_path(Path::new(exe_path));
-        }
-        let mut path = PathBuf::from(exe_path);
-
-        // Append `.exe` if not already there.
-        path = path::append_suffix(path, EXE_SUFFIX.as_ref());
-        if let Some(path) = program_exists(&path) {
-            return Ok(path);
-        } else {
-            // It's ok to use `set_extension` here because the intent is to
-            // remove the extension that was just added.
-            path.set_extension("");
-            return args::to_user_path(&path);
-        }
-    } else {
-        ensure_no_nuls(exe_path)?;
-        // From the `CreateProcessW` docs:
-        // > If the file name does not contain an extension, .exe is appended.
-        // Note that this rule only applies when searching paths.
-        let has_extension = exe_path.as_encoded_bytes().contains(&b'.');
-
-        // Search the directories given by `search_paths`.
-        let result = search_paths(parent_paths, child_paths, |mut path| {
-            path.push(exe_path);
-            if !has_extension {
-                path.set_extension(EXE_EXTENSION);
-            }
-            program_exists(&path)
-        });
-        if let Some(path) = result {
-            return Ok(path);
-        }
-    }
-    // If we get here then the executable cannot be found.
-    Err(io::const_error!(io::ErrorKind::NotFound, "program not found"))
-}
-
-// Calls `f` for every path that should be used to find an executable.
-// Returns once `f` returns the path to an executable or all paths have been searched.
-fn search_paths<Paths, Exists>(
-    parent_paths: Paths,
-    child_paths: Option<&OsStr>,
-    mut exists: Exists,
-) -> Option<Vec<u16>>
-where
-    Paths: FnOnce() -> Option<OsString>,
-    Exists: FnMut(PathBuf) -> Option<Vec<u16>>,
-{
-    // 1. Child paths
-    // This is for consistency with Rust's historic behavior.
-    if let Some(paths) = child_paths {
-        for path in env::split_paths(paths).filter(|p| !p.as_os_str().is_empty()) {
-            if let Some(path) = exists(path) {
-                return Some(path);
-            }
-        }
-    }
-
-    // 2. Application path
-    if let Ok(mut app_path) = env::current_exe() {
-        app_path.pop();
-        if let Some(path) = exists(app_path) {
-            return Some(path);
-        }
-    }
-
-    // 3 & 4. System paths
-    // SAFETY: This uses `fill_utf16_buf` to safely call the OS functions.
-    unsafe {
-        if let Ok(Some(path)) = super::fill_utf16_buf(
-            |buf, size| c::GetSystemDirectoryW(buf, size),
-            |buf| exists(PathBuf::from(OsString::from_wide(buf))),
-        ) {
-            return Some(path);
-        }
-        #[cfg(not(target_vendor = "uwp"))]
-        {
-            if let Ok(Some(path)) = super::fill_utf16_buf(
-                |buf, size| c::GetWindowsDirectoryW(buf, size),
-                |buf| exists(PathBuf::from(OsString::from_wide(buf))),
-            ) {
-                return Some(path);
-            }
-        }
-    }
-
-    // 5. Parent paths
-    if let Some(parent_paths) = parent_paths() {
-        for path in env::split_paths(&parent_paths).filter(|p| !p.as_os_str().is_empty()) {
-            if let Some(path) = exists(path) {
-                return Some(path);
-            }
-        }
-    }
-    None
-}
-
-/// Checks if a file exists without following symlinks.
-fn program_exists(path: &Path) -> Option<Vec<u16>> {
-    unsafe {
-        let path = args::to_user_path(path).ok()?;
-        // Getting attributes using `GetFileAttributesW` does not follow symlinks
-        // and it will almost always be successful if the link exists.
-        // There are some exceptions for special system files (e.g. the pagefile)
-        // but these are not executable.
-        if c::GetFileAttributesW(path.as_ptr()) == c::INVALID_FILE_ATTRIBUTES {
-            None
-        } else {
-            Some(path)
-        }
-    }
-}
-
-impl Stdio {
-    fn to_handle(&self, stdio_id: u32, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> {
-        let use_stdio_id = |stdio_id| match stdio::get_handle(stdio_id) {
-            Ok(io) => unsafe {
-                let io = Handle::from_raw_handle(io);
-                let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS);
-                let _ = io.into_raw_handle(); // Don't close the handle
-                ret
-            },
-            // If no stdio handle is available, then propagate the null value.
-            Err(..) => unsafe { Ok(Handle::from_raw_handle(ptr::null_mut())) },
-        };
-        match *self {
-            Stdio::Inherit => use_stdio_id(stdio_id),
-            Stdio::InheritSpecific { from_stdio_id } => use_stdio_id(from_stdio_id),
-
-            Stdio::MakePipe => {
-                let ours_readable = stdio_id != c::STD_INPUT_HANDLE;
-                let pipes = pipe::anon_pipe(ours_readable, true)?;
-                *pipe = Some(pipes.ours);
-                Ok(pipes.theirs.into_handle())
-            }
-
-            Stdio::Pipe(ref source) => {
-                let ours_readable = stdio_id != c::STD_INPUT_HANDLE;
-                pipe::spawn_pipe_relay(source, ours_readable, true).map(AnonPipe::into_handle)
-            }
-
-            Stdio::Handle(ref handle) => handle.duplicate(0, true, c::DUPLICATE_SAME_ACCESS),
-
-            // Open up a reference to NUL with appropriate read/write
-            // permissions as well as the ability to be inherited to child
-            // processes (as this is about to be inherited).
-            Stdio::Null => {
-                let size = size_of::<c::SECURITY_ATTRIBUTES>();
-                let mut sa = c::SECURITY_ATTRIBUTES {
-                    nLength: size as u32,
-                    lpSecurityDescriptor: ptr::null_mut(),
-                    bInheritHandle: 1,
-                };
-                let mut opts = OpenOptions::new();
-                opts.read(stdio_id == c::STD_INPUT_HANDLE);
-                opts.write(stdio_id != c::STD_INPUT_HANDLE);
-                opts.security_attributes(&mut sa);
-                File::open(Path::new(r"\\.\NUL"), &opts).map(|file| file.into_inner())
-            }
-        }
-    }
-}
-
-impl From<AnonPipe> for Stdio {
-    fn from(pipe: AnonPipe) -> Stdio {
-        Stdio::Pipe(pipe)
-    }
-}
-
-impl From<Handle> for Stdio {
-    fn from(pipe: Handle) -> Stdio {
-        Stdio::Handle(pipe)
-    }
-}
-
-impl From<File> for Stdio {
-    fn from(file: File) -> Stdio {
-        Stdio::Handle(file.into_inner())
-    }
-}
-
-impl From<io::Stdout> for Stdio {
-    fn from(_: io::Stdout) -> Stdio {
-        Stdio::InheritSpecific { from_stdio_id: c::STD_OUTPUT_HANDLE }
-    }
-}
-
-impl From<io::Stderr> for Stdio {
-    fn from(_: io::Stderr) -> Stdio {
-        Stdio::InheritSpecific { from_stdio_id: c::STD_ERROR_HANDLE }
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Processes
-////////////////////////////////////////////////////////////////////////////////
-
-/// A value representing a child process.
-///
-/// The lifetime of this value is linked to the lifetime of the actual
-/// process - the Process destructor calls self.finish() which waits
-/// for the process to terminate.
-pub struct Process {
-    handle: Handle,
-    main_thread_handle: Handle,
-}
-
-impl Process {
-    pub fn kill(&mut self) -> io::Result<()> {
-        let result = unsafe { c::TerminateProcess(self.handle.as_raw_handle(), 1) };
-        if result == c::FALSE {
-            let error = api::get_last_error();
-            // TerminateProcess returns ERROR_ACCESS_DENIED if the process has already been
-            // terminated (by us, or for any other reason). So check if the process was actually
-            // terminated, and if so, do not return an error.
-            if error != WinError::ACCESS_DENIED || self.try_wait().is_err() {
-                return Err(crate::io::Error::from_raw_os_error(error.code as i32));
-            }
-        }
-        Ok(())
-    }
-
-    pub fn id(&self) -> u32 {
-        unsafe { c::GetProcessId(self.handle.as_raw_handle()) }
-    }
-
-    pub fn main_thread_handle(&self) -> BorrowedHandle<'_> {
-        self.main_thread_handle.as_handle()
-    }
-
-    pub fn wait(&mut self) -> io::Result<ExitStatus> {
-        unsafe {
-            let res = c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE);
-            if res != c::WAIT_OBJECT_0 {
-                return Err(Error::last_os_error());
-            }
-            let mut status = 0;
-            cvt(c::GetExitCodeProcess(self.handle.as_raw_handle(), &mut status))?;
-            Ok(ExitStatus(status))
-        }
-    }
-
-    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
-        unsafe {
-            match c::WaitForSingleObject(self.handle.as_raw_handle(), 0) {
-                c::WAIT_OBJECT_0 => {}
-                c::WAIT_TIMEOUT => {
-                    return Ok(None);
-                }
-                _ => return Err(io::Error::last_os_error()),
-            }
-            let mut status = 0;
-            cvt(c::GetExitCodeProcess(self.handle.as_raw_handle(), &mut status))?;
-            Ok(Some(ExitStatus(status)))
-        }
-    }
-
-    pub fn handle(&self) -> &Handle {
-        &self.handle
-    }
-
-    pub fn into_handle(self) -> Handle {
-        self.handle
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
-pub struct ExitStatus(u32);
-
-impl ExitStatus {
-    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
-        match NonZero::<u32>::try_from(self.0) {
-            /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)),
-            /* was zero, couldn't convert */ Err(_) => Ok(()),
-        }
-    }
-    pub fn code(&self) -> Option<i32> {
-        Some(self.0 as i32)
-    }
-}
-
-/// Converts a raw `u32` to a type-safe `ExitStatus` by wrapping it without copying.
-impl From<u32> for ExitStatus {
-    fn from(u: u32) -> ExitStatus {
-        ExitStatus(u)
-    }
-}
-
-impl fmt::Display for ExitStatus {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // Windows exit codes with the high bit set typically mean some form of
-        // unhandled exception or warning. In this scenario printing the exit
-        // code in decimal doesn't always make sense because it's a very large
-        // and somewhat gibberish number. The hex code is a bit more
-        // recognizable and easier to search for, so print that.
-        if self.0 & 0x80000000 != 0 {
-            write!(f, "exit code: {:#x}", self.0)
-        } else {
-            write!(f, "exit code: {}", self.0)
-        }
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitStatusError(NonZero<u32>);
-
-impl Into<ExitStatus> for ExitStatusError {
-    fn into(self) -> ExitStatus {
-        ExitStatus(self.0.into())
-    }
-}
-
-impl ExitStatusError {
-    pub fn code(self) -> Option<NonZero<i32>> {
-        Some((u32::from(self.0) as i32).try_into().unwrap())
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitCode(u32);
-
-impl ExitCode {
-    pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
-    pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);
-
-    #[inline]
-    pub fn as_i32(&self) -> i32 {
-        self.0 as i32
-    }
-}
-
-impl From<u8> for ExitCode {
-    fn from(code: u8) -> Self {
-        ExitCode(u32::from(code))
-    }
-}
-
-impl From<u32> for ExitCode {
-    fn from(code: u32) -> Self {
-        ExitCode(u32::from(code))
-    }
-}
-
-fn zeroed_startupinfo() -> c::STARTUPINFOW {
-    c::STARTUPINFOW {
-        cb: 0,
-        lpReserved: ptr::null_mut(),
-        lpDesktop: ptr::null_mut(),
-        lpTitle: ptr::null_mut(),
-        dwX: 0,
-        dwY: 0,
-        dwXSize: 0,
-        dwYSize: 0,
-        dwXCountChars: 0,
-        dwYCountChars: 0,
-        dwFillAttribute: 0,
-        dwFlags: 0,
-        wShowWindow: 0,
-        cbReserved2: 0,
-        lpReserved2: ptr::null_mut(),
-        hStdInput: ptr::null_mut(),
-        hStdOutput: ptr::null_mut(),
-        hStdError: ptr::null_mut(),
-    }
-}
-
-fn zeroed_process_information() -> c::PROCESS_INFORMATION {
-    c::PROCESS_INFORMATION {
-        hProcess: ptr::null_mut(),
-        hThread: ptr::null_mut(),
-        dwProcessId: 0,
-        dwThreadId: 0,
-    }
-}
-
-// Produces a wide string *without terminating null*; returns an error if
-// `prog` or any of the `args` contain a nul.
-fn make_command_line(argv0: &OsStr, args: &[Arg], force_quotes: bool) -> io::Result<Vec<u16>> {
-    // Encode the command and arguments in a command line string such
-    // that the spawned process may recover them using CommandLineToArgvW.
-    let mut cmd: Vec<u16> = Vec::new();
-
-    // Always quote the program name so CreateProcess to avoid ambiguity when
-    // the child process parses its arguments.
-    // Note that quotes aren't escaped here because they can't be used in arg0.
-    // But that's ok because file paths can't contain quotes.
-    cmd.push(b'"' as u16);
-    cmd.extend(argv0.encode_wide());
-    cmd.push(b'"' as u16);
-
-    for arg in args {
-        cmd.push(' ' as u16);
-        args::append_arg(&mut cmd, arg, force_quotes)?;
-    }
-    Ok(cmd)
-}
-
-// Get `cmd.exe` for use with bat scripts, encoded as a UTF-16 string.
-fn command_prompt() -> io::Result<Vec<u16>> {
-    let mut system: Vec<u16> = super::fill_utf16_buf(
-        |buf, size| unsafe { c::GetSystemDirectoryW(buf, size) },
-        |buf| buf.into(),
-    )?;
-    system.extend("\\cmd.exe".encode_utf16().chain([0]));
-    Ok(system)
-}
-
-fn make_envp(maybe_env: Option<BTreeMap<EnvKey, OsString>>) -> io::Result<(*mut c_void, Vec<u16>)> {
-    // On Windows we pass an "environment block" which is not a char**, but
-    // rather a concatenation of null-terminated k=v\0 sequences, with a final
-    // \0 to terminate.
-    if let Some(env) = maybe_env {
-        let mut blk = Vec::new();
-
-        // If there are no environment variables to set then signal this by
-        // pushing a null.
-        if env.is_empty() {
-            blk.push(0);
-        }
-
-        for (k, v) in env {
-            ensure_no_nuls(k.os_string)?;
-            blk.extend(k.utf16);
-            blk.push('=' as u16);
-            blk.extend(ensure_no_nuls(v)?.encode_wide());
-            blk.push(0);
-        }
-        blk.push(0);
-        Ok((blk.as_mut_ptr() as *mut c_void, blk))
-    } else {
-        Ok((ptr::null_mut(), Vec::new()))
-    }
-}
-
-fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
-    match d {
-        Some(dir) => {
-            let mut dir_str: Vec<u16> = ensure_no_nuls(dir)?.encode_wide().collect();
-            dir_str.push(0);
-            Ok((dir_str.as_ptr(), dir_str))
-        }
-        None => Ok((ptr::null(), Vec::new())),
-    }
-}
-
-pub struct CommandArgs<'a> {
-    iter: crate::slice::Iter<'a, Arg>,
-}
-
-impl<'a> Iterator for CommandArgs<'a> {
-    type Item = &'a OsStr;
-    fn next(&mut self) -> Option<&'a OsStr> {
-        self.iter.next().map(|arg| match arg {
-            Arg::Regular(s) | Arg::Raw(s) => s.as_ref(),
-        })
-    }
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-}
-
-impl<'a> ExactSizeIterator for CommandArgs<'a> {
-    fn len(&self) -> usize {
-        self.iter.len()
-    }
-    fn is_empty(&self) -> bool {
-        self.iter.is_empty()
-    }
-}
-
-impl<'a> fmt::Debug for CommandArgs<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_list().entries(self.iter.clone()).finish()
-    }
-}
diff --git a/library/std/src/sys/pal/windows/process/tests.rs b/library/std/src/sys/pal/windows/process/tests.rs
deleted file mode 100644
index 1377e12162f..00000000000
--- a/library/std/src/sys/pal/windows/process/tests.rs
+++ /dev/null
@@ -1,223 +0,0 @@
-use super::{Arg, make_command_line};
-use crate::env;
-use crate::ffi::{OsStr, OsString};
-use crate::process::Command;
-
-#[test]
-fn test_raw_args() {
-    let command_line = &make_command_line(
-        OsStr::new("quoted exe"),
-        &[
-            Arg::Regular(OsString::from("quote me")),
-            Arg::Raw(OsString::from("quote me *not*")),
-            Arg::Raw(OsString::from("\t\\")),
-            Arg::Raw(OsString::from("internal \\\"backslash-\"quote")),
-            Arg::Regular(OsString::from("optional-quotes")),
-        ],
-        false,
-    )
-    .unwrap();
-    assert_eq!(
-        String::from_utf16(command_line).unwrap(),
-        "\"quoted exe\" \"quote me\" quote me *not* \t\\ internal \\\"backslash-\"quote optional-quotes"
-    );
-}
-
-#[test]
-fn test_thread_handle() {
-    use crate::os::windows::io::BorrowedHandle;
-    use crate::os::windows::process::{ChildExt, CommandExt};
-    const CREATE_SUSPENDED: u32 = 0x00000004;
-
-    let p = Command::new("cmd").args(&["/C", "exit 0"]).creation_flags(CREATE_SUSPENDED).spawn();
-    assert!(p.is_ok());
-    let mut p = p.unwrap();
-
-    unsafe extern "system" {
-        fn ResumeThread(_: BorrowedHandle<'_>) -> u32;
-    }
-    unsafe {
-        ResumeThread(p.main_thread_handle());
-    }
-
-    crate::thread::sleep(crate::time::Duration::from_millis(100));
-
-    let res = p.try_wait();
-    assert!(res.is_ok());
-    assert!(res.unwrap().is_some());
-    assert!(p.try_wait().unwrap().unwrap().success());
-}
-
-#[test]
-fn test_make_command_line() {
-    fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
-        let command_line = &make_command_line(
-            OsStr::new(prog),
-            &args.iter().map(|a| Arg::Regular(OsString::from(a))).collect::<Vec<_>>(),
-            force_quotes,
-        )
-        .unwrap();
-        String::from_utf16(command_line).unwrap()
-    }
-
-    assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"], false), "\"prog\" aaa bbb ccc");
-
-    assert_eq!(test_wrapper("prog", &[r"C:\"], false), r#""prog" C:\"#);
-    assert_eq!(test_wrapper("prog", &[r"2slashes\\"], false), r#""prog" 2slashes\\"#);
-    assert_eq!(test_wrapper("prog", &[r" C:\"], false), r#""prog" " C:\\""#);
-    assert_eq!(test_wrapper("prog", &[r" 2slashes\\"], false), r#""prog" " 2slashes\\\\""#);
-
-    assert_eq!(
-        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"], false),
-        "\"C:\\Program Files\\blah\\blah.exe\" aaa"
-    );
-    assert_eq!(
-        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], false),
-        "\"C:\\Program Files\\blah\\blah.exe\" aaa v*"
-    );
-    assert_eq!(
-        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], true),
-        "\"C:\\Program Files\\blah\\blah.exe\" \"aaa\" \"v*\""
-    );
-    assert_eq!(
-        test_wrapper("C:\\Program Files\\test", &["aa\"bb"], false),
-        "\"C:\\Program Files\\test\" aa\\\"bb"
-    );
-    assert_eq!(test_wrapper("echo", &["a b c"], false), "\"echo\" \"a b c\"");
-    assert_eq!(
-        test_wrapper("echo", &["\" \\\" \\", "\\"], false),
-        "\"echo\" \"\\\" \\\\\\\" \\\\\" \\"
-    );
-    assert_eq!(
-        test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[], false),
-        "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\""
-    );
-}
-
-// On Windows, environment args are case preserving but comparisons are case-insensitive.
-// See: #85242
-#[test]
-fn windows_env_unicode_case() {
-    let test_cases = [
-        ("ä", "Ä"),
-        ("ß", "SS"),
-        ("Ä", "Ö"),
-        ("Ä", "Ö"),
-        ("I", "İ"),
-        ("I", "i"),
-        ("I", "ı"),
-        ("i", "I"),
-        ("i", "İ"),
-        ("i", "ı"),
-        ("İ", "I"),
-        ("İ", "i"),
-        ("İ", "ı"),
-        ("ı", "I"),
-        ("ı", "i"),
-        ("ı", "İ"),
-        ("ä", "Ä"),
-        ("ß", "SS"),
-        ("Ä", "Ö"),
-        ("Ä", "Ö"),
-        ("I", "İ"),
-        ("I", "i"),
-        ("I", "ı"),
-        ("i", "I"),
-        ("i", "İ"),
-        ("i", "ı"),
-        ("İ", "I"),
-        ("İ", "i"),
-        ("İ", "ı"),
-        ("ı", "I"),
-        ("ı", "i"),
-        ("ı", "İ"),
-    ];
-    // Test that `cmd.env` matches `env::set_var` when setting two strings that
-    // may (or may not) be case-folded when compared.
-    for (a, b) in test_cases.iter() {
-        let mut cmd = Command::new("cmd");
-        cmd.env(a, "1");
-        cmd.env(b, "2");
-        unsafe {
-            env::set_var(a, "1");
-            env::set_var(b, "2");
-        }
-
-        for (key, value) in cmd.get_envs() {
-            assert_eq!(
-                env::var(key).ok(),
-                value.map(|s| s.to_string_lossy().into_owned()),
-                "command environment mismatch: {a} {b}",
-            );
-        }
-    }
-}
-
-// UWP applications run in a restricted environment which means this test may not work.
-#[cfg(not(target_vendor = "uwp"))]
-#[test]
-fn windows_exe_resolver() {
-    use super::resolve_exe;
-    use crate::io;
-    use crate::sys::fs::symlink;
-    use crate::test_helpers::tmpdir;
-
-    let env_paths = || env::var_os("PATH");
-
-    // Test a full path, with and without the `exe` extension.
-    let mut current_exe = env::current_exe().unwrap();
-    assert!(resolve_exe(current_exe.as_ref(), env_paths, None).is_ok());
-    current_exe.set_extension("");
-    assert!(resolve_exe(current_exe.as_ref(), env_paths, None).is_ok());
-
-    // Test lone file names.
-    assert!(resolve_exe(OsStr::new("cmd"), env_paths, None).is_ok());
-    assert!(resolve_exe(OsStr::new("cmd.exe"), env_paths, None).is_ok());
-    assert!(resolve_exe(OsStr::new("cmd.EXE"), env_paths, None).is_ok());
-    assert!(resolve_exe(OsStr::new("fc"), env_paths, None).is_ok());
-
-    // Invalid file names should return InvalidInput.
-    assert_eq!(
-        resolve_exe(OsStr::new(""), env_paths, None).unwrap_err().kind(),
-        io::ErrorKind::InvalidInput
-    );
-    assert_eq!(
-        resolve_exe(OsStr::new("\0"), env_paths, None).unwrap_err().kind(),
-        io::ErrorKind::InvalidInput
-    );
-    // Trailing slash, therefore there's no file name component.
-    assert_eq!(
-        resolve_exe(OsStr::new(r"C:\Path\to\"), env_paths, None).unwrap_err().kind(),
-        io::ErrorKind::InvalidInput
-    );
-
-    /*
-    Some of the following tests may need to be changed if you are deliberately
-    changing the behavior of `resolve_exe`.
-    */
-
-    let empty_paths = || None;
-
-    // The resolver looks in system directories even when `PATH` is empty.
-    assert!(resolve_exe(OsStr::new("cmd.exe"), empty_paths, None).is_ok());
-
-    // The application's directory is also searched.
-    let current_exe = env::current_exe().unwrap();
-    assert!(resolve_exe(current_exe.file_name().unwrap().as_ref(), empty_paths, None).is_ok());
-
-    // Create a temporary path and add a broken symlink.
-    let temp = tmpdir();
-    let mut exe_path = temp.path().to_owned();
-    exe_path.push("exists.exe");
-
-    // A broken symlink should still be resolved.
-    // Skip this check if not in CI and creating symlinks isn't possible.
-    let is_ci = env::var("CI").is_ok();
-    let result = symlink("<DOES NOT EXIST>".as_ref(), &exe_path);
-    if is_ci || result.is_ok() {
-        result.unwrap();
-        assert!(
-            resolve_exe(OsStr::new("exists.exe"), empty_paths, Some(temp.path().as_ref())).is_ok()
-        );
-    }
-}
diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs
index 7d823012ad1..58926e2beb1 100644
--- a/library/std/src/sys/pal/xous/mod.rs
+++ b/library/std/src/sys/pal/xous/mod.rs
@@ -6,8 +6,6 @@ pub mod env;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-#[path = "../unsupported/process.rs"]
-pub mod process;
 pub mod thread;
 pub mod time;
 
diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs
index 499e2787201..4659dad16e8 100644
--- a/library/std/src/sys/pal/zkvm/mod.rs
+++ b/library/std/src/sys/pal/zkvm/mod.rs
@@ -17,8 +17,6 @@ pub mod env;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-#[path = "../unsupported/process.rs"]
-pub mod process;
 #[path = "../unsupported/thread.rs"]
 pub mod thread;
 #[path = "../unsupported/time.rs"]