1use anyhow::{Context, Result};
7use nix::sys::signal::{self, Signal};
8use nix::unistd::Pid;
9
10pub fn kill_process(pid: u32, force: bool) -> Result<()> {
17 if !is_running(pid) {
18 anyhow::bail!("process {pid} is no longer running");
19 }
20 let sig = if force {
21 Signal::SIGKILL
22 } else {
23 Signal::SIGTERM
24 };
25 signal::kill(Pid::from_raw(pid as i32), sig)
26 .with_context(|| format!("failed to send {sig} to pid {pid}"))
27}
28
29pub fn is_running(pid: u32) -> bool {
33 signal::kill(Pid::from_raw(pid as i32), None).is_ok()
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39
40 #[test]
41 fn current_process_is_running() {
42 assert!(is_running(std::process::id()));
43 }
44
45 #[test]
46 fn nonexistent_process_is_not_running() {
47 assert!(!is_running(4_000_000));
48 }
49
50 #[test]
51 fn kill_nonexistent_process_returns_error() {
52 assert!(kill_process(4_000_000, false).is_err());
53 }
54
55 #[test]
56 fn kill_error_message_contains_pid() {
57 let err = kill_process(4_000_000, false).unwrap_err();
58 assert!(err.to_string().contains("4000000"));
59 }
60}