process: do not kill spawned processes on drop (#1814)

This updates the tokio `Command` and `Child` behavior to match that of
the stdlib: spawned processes will *not* be automatically killed when
the handle is dropped

Unlike the stdlib, any dropped (unix) processes may be reaped by tokio
behind-the-scenes after they exit and if new processes are awaited,
which mitigates the risks of piling up unreaped zombie unix processes

A `Command::kill_on_drop` method is added to allow the caller to
control whether the spawned child should be killed when the handle is
dropped. By default, this value is `false`.

The `Child::forget` method has been removed, as it is superseded by
`Command::kill_on_drop`
This commit is contained in:
Ivan Petkov
2019-11-22 20:10:05 -08:00
committed by Carl Lerche
parent 7b4c999341
commit e20dff39ce
3 changed files with 127 additions and 83 deletions
+1
View File
@@ -33,6 +33,7 @@ fn run_test() {
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.kill_on_drop(true)
.spawn()
.unwrap()
.boxed(),
+42
View File
@@ -0,0 +1,42 @@
#![cfg(all(unix, feature = "process"))]
#![warn(rust_2018_idioms)]
use std::process::Stdio;
use std::time::Duration;
use tokio::io::AsyncReadExt;
use tokio::process::Command;
use tokio::time::delay_for;
use tokio_test::assert_ok;
#[tokio::test]
async fn kill_on_drop() {
let mut cmd = Command::new("sh");
cmd.args(&[
"-c",
"
# Fork another child that won't get killed
sh -c 'sleep 1; echo child ran' &
disown -a
# Await our death
sleep 5
echo hello from beyond the grave
",
]);
let mut child = cmd
.kill_on_drop(true)
.stdout(Stdio::piped())
.spawn()
.unwrap();
delay_for(Duration::from_secs(2)).await;
let mut out = child.stdout().take().unwrap();
drop(child);
let mut msg = String::new();
assert_ok!(out.read_to_string(&mut msg).await);
assert_eq!("child ran\n", msg);
}