1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use crate::*;
use std::time::Duration;
use std::{io, process::Child};
use libc::timeval;
#[allow(clippy::useless_conversion)]
fn timeval_to_duration(val: timeval) -> Duration {
let v = i64::from(val.tv_sec) * 1_000_000 + i64::from(val.tv_usec);
Duration::from_micros(v as u64)
}
cfg_if::cfg_if! {
if #[cfg(any(target_os = "macos", target_os = "linux", target_os = "freebsd"))] {
use std::os::unix::process::ExitStatusExt;
impl Wait4 for Child {
fn wait4(&mut self) -> io::Result<ResUse> {
drop(self.stdin.take());
let pid = self.id() as i32;
let mut status = 0;
let options = 0;
let mut rusage = std::mem::MaybeUninit::zeroed();
let r = unsafe { libc::wait4(pid, &mut status, options, rusage.as_mut_ptr()) };
if r < 0 {
Err(io::Error::last_os_error())
} else {
let rusage = unsafe { rusage.assume_init() };
let maxrss = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
rusage.ru_maxrss
} else {
rusage.ru_maxrss * 1024
};
Ok(ResUse {
status: ExitStatus::from_raw(status),
rusage: ResourceUsage {
utime: timeval_to_duration(rusage.ru_utime),
stime: timeval_to_duration(rusage.ru_stime),
maxrss: maxrss as u64,
},
})
}
}
}
} else {
fn get_resource_usage(for_children: bool) -> ResourceUsage {
let who = if for_children {
libc::RUSAGE_CHILDREN
} else {
libc::RUSAGE_SELF
};
let rusage = unsafe {
let mut rusage = std::mem::MaybeUninit::zeroed();
libc::getrusage(who, rusage.as_mut_ptr());
rusage.assume_init()
};
let maxrss = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
rusage.ru_maxrss
} else {
rusage.ru_maxrss * 1024
};
ResourceUsage {
utime: timeval_to_duration(rusage.ru_utime),
stime: timeval_to_duration(rusage.ru_stime),
maxrss: maxrss as u64,
}
}
impl ResourceUsage {
/// Return resource usage statistics for all children of the calling process
/// that have terminated and been waited for.
/// These statistics will include the resources used by grandchildren,
/// and further removed descendants, if all of the intervening descendants waited
/// on their terminated children.
fn for_children() -> ResourceUsage {
get_resource_usage(true)
}
/*
/// Return resource usage statistics for the calling process, which is the sum
/// of resources used by all threads in the process.
fn for_self() -> ResourceUsage {
get_resource_usage(false)
}
*/
}
impl Wait4 for Child {
fn wait4(&mut self) -> io::Result<ResUse> {
self.wait().map(|status| {
let rusage = ResourceUsage::for_children();
ResUse { status, rusage }
})
}
}
}
}