Actually fix process cleanup
This commit is contained in:
parent
3849835ff9
commit
412b53aca6
3 changed files with 71 additions and 32 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -339,6 +339,7 @@ dependencies = [
|
||||||
"roxmltree",
|
"roxmltree",
|
||||||
"scheduled-executor",
|
"scheduled-executor",
|
||||||
"serde",
|
"serde",
|
||||||
|
"simple-signal",
|
||||||
"smart-default",
|
"smart-default",
|
||||||
"stoppable_thread",
|
"stoppable_thread",
|
||||||
"structopt",
|
"structopt",
|
||||||
|
@ -1634,6 +1635,16 @@ dependencies = [
|
||||||
"syn 1.0.44",
|
"syn 1.0.44",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simple-signal"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53f7da44adcc42667d57483bd93f81295f27d66897804b757573b61b6f13288b"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
|
|
@ -46,6 +46,7 @@ nix = "0.19"
|
||||||
smart-default = "0.6"
|
smart-default = "0.6"
|
||||||
filedescriptor = "0.7"
|
filedescriptor = "0.7"
|
||||||
ctrlc = { version = "3.1", features = [ "termination" ] }
|
ctrlc = { version = "3.1", features = [ "termination" ] }
|
||||||
|
simple-signal = "1.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "0.6.1"
|
pretty_assertions = "0.6.1"
|
||||||
|
|
|
@ -124,7 +124,9 @@ impl ScriptVarHandler {
|
||||||
};
|
};
|
||||||
util::print_result_err("in script-var tail handler thread", &result);
|
util::print_result_err("in script-var tail handler thread", &result);
|
||||||
}
|
}
|
||||||
script_var_processes.values().for_each(|process| process.kill());
|
for process in script_var_processes.values() {
|
||||||
|
util::print_result_err("While killing tail-var process at the end of tail task", &process.kill());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
self.tail_handler_thread = Some(thread_handle);
|
self.tail_handler_thread = Some(thread_handle);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -143,7 +145,7 @@ pub mod script_var_process {
|
||||||
sys::{signal, wait},
|
sys::{signal, wait},
|
||||||
unistd::Pid,
|
unistd::Pid,
|
||||||
};
|
};
|
||||||
use std::{io::BufReader, process::Stdio, sync::Mutex};
|
use std::{ffi::CString, io::BufReader, sync::Mutex};
|
||||||
|
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
|
||||||
|
@ -151,54 +153,79 @@ pub mod script_var_process {
|
||||||
static ref SCRIPT_VAR_CHILDREN: Mutex<Vec<u32>> = Mutex::new(Vec::new());
|
static ref SCRIPT_VAR_CHILDREN: Mutex<Vec<u32>> = Mutex::new(Vec::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn terminate_pid(pid: u32) {
|
fn terminate_pid(pid: u32) -> Result<()> {
|
||||||
println!("Killing pid: {}", pid);
|
signal::kill(Pid::from_raw(pid as i32), signal::SIGTERM)?;
|
||||||
let result = signal::kill(Pid::from_raw(pid as i32), signal::SIGTERM);
|
wait::waitpid(Pid::from_raw(pid as i32), None)?;
|
||||||
util::print_result_err("While killing tail-var child processes", &result);
|
Ok(())
|
||||||
let wait_result = wait::waitpid(Pid::from_raw(pid as i32), None);
|
|
||||||
util::print_result_err("While killing tail-var child processes", &wait_result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function should be called in the signal handler, killing all child processes.
|
/// This function should be called in the signal handler, killing all child processes.
|
||||||
pub fn on_application_death() {
|
pub fn on_application_death() {
|
||||||
SCRIPT_VAR_CHILDREN
|
SCRIPT_VAR_CHILDREN.lock().unwrap().drain(..).for_each(|pid| {
|
||||||
.lock()
|
let result = terminate_pid(pid);
|
||||||
.unwrap()
|
util::print_result_err("While killing process '{}' during cleanup", &result);
|
||||||
.drain(..)
|
});
|
||||||
.for_each(|pid| terminate_pid(pid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ScriptVarProcess {
|
pub struct ScriptVarProcess {
|
||||||
child: std::process::Child,
|
pid: i32,
|
||||||
pub stdout_reader: BufReader<std::process::ChildStdout>,
|
pub stdout_reader: BufReader<filedescriptor::FileDescriptor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScriptVarProcess {
|
impl ScriptVarProcess {
|
||||||
pub(super) fn run(command: &str) -> Result<Self> {
|
pub(super) fn run(command: &str) -> Result<Self> {
|
||||||
println!("Running {}", command);
|
use nix::unistd::*;
|
||||||
let mut child = std::process::Command::new("/bin/sh")
|
|
||||||
.arg("-c")
|
let pipe = filedescriptor::Pipe::new()?;
|
||||||
.arg(command)
|
|
||||||
.stdout(Stdio::piped())
|
match unsafe { fork()? } {
|
||||||
.stderr(Stdio::inherit())
|
ForkResult::Parent { child, .. } => {
|
||||||
.stdin(Stdio::null())
|
SCRIPT_VAR_CHILDREN.lock().unwrap().push(child.as_raw() as u32);
|
||||||
.spawn()?;
|
|
||||||
SCRIPT_VAR_CHILDREN.lock().unwrap().push(child.id());
|
Ok(ScriptVarProcess {
|
||||||
Ok(ScriptVarProcess {
|
stdout_reader: BufReader::new(pipe.read),
|
||||||
stdout_reader: BufReader::new(child.stdout.take().unwrap()),
|
pid: child.as_raw(),
|
||||||
child,
|
})
|
||||||
})
|
}
|
||||||
|
ForkResult::Child => {
|
||||||
|
let _ = setpgid(Pid::from_raw(0), Pid::from_raw(0));
|
||||||
|
match unsafe { fork()? } {
|
||||||
|
ForkResult::Parent { .. } => {
|
||||||
|
simple_signal::set_handler(&[simple_signal::Signal::Int, simple_signal::Signal::Term], |_| {
|
||||||
|
let pgid = getpgid(Some(getpid())).unwrap();
|
||||||
|
let _ = signal::killpg(pgid, nix::sys::signal::SIGKILL);
|
||||||
|
while nix::sys::wait::wait().unwrap().pid().is_some() {}
|
||||||
|
});
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
ForkResult::Child => {
|
||||||
|
execv(
|
||||||
|
CString::new("/bin/sh").unwrap().as_ref(),
|
||||||
|
&[
|
||||||
|
CString::new("/bin/sh").unwrap(),
|
||||||
|
CString::new("-c").unwrap(),
|
||||||
|
CString::new(command).unwrap(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
unreachable!(
|
||||||
|
"Child fork called exec, thus the process was replaced by the command the user provided"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn kill(&self) {
|
pub(super) fn kill(&self) -> Result<()> {
|
||||||
SCRIPT_VAR_CHILDREN.lock().unwrap().retain(|item| *item != self.child.id());
|
SCRIPT_VAR_CHILDREN.lock().unwrap().retain(|item| *item != self.pid as u32);
|
||||||
terminate_pid(self.child.id());
|
terminate_pid(self.pid as u32).context("Error manually killing tail-var script")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for ScriptVarProcess {
|
impl Drop for ScriptVarProcess {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.kill();
|
let _ = self.kill();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue