use std::fmt;
use std::time::Duration;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ProcessInfo {
pub pid: u32,
pub name: String,
pub executable_path: Option<String>,
pub parent_pid: Option<u32>,
pub memory_usage: Option<u64>,
pub user_cpu_time: Option<Duration>,
pub kernel_cpu_time: Option<Duration>,
pub thread_count: Option<u32>,
pub priority_class: Option<ProcessPriority>,
pub creation_time: Option<SystemTime>,
}
impl ProcessInfo {
pub fn basic(pid: u32, name: String) -> Self {
Self {
pid,
name,
executable_path: None,
parent_pid: None,
memory_usage: None,
user_cpu_time: None,
kernel_cpu_time: None,
thread_count: None,
priority_class: None,
creation_time: None,
}
}
pub fn total_cpu_time(&self) -> Option<Duration> {
match (self.user_cpu_time, self.kernel_cpu_time) {
(Some(user), Some(kernel)) => Some(user + kernel),
(Some(user), None) => Some(user),
(None, Some(kernel)) => Some(kernel),
(None, None) => None,
}
}
pub fn memory_usage_mb(&self) -> Option<f64> {
self.memory_usage.map(|bytes| bytes as f64 / (1024.0 * 1024.0))
}
pub fn is_alive(&self) -> bool {
#[cfg(feature = "win32")]
{
use windows::Win32::Foundation::CloseHandle;
use windows::Win32::System::Threading::{
GetExitCodeProcess, OpenProcess, PROCESS_QUERY_LIMITED_INFORMATION,
};
const STILL_ACTIVE: u32 = 259;
unsafe {
let handle = match OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, self.pid) {
Ok(h) => h,
Err(_) => return false,
};
let mut exit_code: u32 = 0;
let ok = GetExitCodeProcess(handle, &mut exit_code).is_ok();
let _ = CloseHandle(handle);
ok && exit_code == STILL_ACTIVE
}
}
#[cfg(not(feature = "win32"))]
{
false
}
}
}
impl fmt::Display for ProcessInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}] {}", self.pid, self.name)?;
if let Some(mb) = self.memory_usage_mb() {
write!(f, " mem={:.1} MB", mb)?;
}
if let Some(t) = self.thread_count {
write!(f, " threads={}", t)?;
}
if let Some(ref p) = self.priority_class {
write!(f, " priority={}", p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ProcessPriority {
Idle,
BelowNormal,
Normal,
AboveNormal,
High,
Realtime,
}
impl fmt::Display for ProcessPriority {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
ProcessPriority::Idle => "Idle",
ProcessPriority::BelowNormal => "BelowNormal",
ProcessPriority::Normal => "Normal",
ProcessPriority::AboveNormal => "AboveNormal",
ProcessPriority::High => "High",
ProcessPriority::Realtime => "Realtime",
};
f.write_str(s)
}
}
impl ProcessPriority {
#[cfg(feature = "win32")]
pub fn to_windows_constant(&self) -> u32 {
use windows::Win32::System::Threading::*;
match self {
ProcessPriority::Idle => IDLE_PRIORITY_CLASS.0,
ProcessPriority::BelowNormal => BELOW_NORMAL_PRIORITY_CLASS.0,
ProcessPriority::Normal => NORMAL_PRIORITY_CLASS.0,
ProcessPriority::AboveNormal => ABOVE_NORMAL_PRIORITY_CLASS.0,
ProcessPriority::High => HIGH_PRIORITY_CLASS.0,
ProcessPriority::Realtime => REALTIME_PRIORITY_CLASS.0,
}
}
#[cfg(feature = "win32")]
pub fn from_windows_constant(value: u32) -> Option<Self> {
use windows::Win32::System::Threading::*;
match value {
v if v == IDLE_PRIORITY_CLASS.0 => Some(ProcessPriority::Idle),
v if v == BELOW_NORMAL_PRIORITY_CLASS.0 => Some(ProcessPriority::BelowNormal),
v if v == NORMAL_PRIORITY_CLASS.0 => Some(ProcessPriority::Normal),
v if v == ABOVE_NORMAL_PRIORITY_CLASS.0 => Some(ProcessPriority::AboveNormal),
v if v == HIGH_PRIORITY_CLASS.0 => Some(ProcessPriority::High),
v if v == REALTIME_PRIORITY_CLASS.0 => Some(ProcessPriority::Realtime),
_ => None,
}
}
}
use std::time::SystemTime;
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MemoryInfo {
pub working_set_size: u64,
pub peak_working_set_size: u64,
pub page_file_usage: u64,
pub peak_page_file_usage: u64,
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CpuTimes {
pub user_time: Duration,
pub kernel_time: Duration,
pub creation_time: SystemTime,
pub exit_time: Option<SystemTime>,
}
impl CpuTimes {
pub fn total(&self) -> Duration {
self.user_time + self.kernel_time
}
}