summaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
authorNathan Whitaker <17734409+nathanwhit@users.noreply.github.com>2024-09-12 12:24:58 -0700
committerGitHub <noreply@github.com>2024-09-12 19:24:58 +0000
commit18b89d948dcb849c4dc577478794c3d5fb23b597 (patch)
tree9945567e4b53dc50d2a61a3149b51edf97c05839 /runtime
parent3f15e300625723df10c564c4e29ec276288a931b (diff)
fix(ext/node): Implement detached option in `child_process` (#25218)
Fixes https://github.com/denoland/deno/issues/25193.
Diffstat (limited to 'runtime')
-rw-r--r--runtime/js/40_process.js13
-rw-r--r--runtime/ops/process.rs32
2 files changed, 35 insertions, 10 deletions
diff --git a/runtime/js/40_process.js b/runtime/js/40_process.js
index 358805180..ac9411916 100644
--- a/runtime/js/40_process.js
+++ b/runtime/js/40_process.js
@@ -157,6 +157,10 @@ function run({
return new Process(res);
}
+export const kExtraStdio = Symbol("extraStdio");
+export const kIpc = Symbol("ipc");
+export const kDetached = Symbol("detached");
+
const illegalConstructorKey = Symbol("illegalConstructorKey");
function spawnChildInner(command, apiName, {
@@ -166,13 +170,14 @@ function spawnChildInner(command, apiName, {
env = { __proto__: null },
uid = undefined,
gid = undefined,
+ signal = undefined,
stdin = "null",
stdout = "piped",
stderr = "piped",
- signal = undefined,
windowsRawArguments = false,
- ipc = -1,
- extraStdio = [],
+ [kDetached]: detached = false,
+ [kExtraStdio]: extraStdio = [],
+ [kIpc]: ipc = -1,
} = { __proto__: null }) {
const child = op_spawn_child({
cmd: pathFromURL(command),
@@ -188,6 +193,7 @@ function spawnChildInner(command, apiName, {
windowsRawArguments,
ipc,
extraStdio,
+ detached,
}, apiName);
return new ChildProcess(illegalConstructorKey, {
...child,
@@ -414,6 +420,7 @@ function spawnSync(command, {
stderr,
windowsRawArguments,
extraStdio: [],
+ detached: false,
});
return {
success: result.status.success,
diff --git a/runtime/ops/process.rs b/runtime/ops/process.rs
index d7058a053..b7242c07f 100644
--- a/runtime/ops/process.rs
+++ b/runtime/ops/process.rs
@@ -159,6 +159,7 @@ pub struct SpawnArgs {
stdio: ChildStdio,
extra_stdio: Vec<Stdio>,
+ detached: bool,
}
#[derive(Deserialize)]
@@ -243,12 +244,21 @@ fn create_command(
let mut command = std::process::Command::new(cmd);
#[cfg(windows)]
- if args.windows_raw_arguments {
- for arg in args.args.iter() {
- command.raw_arg(arg);
+ {
+ if args.detached {
+ // TODO(nathanwhit): Currently this causes the process to hang
+ // until the detached process exits (so never). It repros with just the
+ // rust std library, so it's either a bug or requires more control than we have.
+ // To be resolved at the same time as additional stdio support.
+ log::warn!("detached processes are not currently supported on Windows");
+ }
+ if args.windows_raw_arguments {
+ for arg in args.args.iter() {
+ command.raw_arg(arg);
+ }
+ } else {
+ command.args(args.args);
}
- } else {
- command.args(args.args);
}
#[cfg(not(windows))]
@@ -336,7 +346,11 @@ fn create_command(
}
}
+ let detached = args.detached;
command.pre_exec(move || {
+ if detached {
+ libc::setsid();
+ }
for &(src, dst) in &fds_to_dup {
if src >= 0 && dst >= 0 {
let _fd = libc::dup2(src, dst);
@@ -402,12 +416,15 @@ fn spawn_child(
command: std::process::Command,
ipc_pipe_rid: Option<ResourceId>,
extra_pipe_rids: Vec<Option<ResourceId>>,
+ detached: bool,
) -> Result<Child, AnyError> {
let mut command = tokio::process::Command::from(command);
// TODO(@crowlkats): allow detaching processes.
// currently deno will orphan a process when exiting with an error or Deno.exit()
// We want to kill child when it's closed
- command.kill_on_drop(true);
+ if !detached {
+ command.kill_on_drop(true);
+ }
let mut child = match command.spawn() {
Ok(child) => child,
@@ -647,9 +664,10 @@ fn op_spawn_child(
#[serde] args: SpawnArgs,
#[string] api_name: String,
) -> Result<Child, AnyError> {
+ let detached = args.detached;
let (command, pipe_rid, extra_pipe_rids, handles_to_close) =
create_command(state, args, &api_name)?;
- let child = spawn_child(state, command, pipe_rid, extra_pipe_rids);
+ let child = spawn_child(state, command, pipe_rid, extra_pipe_rids, detached);
for handle in handles_to_close {
close_raw_handle(handle);
}