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 {
51 let snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
52 if snapshot == INVALID_HANDLE_VALUE {
53 log::debug!(
54 "CreateToolhelp32Snapshot failed for PID existence check, error: {}",
55 windows_sys::Win32::Foundation::GetLastError()
56 );
57 return None;
58 }
59
60 let result = {
61 let mut entry: PROCESSENTRY32 = std::mem::zeroed();
62 entry.dwSize = std::mem::size_of::<PROCESSENTRY32>() as u32;
63
64 if Process32First(snapshot, &mut entry) == 0 {
65 log::debug!(
66 "Process32First failed, error: {}",
67 windows_sys::Win32::Foundation::GetLastError()
68 );
69 None
70 } else {
71 let mut found = false;
72 loop {
73 if entry.th32ProcessID == pid {
74 found = true;
75 break;
76 }
77 if Process32Next(snapshot, &mut entry) == 0 {
78 break;
79 }
80 }
81 Some(found)
82 }
83 };
84
85 CloseHandle(snapshot);
86 result
87 }
88}
89
90pub fn pid_is_running(pid: u32) -> Option<bool> {
91 #[cfg(unix)]
92 {
93 let result = unsafe { libc::kill(pid as i32, 0) };
96 if result == 0 {
97 return Some(true);
98 }
99 let error = std::io::Error::last_os_error();
100 if error.raw_os_error() == Some(libc::ESRCH) {
101 return Some(false);
102 }
103 None
104 }
105
106 #[cfg(windows)]
107 {
108 use windows_sys::Win32::Foundation::{
109 CloseHandle, ERROR_ACCESS_DENIED, ERROR_INVALID_PARAMETER,
110 };
111 use windows_sys::Win32::System::Threading::{OpenProcess, PROCESS_QUERY_INFORMATION};
112
113 unsafe {
116 let handle = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid);
117 if handle != 0 {
118 CloseHandle(handle);
119 Some(true)
120 } else {
121 let error = windows_sys::Win32::Foundation::GetLastError();
122 if error == ERROR_INVALID_PARAMETER {
123 Some(false)
124 } else if error == ERROR_ACCESS_DENIED {
125 log::debug!(
126 "OpenProcess({}) failed with ERROR_ACCESS_DENIED, falling back to ToolHelp enumeration",
127 pid
128 );
129 pid_exists_via_toolhelp(pid)
130 } else {
131 log::debug!(
132 "OpenProcess({}) failed with unexpected error: {}",
133 pid,
134 error
135 );
136 None
137 }
138 }
139 }
140 }
141
142 #[cfg(not(any(unix, windows)))]
143 {
144 let _ = pid;
145 None
146 }
147}