util: Always use posix_spawn on macOS even with pre_exec hooks (#49090)
Here's some backstory: * on macOS, @cole-miller and I noticed that since roughly Oct 2025, due to some changes to latest macOS Tahoe, for any spawned child process we needed to reset Mach exception ports (https://github.com/zed-industries/zed/issues/36754 + https://github.com/RemiKalbe/zed/commit/6e8f2d2ebe5a93753625a3026aeb996de8cb436b) * the changes in that PR achieve that via `pre_exec` hook on `std::process::Command` which then abandons `posix_spawn` syscall for `fork` + `execve` dance on macOS (we tracked it down in Rust's std implementation) * as it turns out, `fork` + `execve` is pretty expensive on macOS (apparently way more so than on other OSes like Linux) and `fork` takes a process-wide lock on the allocator which is bad * however, since we wanna reset exception ports on the child, the only official way supported by Rust's std is to use `pre_exec` hook * posix_spawn on macOS exposes this tho via a macOS specific extension to that syscall `posix_spawnattr_setexceptionports_np` but there is no way to use that via any standard interfaces in `std::process::Command` * thus, it seemed like a good idea to instead create our own custom Command wrapper that on non-macOS hosts is a zero-cost wrapper of `smol::process::Command`, while on macOS we reimplement the minimum to achieve `smol::process::Command` with `posix_spawn` under-the-hood Notably, this changeset improves git-blame in very large repos significantly. Release Notes: - Fixed performance spawning child processes on macOS by always forcing `posix_spawn` no matter what. --------- Co-authored-by: Cole Miller <cole@zed.dev>
This commit is contained in:
1 parent
4f54c3e07c
commit
16dfc60ad2
38 files changed
+1140
-297
No files matched your search
@@ -80,16 +80,15 @@ pub async fn get_messages(working_directory: &Path, shas: &[Oid]) -> Result<Hash
|
||||
|
||||
async fn get_messages_impl(working_directory: &Path, shas: &[Oid]) -> Result<Vec<String>> {
|
||||
const MARKER: &str = "<MARKER>";
|
||||
let mut cmd = util::command::new_smol_command("git");
|
||||
cmd.current_dir(working_directory)
|
||||
let output = util::command::new_command("git")
|
||||
.current_dir(working_directory)
|
||||
.arg("show")
|
||||
.arg("-s")
|
||||
.arg(format!("--format=%B{}", MARKER))
|
||||
.args(shas.iter().map(ToString::to_string));
|
||||
let output = cmd
|
||||
.args(shas.iter().map(ToString::to_string))
|
||||
.output()
|
||||
.await
|
||||
.with_context(|| format!("starting git blame process: {:?}", cmd))?;
|
||||
.context("starting git show process")?;
|
||||
anyhow::ensure!(
|
||||
output.status.success(),
|
||||
"'git show' failed with error {:?}",
|
||||
|
||||
Reference in new issue
Block a user