use std::fmt::Display;
use std::str::FromStr;
use std::time::Duration;
use lazy_static::lazy_static;
use crate::stat_iterator::StatFile;
lazy_static!(
static ref CLOCK_TICKS: i64 = unsafe {
libc::sysconf(libc::_SC_CLK_TCK)
};
);
#[allow(clippy::upper_case_acronyms)]
pub enum Signal {
SIGSTOP,
SIGCONT,
SIGNULL,
}
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Hash, Debug)]
pub struct Pid(u32);
const INIT: Pid = Pid(1);
impl FromStr for Pid {
type Err = core::num::ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Pid(s.parse::<u32>()?))
}
}
impl TryFrom<&str> for Pid {
type Error = core::num::ParseIntError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
Pid::from_str(value)
}
}
impl From<u32> for Pid {
fn from(pid: u32) -> Self {
Self(pid)
}
}
impl Display for Pid {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Pid {
#[must_use]
pub fn get_ppid(&self) -> Self {
StatFile::open(*self)
.ok()
.and_then(|stat| {
let mut stat = stat.iter();
stat.nth(3).map(ToOwned::to_owned)
})
.and_then(|ppid| Self::from_str(&ppid).ok())
.unwrap_or(Self(0))
}
pub fn is_child_of(&self, other: Pid) -> bool {
let mut ppid = *self;
while ppid > INIT && ppid != other {
ppid = ppid.get_ppid();
}
ppid == other
}
pub fn get_cputime(&self) -> Duration {
StatFile::open(*self)
.ok()
.map(|stat| {
let stat = stat.iter();
let time: u64 = stat
.skip(13)
.take(2) .map(|t| t.parse::<u64>().unwrap_or_default())
.sum();
Duration::from_secs_f64(time as f64 / *CLOCK_TICKS as f64)
})
.unwrap_or(Duration::from_secs(0))
}
pub fn alive(&self) -> bool {
self.kill(&Signal::SIGNULL).is_ok()
}
#[inline]
pub(crate) fn kill(self, signal: &Signal) -> Result<(), ()> {
let sig = match signal {
Signal::SIGNULL => 0,
Signal::SIGSTOP => libc::SIGSTOP,
Signal::SIGCONT => libc::SIGCONT,
};
let res = unsafe { libc::kill(self.0 as _, sig) };
if res == 0 {
Ok(())
} else {
Err(())
}
}
}