[musl] use posix_spawn if a directory change was requested
Currently, not all libcs have the `posix_spawn_file_actions_addchdir_np` symbol available to them. So we attempt to do a weak symbol lookup for that function. But that only works if libc is a dynamic library -- with statically linked musl binaries the symbol lookup would never work, so we would never be able to use it even if the musl in use supported the symbol. Now that Rust has a minimum musl version of 1.2.3, all supported musl versions now include this symbol, so we can unconditionally expect it to be there. This symbol was added to libc in https://github.com/rust-lang/libc/pull/3949 -- use it here. I couldn't find any tests for whether the posix_spawn path is used, but I've verified with cargo-nextest that this change works. This is a substantial improvement to nextest's performance with musl. On my workstation with a Ryzen 7950x, against https://github.com/clap-rs/clap at 61f5ee514f8f60ed8f04c6494bdf36c19e7a8126: Before: ``` Summary [ 1.071s] 879 tests run: 879 passed, 0 skipped ``` After: ``` Summary [ 0.392s] 879 tests run: 879 passed, 0 skipped ``` Fixes #99740.
This commit is contained in:
parent
b8bb2968ce
commit
7f74c894b0
@ -96,9 +96,23 @@ fn stdout_works() {
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(any(windows, target_os = "vxworks"), ignore)]
|
#[cfg_attr(any(windows, target_os = "vxworks"), ignore)]
|
||||||
fn set_current_dir_works() {
|
fn set_current_dir_works() {
|
||||||
|
// On many Unix platforms this will use the posix_spawn path.
|
||||||
let mut cmd = shell_cmd();
|
let mut cmd = shell_cmd();
|
||||||
cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped());
|
cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped());
|
||||||
assert_eq!(run_output(cmd), "/\n");
|
assert_eq!(run_output(cmd), "/\n");
|
||||||
|
|
||||||
|
// Also test the fork/exec path by setting a pre_exec function.
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
use crate::os::unix::process::CommandExt;
|
||||||
|
|
||||||
|
let mut cmd = shell_cmd();
|
||||||
|
cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped());
|
||||||
|
unsafe {
|
||||||
|
cmd.pre_exec(|| Ok(()));
|
||||||
|
}
|
||||||
|
assert_eq!(run_output(cmd), "/\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -448,7 +448,6 @@ fn posix_spawn(
|
|||||||
use core::sync::atomic::{AtomicU8, Ordering};
|
use core::sync::atomic::{AtomicU8, Ordering};
|
||||||
|
|
||||||
use crate::mem::MaybeUninit;
|
use crate::mem::MaybeUninit;
|
||||||
use crate::sys::weak::weak;
|
|
||||||
use crate::sys::{self, cvt_nz, on_broken_pipe_flag_used};
|
use crate::sys::{self, cvt_nz, on_broken_pipe_flag_used};
|
||||||
|
|
||||||
if self.get_gid().is_some()
|
if self.get_gid().is_some()
|
||||||
@ -462,6 +461,8 @@ fn posix_spawn(
|
|||||||
|
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(target_os = "linux")] {
|
if #[cfg(target_os = "linux")] {
|
||||||
|
use crate::sys::weak::weak;
|
||||||
|
|
||||||
weak! {
|
weak! {
|
||||||
fn pidfd_spawnp(
|
fn pidfd_spawnp(
|
||||||
*mut libc::c_int,
|
*mut libc::c_int,
|
||||||
@ -575,16 +576,44 @@ unsafe fn retrying_libc_posix_spawnp(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Solaris, glibc 2.29+, and musl 1.24+ can set a new working directory,
|
type PosixSpawnAddChdirFn = unsafe extern "C" fn(
|
||||||
// and maybe others will gain this non-POSIX function too. We'll check
|
*mut libc::posix_spawn_file_actions_t,
|
||||||
// for this weak symbol as soon as it's needed, so we can return early
|
*const libc::c_char,
|
||||||
// otherwise to do a manual chdir before exec.
|
) -> 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;
|
||||||
|
|
||||||
weak! {
|
weak! {
|
||||||
fn posix_spawn_file_actions_addchdir_np(
|
fn posix_spawn_file_actions_addchdir_np(
|
||||||
*mut libc::posix_spawn_file_actions_t,
|
*mut libc::posix_spawn_file_actions_t,
|
||||||
*const libc::c_char
|
*const libc::c_char
|
||||||
) -> libc::c_int
|
) -> libc::c_int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
posix_spawn_file_actions_addchdir_np.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() {
|
let addchdir = match self.get_cwd() {
|
||||||
Some(cwd) => {
|
Some(cwd) => {
|
||||||
if cfg!(target_vendor = "apple") {
|
if cfg!(target_vendor = "apple") {
|
||||||
@ -597,7 +626,10 @@ fn posix_spawn_file_actions_addchdir_np(
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match posix_spawn_file_actions_addchdir_np.get() {
|
// 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)),
|
Some(f) => Some((f, cwd)),
|
||||||
None => return Ok(None),
|
None => return Ok(None),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user