1use anyhow::Result;
2
3pub fn is_alive(pid: u32) -> bool {
5 #[cfg(unix)]
6 {
7 unsafe { libc::kill(pid as libc::pid_t, 0) == 0 }
8 }
9 #[cfg(windows)]
10 {
11 use windows_sys::Win32::Foundation::{CloseHandle, STILL_ACTIVE, WAIT_TIMEOUT};
12 use windows_sys::Win32::System::Threading::{
13 GetExitCodeProcess, OpenProcess, WaitForSingleObject, PROCESS_QUERY_LIMITED_INFORMATION,
14 };
15
16 unsafe {
17 let handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, pid);
18 if handle.is_null() {
19 return false;
20 }
21 let wait = WaitForSingleObject(handle, 0);
22 if wait == WAIT_TIMEOUT {
23 CloseHandle(handle);
24 return true;
25 }
26 let mut exit_code: u32 = 0;
27 GetExitCodeProcess(handle, &mut exit_code);
28 CloseHandle(handle);
29 exit_code == STILL_ACTIVE as u32
30 }
31 }
32}
33
34pub fn terminate_gracefully(pid: u32) -> Result<()> {
37 #[cfg(unix)]
38 {
39 let ret = unsafe { libc::kill(pid as libc::pid_t, libc::SIGTERM) };
40 if ret != 0 {
41 anyhow::bail!(
42 "Failed to send SIGTERM to PID {pid}: {}",
43 std::io::Error::last_os_error()
44 );
45 }
46 Ok(())
47 }
48 #[cfg(windows)]
49 {
50 force_kill(pid)
51 }
52}
53
54pub fn force_kill(pid: u32) -> Result<()> {
56 #[cfg(unix)]
57 {
58 let ret = unsafe { libc::kill(pid as libc::pid_t, libc::SIGKILL) };
59 if ret != 0 {
60 anyhow::bail!(
61 "Failed to send SIGKILL to PID {pid}: {}",
62 std::io::Error::last_os_error()
63 );
64 }
65 Ok(())
66 }
67 #[cfg(windows)]
68 {
69 use windows_sys::Win32::Foundation::CloseHandle;
70 use windows_sys::Win32::System::Threading::{
71 OpenProcess, TerminateProcess, PROCESS_TERMINATE,
72 };
73
74 unsafe {
75 let handle = OpenProcess(PROCESS_TERMINATE, 0, pid);
76 if handle.is_null() {
77 anyhow::bail!(
78 "Failed to open PID {pid} for termination: {}",
79 std::io::Error::last_os_error()
80 );
81 }
82 let ok = TerminateProcess(handle, 1);
83 CloseHandle(handle);
84 if ok == 0 {
85 anyhow::bail!(
86 "Failed to terminate PID {pid}: {}",
87 std::io::Error::last_os_error()
88 );
89 }
90 Ok(())
91 }
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn current_process_is_alive() {
101 assert!(is_alive(std::process::id()));
102 }
103
104 #[test]
105 fn bogus_pid_is_not_alive() {
106 assert!(!is_alive(u32::MAX - 42));
107 }
108}