1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
use std::io; use std::process::Child; fn kill_process(process: &mut Child) -> Result<(), io::Error> { if let Ok(()) = process.kill() { process.wait()?; } else { println!("Process {} has already exited", process.id()); } Ok(()) } #[cfg(windows)] pub fn stop_process(process: &mut Child) -> Result<(), io::Error> { kill_process(process) } #[cfg(not(windows))] pub fn stop_process(process: &mut Child) -> Result<(), io::Error> { use nix::errno::Errno::{EINVAL, EPERM, ESRCH}; use nix::sys::signal::{kill, Signal}; use nix::unistd::Pid; use nix::Error::Sys; use std::io::ErrorKind; use std::thread; use std::time::{Duration, Instant}; let nice_wait = Duration::from_secs(5); let pid = Pid::from_raw(process.id() as i32); match kill(pid, Signal::SIGINT) { Ok(()) => { let expire = Instant::now() + nice_wait; while let Ok(None) = process.try_wait() { if Instant::now() > expire { break; } thread::sleep(nice_wait / 10); } if let Ok(None) = process.try_wait() { kill_process(process)?; } } Err(Sys(EINVAL)) => { println!("Invalid signal. Killing process {}", pid); kill_process(process)?; } Err(Sys(EPERM)) => { return Err(io::Error::new( ErrorKind::InvalidInput, format!("Insufficient permissions to signal process {}", pid), )); } Err(Sys(ESRCH)) => { return Err(io::Error::new( ErrorKind::InvalidInput, format!("Process {} does not exist", pid), )); } Err(e) => { return Err(io::Error::new( ErrorKind::InvalidInput, format!("Unexpected error {}", e), )); } }; Ok(()) }