sys: change PidStat API

Rather than standalone functions, `PidStat` now provides a
`read_for_pid` and `parse` method. Both are public.
One side effect is that the documentation of PidStat's
contents are on the same page as the ways to retrieve it.

Additionally, we deprecate `read_proc_starttime` as it was
reading the entire contents to then filter out one value, in
order to promote caching.

The standalone `read_proc_pid_stat` method is now also
deprecated.

Once we add pid-fds the API will feel cleaner this way.

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2020-01-14 12:01:06 +01:00
parent e3b41dc815
commit 42a155668e

View File

@ -26,6 +26,7 @@ lazy_static! {
static ref CLOCK_TICKS: f64 = sysconf(libc::_SC_CLK_TCK) as f64; static ref CLOCK_TICKS: f64 = sysconf(libc::_SC_CLK_TCK) as f64;
} }
/// Selected contents of the `/proc/PID/stat` file.
pub struct PidStat { pub struct PidStat {
pub pid: Pid, pub pid: Pid,
pub ppid: Pid, pub ppid: Pid,
@ -38,12 +39,14 @@ pub struct PidStat {
pub rss: i64, pub rss: i64,
} }
pub fn read_proc_pid_stat(pid: libc::pid_t) -> Result<PidStat, Error> { impl PidStat {
let stat = parse_proc_pid_stat(std::str::from_utf8(&std::fs::read(format!( /// Retrieve the `stat` file contents of a process.
pub fn read_for_pid(pid: Pid) -> Result<Self, Error> {
let stat = Self::parse(std::str::from_utf8(&std::fs::read(format!(
"/proc/{}/stat", "/proc/{}/stat",
pid pid
))?)?)?; ))?)?)?;
if stat.pid.as_raw() != pid { if stat.pid != pid {
bail!( bail!(
"unexpected pid for process: found pid {} in /proc/{}/stat", "unexpected pid for process: found pid {} in /proc/{}/stat",
stat.pid.as_raw(), stat.pid.as_raw(),
@ -53,7 +56,8 @@ pub fn read_proc_pid_stat(pid: libc::pid_t) -> Result<PidStat, Error> {
Ok(stat) Ok(stat)
} }
fn parse_proc_pid_stat(statstr: &str) -> Result<PidStat, Error> { /// Parse the contents of a `/proc/PID/stat` file.
pub fn parse(statstr: &str) -> Result<PidStat, Error> {
// It starts with the pid followed by a '('. // It starts with the pid followed by a '('.
let cmdbeg = statstr let cmdbeg = statstr
.find('(') .find('(')
@ -112,10 +116,17 @@ fn parse_proc_pid_stat(statstr: &str) -> Result<PidStat, Error> {
Ok(out) Ok(out)
} }
}
/// Read `/proc/PID/stat` for a pid.
#[deprecated(note = "use `PidStat::read_for_pid`")]
pub fn read_proc_pid_stat(pid: libc::pid_t) -> Result<PidStat, Error> {
PidStat::read_for_pid(Pid::from_raw(pid))
}
#[test] #[test]
fn test_read_proc_pid_stat() { fn test_read_proc_pid_stat() {
let stat = parse_proc_pid_stat( let stat = PidStat::parse(
"28900 (zsh) S 22489 28900 28900 34826 10252 4194304 6851 5946551 0 2344 6 3 25205 1413 \ "28900 (zsh) S 22489 28900 28900 34826 10252 4194304 6851 5946551 0 2344 6 3 25205 1413 \
20 0 1 0 287592 12496896 1910 18446744073709551615 93999319244800 93999319938061 \ 20 0 1 0 287592 12496896 1910 18446744073709551615 93999319244800 93999319938061 \
140722897984224 0 0 0 2 3686404 134295555 1 0 0 17 10 0 0 0 0 0 93999320079088 \ 140722897984224 0 0 0 2 3686404 134295555 1 0 0 17 10 0 0 0 0 0 93999320079088 \
@ -134,19 +145,15 @@ fn test_read_proc_pid_stat() {
assert_eq!(stat.rss, 1910 * 4096); assert_eq!(stat.rss, 1910 * 4096);
} }
#[deprecated(note = "use `PidStat`")]
pub fn read_proc_starttime(pid: libc::pid_t) -> Result<u64, Error> { pub fn read_proc_starttime(pid: libc::pid_t) -> Result<u64, Error> {
let info = read_proc_pid_stat(pid)?; PidStat::read_for_pid(Pid::from_raw(pid)).map(|stat| stat.starttime)
Ok(info.starttime)
} }
pub fn check_process_running(pid: libc::pid_t) -> Option<PidStat> { pub fn check_process_running(pid: libc::pid_t) -> Option<PidStat> {
if let Ok(info) = read_proc_pid_stat(pid) { PidStat::read_for_pid(Pid::from_raw(pid))
if info.status != b'Z' { .ok()
return Some(info); .filter(|stat| stat.status != b'Z')
}
}
None
} }
pub fn check_process_running_pstart(pid: libc::pid_t, pstart: u64) -> Option<PidStat> { pub fn check_process_running_pstart(pid: libc::pid_t, pstart: u64) -> Option<PidStat> {