Auto merge of #136929 - joboet:move_process_pal, r=Mark-Simulacrum

std: move process implementations to `sys`

As per #117276, this moves the implementations of `Process` and friends out of the `pal` module and into the `sys` module, removing quite a lot of error-prone `#[path]` imports in the process (hah, get it ;-)). I've also made the `zircon` module a dedicated submodule of `pal::unix`, hopefully we can move some other definitions there as well (they are currently quite a lot of duplications in `sys`). Also, the `ensure_no_nuls` function on Windows now lives in `sys::pal::windows` – it's not specific to processes and shared by the argument implementation.
This commit is contained in:
bors 2025-03-23 14:10:35 +00:00
commit aa8f0fd716
32 changed files with 90 additions and 104 deletions

View file

@ -17,6 +17,7 @@ pub mod io;
pub mod net;
pub mod os_str;
pub mod path;
pub mod process;
pub mod random;
pub mod stdio;
pub mod sync;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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"]

View file

@ -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;

View file

@ -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> {

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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"]

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

View file

@ -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"]

View file

@ -0,0 +1,19 @@
cfg_if::cfg_if! {
if #[cfg(target_family = "unix")] {
mod unix;
use unix as imp;
} else if #[cfg(target_os = "windows")] {
mod windows;
use windows as imp;
} else if #[cfg(target_os = "uefi")] {
mod uefi;
use uefi as imp;
} else {
mod unsupported;
use unsupported as imp;
}
}
pub use imp::{
Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio, StdioPipes,
};

View file

@ -1,12 +1,13 @@
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::pal::helpers;
use crate::sys::pal::os::error_string;
use crate::sys::pipe::AnonPipe;
use crate::sys::unsupported;
use crate::sys_common::process::{CommandEnv, CommandEnvs};
@ -225,7 +226,7 @@ impl ExitStatus {
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());
let err_str = error_string(self.0.as_usize());
write!(f, "{}", err_str)
}
}
@ -241,7 +242,7 @@ 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());
let err_str = error_string(self.0.as_usize());
write!(f, "{}", err_str)
}
}
@ -335,7 +336,6 @@ impl<'a> fmt::Debug for CommandArgs<'a> {
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;
@ -343,7 +343,7 @@ mod uefi_command_internal {
use crate::os::uefi::ffi::{OsStrExt, OsStringExt};
use crate::ptr::NonNull;
use crate::slice;
use crate::sys::pal::uefi::helpers::OwnedTable;
use crate::sys::pal::helpers::{self, OwnedTable};
use crate::sys_common::wstr::WStrUnits;
pub struct Image {

View file

@ -54,7 +54,7 @@ cfg_if::cfg_if! {
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);
crate::sys::pal::os::set_errno(libc::EINVAL);
return -1;
}
let raw = slice::from_raw_parts_mut(

View file

@ -1,8 +1,8 @@
use libc::{c_int, size_t};
use super::common::*;
use crate::num::NonZero;
use crate::sys::process::process_common::*;
use crate::sys::process::zircon::{Handle, zx_handle_t};
use crate::sys::pal::fuchsia::*;
use crate::{fmt, io, mem, ptr};
////////////////////////////////////////////////////////////////////////////////
@ -58,8 +58,6 @@ impl Command {
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.
@ -152,8 +150,6 @@ impl Process {
}
pub fn kill(&mut self) -> io::Result<()> {
use crate::sys::process::zircon::*;
unsafe {
zx_cvt(zx_task_kill(self.handle.raw()))?;
}
@ -162,8 +158,6 @@ impl Process {
}
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;
@ -194,8 +188,6 @@ impl Process {
}
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;
@ -251,7 +243,7 @@ impl ExitStatus {
None
}
// FIXME: The actually-Unix implementation in process_unix.rs uses WSTOPSIG, WCOREDUMP et al.
// FIXME: The actually-Unix implementation in 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.
//

View file

@ -0,0 +1,23 @@
#[cfg_attr(any(target_os = "espidf", target_os = "horizon", target_os = "nuttx"), allow(unused))]
mod common;
cfg_if::cfg_if! {
if #[cfg(target_os = "fuchsia")] {
mod fuchsia;
use fuchsia as imp;
} else if #[cfg(target_os = "vxworks")] {
mod vxworks;
use vxworks as imp;
} else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] {
mod unsupported;
use unsupported as imp;
} else {
mod unix;
use unix as imp;
}
}
pub use imp::{ExitStatus, ExitStatusError, Process};
pub use self::common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes};
pub use crate::ffi::OsString as EnvKey;

View file

@ -10,12 +10,12 @@ use libc::{c_int, pid_t};
)))]
use libc::{gid_t, uid_t};
use super::common::*;
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::sys::pal::linux::pidfd::PidFd;
use crate::{fmt, mem, sys};
cfg_if::cfg_if! {
@ -1051,7 +1051,7 @@ impl ExitStatus {
// 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.
// 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(()),
@ -1232,10 +1232,9 @@ impl ExitStatusError {
#[cfg(target_os = "linux")]
mod linux_child_ext {
use crate::io::ErrorKind;
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::pal::linux::pidfd as imp;
use crate::sys_common::FromInner;
use crate::{io, mem};
@ -1261,10 +1260,9 @@ mod linux_child_ext {
}
#[cfg(test)]
#[path = "process_unix/tests.rs"]
mod tests;
// See [`process_unsupported_wait_status::compare_with_linux`];
// See [`unsupported_wait_status::compare_with_linux`];
#[cfg(all(test, target_os = "linux"))]
#[path = "process_unsupported/wait_status.rs"]
mod process_unsupported_wait_status;
#[path = "unsupported/wait_status.rs"]
mod unsupported_wait_status;

View file

@ -1,9 +1,9 @@
use libc::{c_int, pid_t};
use super::common::*;
use crate::io;
use crate::num::NonZero;
use crate::sys::pal::unix::unsupported::*;
use crate::sys::process::process_common::*;
use crate::sys::pal::unsupported::*;
////////////////////////////////////////////////////////////////////////////////
// Command

View file

@ -7,7 +7,7 @@ use crate::ffi::c_int;
use crate::fmt;
use crate::num::NonZero;
/// Emulated wait status for use by `process_unsupported.rs`
/// Emulated wait status for use by `unsupported.rs`
///
/// Uses the "traditional unix" encoding. For use on platfors which are `#[cfg(unix)]`
/// but do not actually support subprocesses at all.
@ -48,7 +48,7 @@ impl ExitStatus {
// 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.
// 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(()),
@ -79,5 +79,6 @@ impl ExitStatus {
}
#[cfg(test)]
#[path = "wait_status/tests.rs"] // needed because of strange layout of process_unsupported
#[path = "wait_status/tests.rs"]
// needed because this module is also imported through #[path] for testing purposes
mod tests;

View file

@ -1,4 +1,4 @@
// Note that tests in this file are run on Linux as well as on platforms using process_unsupported
// Note that tests in this file are run on Linux as well as on platforms using unsupported
// Test that our emulation exactly matches Linux
//

View file

@ -1,11 +1,11 @@
#![forbid(unsafe_op_in_unsafe_fn)]
use libc::{self, RTP_ID, c_char, c_int};
use super::common::*;
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::sys::pal::thread;
use crate::{fmt, sys};
////////////////////////////////////////////////////////////////////////////////
@ -200,7 +200,7 @@ impl ExitStatus {
// 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.
// unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
match NonZero::try_from(self.0) {
Ok(failure) => Err(ExitStatusError(failure)),
Err(_) => Ok(()),

View file

@ -5,11 +5,10 @@ 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::io::{self, Error};
use crate::num::NonZero;
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle};
@ -20,6 +19,8 @@ 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::pal::api::{self, WinError};
use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf};
use crate::sys::pipe::{self, AnonPipe};
use crate::sys::{cvt, path, stdio};
use crate::sys_common::IntoInner;
@ -142,14 +143,6 @@ impl AsRef<OsStr> for EnvKey {
}
}
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>,
@ -279,7 +272,7 @@ impl Command {
let is_batch_file = if path::is_verbatim(&program) {
has_bat_extension(&program[..program.len() - 1])
} else {
super::fill_utf16_buf(
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())
@ -521,7 +514,7 @@ where
// 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(
if let Ok(Some(path)) = fill_utf16_buf(
|buf, size| c::GetSystemDirectoryW(buf, size),
|buf| exists(PathBuf::from(OsString::from_wide(buf))),
) {
@ -529,7 +522,7 @@ where
}
#[cfg(not(target_vendor = "uwp"))]
{
if let Ok(Some(path)) = super::fill_utf16_buf(
if let Ok(Some(path)) = fill_utf16_buf(
|buf, size| c::GetWindowsDirectoryW(buf, size),
|buf| exists(PathBuf::from(OsString::from_wide(buf))),
) {
@ -851,10 +844,8 @@ fn make_command_line(argv0: &OsStr, args: &[Arg], force_quotes: bool) -> io::Res
// 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(),
)?;
let mut system: Vec<u16> =
fill_utf16_buf(|buf, size| unsafe { c::GetSystemDirectoryW(buf, size) }, |buf| buf.into())?;
system.extend("\\cmd.exe".encode_utf16().chain([0]));
Ok(system)
}