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;
}
/// Selected contents of the `/proc/PID/stat` file.
pub struct PidStat {
pub pid: Pid,
pub ppid: Pid,
@ -38,12 +39,14 @@ pub struct PidStat {
pub rss: i64,
}
pub fn read_proc_pid_stat(pid: libc::pid_t) -> Result<PidStat, Error> {
let stat = parse_proc_pid_stat(std::str::from_utf8(&std::fs::read(format!(
impl PidStat {
/// 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",
pid
))?)?)?;
if stat.pid.as_raw() != pid {
if stat.pid != pid {
bail!(
"unexpected pid for process: found pid {} in /proc/{}/stat",
stat.pid.as_raw(),
@ -53,7 +56,8 @@ pub fn read_proc_pid_stat(pid: libc::pid_t) -> Result<PidStat, Error> {
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 '('.
let cmdbeg = statstr
.find('(')
@ -112,10 +116,17 @@ fn parse_proc_pid_stat(statstr: &str) -> Result<PidStat, Error> {
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]
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 \
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 \
@ -134,19 +145,15 @@ fn test_read_proc_pid_stat() {
assert_eq!(stat.rss, 1910 * 4096);
}
#[deprecated(note = "use `PidStat`")]
pub fn read_proc_starttime(pid: libc::pid_t) -> Result<u64, Error> {
let info = read_proc_pid_stat(pid)?;
Ok(info.starttime)
PidStat::read_for_pid(Pid::from_raw(pid)).map(|stat| stat.starttime)
}
pub fn check_process_running(pid: libc::pid_t) -> Option<PidStat> {
if let Ok(info) = read_proc_pid_stat(pid) {
if info.status != b'Z' {
return Some(info);
}
}
None
PidStat::read_for_pid(Pid::from_raw(pid))
.ok()
.filter(|stat| stat.status != b'Z')
}
pub fn check_process_running_pstart(pid: libc::pid_t, pstart: u64) -> Option<PidStat> {