1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum PidLiveness {
17 Running,
18 NotRunning,
19 Indeterminate,
20}
21
22impl PidLiveness {
23 pub fn is_definitely_not_running(self) -> bool {
24 matches!(self, Self::NotRunning)
25 }
26
27 pub fn is_running_or_indeterminate(self) -> bool {
28 matches!(self, Self::Running | Self::Indeterminate)
29 }
30}
31
32pub fn pid_liveness(pid: u32) -> PidLiveness {
33 match pid_is_running(pid) {
34 Some(true) => PidLiveness::Running,
35 Some(false) => PidLiveness::NotRunning,
36 None => PidLiveness::Indeterminate,
37 }
38}
39
40#[cfg(windows)]
41fn pid_exists_via_toolhelp(pid: u32) -> Option<bool> {
42 use windows_sys::Win32::Foundation::{CloseHandle, INVALID_HANDLE_VALUE};
43 use windows_sys::Win32::System::Diagnostics::ToolHelp::{
44 CreateToolhelp32Snapshot, PROCESSENTRY32, Process32First, Process32Next, TH32CS_SNAPPROCESS,
45 };
46
47 unsafe {
48 let snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
49 if snapshot == INVALID_HANDLE_VALUE {
50 log::debug!(
51 "CreateToolhelp32Snapshot failed for PID existence check, error: {}",
52 windows_sys::Win32::Foundation::GetLastError()
53 );
54 return None;
55 }
56
57 let result = {
58 let mut entry: PROCESSENTRY32 = std::mem::zeroed();
59 entry.dwSize = std::mem::size_of::<PROCESSENTRY32>() as u32;
60
61 if Process32First(snapshot, &mut entry) == 0 {
62 log::debug!(
63 "Process32First failed, error: {}",
64 windows_sys::Win32::Foundation::GetLastError()
65 );
66 None
67 } else {
68 let mut found = false;
69 loop {
70 if entry.th32ProcessID == pid {
71 found = true;
72 break;
73 }
74 if Process32Next(snapshot, &mut entry) == 0 {
75 break;
76 }
77 }
78 Some(found)
79 }
80 };
81
82 CloseHandle(snapshot);
83 result
84 }
85}
86
87pub fn pid_is_running(pid: u32) -> Option<bool> {
88 #[cfg(unix)]
89 {
90 let result = unsafe { libc::kill(pid as i32, 0) };
91 if result == 0 {
92 return Some(true);
93 }
94 let error = std::io::Error::last_os_error();
95 if error.raw_os_error() == Some(libc::ESRCH) {
96 return Some(false);
97 }
98 None
99 }
100
101 #[cfg(windows)]
102 {
103 use windows_sys::Win32::Foundation::{
104 CloseHandle, ERROR_ACCESS_DENIED, ERROR_INVALID_PARAMETER,
105 };
106 use windows_sys::Win32::System::Threading::{OpenProcess, PROCESS_QUERY_INFORMATION};
107
108 unsafe {
109 let handle = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid);
110 if handle != 0 {
111 CloseHandle(handle);
112 Some(true)
113 } else {
114 let error = windows_sys::Win32::Foundation::GetLastError();
115 if error == ERROR_INVALID_PARAMETER {
116 Some(false)
117 } else if error == ERROR_ACCESS_DENIED {
118 log::debug!(
119 "OpenProcess({}) failed with ERROR_ACCESS_DENIED, falling back to ToolHelp enumeration",
120 pid
121 );
122 pid_exists_via_toolhelp(pid)
123 } else {
124 log::debug!(
125 "OpenProcess({}) failed with unexpected error: {}",
126 pid,
127 error
128 );
129 None
130 }
131 }
132 }
133 }
134
135 #[cfg(not(any(unix, windows)))]
136 {
137 let _ = pid;
138 None
139 }
140}