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