summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorLinus Färnstrand <linus@mullvad.net>2017-06-13 11:45:13 +0200
committerLinus Färnstrand <linus@mullvad.net>2017-06-13 13:42:11 +0200
commit351dcdc456833a3d93f842e381a3a0d9ad886dd4 (patch)
tree5e8609df33a9222ba0ee2c3431c616126ce67902
parent734ca1551d08b6cadc4331916b8d53e681a379a4 (diff)
downloadmullvadvpn-351dcdc456833a3d93f842e381a3a0d9ad886dd4.tar.xz
mullvadvpn-351dcdc456833a3d93f842e381a3a0d9ad886dd4.zip
Add nice_kill method for graceful child exit
-rw-r--r--talpid_core/Cargo.toml5
-rw-r--r--talpid_core/src/process/mod.rs4
-rw-r--r--talpid_core/src/process/unix.rs33
3 files changed, 41 insertions, 1 deletions
diff --git a/talpid_core/Cargo.toml b/talpid_core/Cargo.toml
index 6fd7222f27..4b3afa4d80 100644
--- a/talpid_core/Cargo.toml
+++ b/talpid_core/Cargo.toml
@@ -5,12 +5,15 @@ authors = ["Linus Färnstrand <linus@mullvad.net>", "Erik Larkö <erik@mullvad.n
description = "Core backend functionality of the Mullvad VPN client"
[dependencies]
-duct = "0.8"
+duct = "0.9.1"
error-chain = "0.10"
log = "0.3"
jsonrpc-core = { git = "https://github.com/faern/jsonrpc", branch = "ws-close-handle" }
jsonrpc-macros = { git = "https://github.com/faern/jsonrpc", branch = "ws-close-handle" }
+[target.'cfg(unix)'.dependencies]
+libc = "0.2.20"
+
[dependencies.talpid_ipc]
path = "../talpid_ipc"
diff --git a/talpid_core/src/process/mod.rs b/talpid_core/src/process/mod.rs
index 6ae568907b..88bdc12ea4 100644
--- a/talpid_core/src/process/mod.rs
+++ b/talpid_core/src/process/mod.rs
@@ -1,2 +1,6 @@
/// A module for all OpenVPN related process management.
pub mod openvpn;
+
+/// Unix specific process management features.
+#[cfg(unix)]
+pub mod unix;
diff --git a/talpid_core/src/process/unix.rs b/talpid_core/src/process/unix.rs
new file mode 100644
index 0000000000..64599a6930
--- /dev/null
+++ b/talpid_core/src/process/unix.rs
@@ -0,0 +1,33 @@
+extern crate libc;
+
+use duct;
+use duct::unix::HandleExt;
+
+use std::io;
+use std::sync::{Arc, mpsc};
+use std::thread;
+use std::time::Duration;
+
+/// Kills a process by first sending it the `SIGTERM` signal and then wait up to `timeout`. If the
+/// process has not died after the timeout has expired it is killed.
+pub fn nice_kill(handle: Arc<duct::Handle>, timeout: Duration) -> io::Result<()> {
+ trace!("Sending SIGTERM to child process");
+ handle.send_signal(libc::SIGTERM)?;
+
+ if wait_timeout(handle.clone(), timeout) {
+ debug!("Child process exited from SIGTERM");
+ Ok(())
+ } else {
+ debug!("Child process did not exit from SIGTERM, sending SIGKILL");
+ handle.kill()
+ }
+}
+
+/// Wait for a process to die for a maximum of `timeout`. Returns true if the process died within
+/// the timeout. Warning, if the process does not exit in the given time, this function will leave
+/// a thread running until it does exit.
+fn wait_timeout(handle: Arc<duct::Handle>, timeout: Duration) -> bool {
+ let (stop, stopped) = mpsc::channel();
+ thread::spawn(move || { let _ = stop.send(handle.wait().is_ok()); });
+ stopped.recv_timeout(timeout).unwrap_or(false)
+}