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
@@ -30,9 +30,9 @@ use terminal::terminal_settings::TerminalSettings;
|
||||
use smol::lock::OnceCell;
|
||||
use std::cmp::{Ordering, Reverse};
|
||||
use std::env::consts;
|
||||
use std::process::Stdio;
|
||||
use util::command::Stdio;
|
||||
|
||||
use util::command::new_smol_command;
|
||||
use util::command::new_command;
|
||||
use util::fs::{make_file_executable, remove_matching};
|
||||
use util::paths::PathStyle;
|
||||
use util::rel_path::RelPath;
|
||||
@@ -1620,7 +1620,7 @@ impl PyLspAdapter {
|
||||
let mut path = PathBuf::from(work_dir.as_ref());
|
||||
path.push("pylsp-venv");
|
||||
if !path.exists() {
|
||||
util::command::new_smol_command(python_path)
|
||||
util::command::new_command(python_path)
|
||||
.arg("-m")
|
||||
.arg("venv")
|
||||
.arg("pylsp-venv")
|
||||
@@ -1641,7 +1641,7 @@ impl PyLspAdapter {
|
||||
// Try to detect situations where `python3` exists but is not a real Python interpreter.
|
||||
// Notably, on fresh Windows installs, `python3` is a shim that opens the Microsoft Store app
|
||||
// when run with no arguments, and just fails otherwise.
|
||||
let Some(output) = new_smol_command(&path)
|
||||
let Some(output) = new_command(&path)
|
||||
.args(["-c", "print(1 + 2)"])
|
||||
.output()
|
||||
.await
|
||||
@@ -1853,7 +1853,7 @@ impl LspInstaller for PyLspAdapter {
|
||||
let venv = self.base_venv(delegate).await.map_err(|e| anyhow!(e))?;
|
||||
let pip_path = venv.join(BINARY_DIR).join("pip3");
|
||||
ensure!(
|
||||
util::command::new_smol_command(pip_path.as_path())
|
||||
util::command::new_command(pip_path.as_path())
|
||||
.arg("install")
|
||||
.arg("python-lsp-server[all]")
|
||||
.arg("--upgrade")
|
||||
@@ -1864,7 +1864,7 @@ impl LspInstaller for PyLspAdapter {
|
||||
"python-lsp-server[all] installation failed"
|
||||
);
|
||||
ensure!(
|
||||
util::command::new_smol_command(pip_path)
|
||||
util::command::new_command(pip_path)
|
||||
.arg("install")
|
||||
.arg("pylsp-mypy")
|
||||
.arg("--upgrade")
|
||||
@@ -2421,7 +2421,7 @@ impl LspAdapter for RuffLspAdapter {
|
||||
.0
|
||||
.ok()?;
|
||||
|
||||
let mut command = util::command::new_smol_command(&binary.path);
|
||||
let mut command = util::command::new_command(&binary.path);
|
||||
command
|
||||
.args(&["config", "--output-format", "json"])
|
||||
.stdout(Stdio::piped())
|
||||
|
||||
Reference in new issue
Block a user