]> git.proxmox.com Git - rustc.git/blame - vendor/sysinfo/src/freebsd/process.rs
New upstream version 1.67.1+dfsg1
[rustc.git] / vendor / sysinfo / src / freebsd / process.rs
CommitLineData
923072b8
FG
1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::{DiskUsage, Gid, Pid, ProcessExt, ProcessRefreshKind, ProcessStatus, Signal, Uid};
4
5use std::fmt;
6use std::path::{Path, PathBuf};
7
487cf647
FG
8use libc::kill;
9
923072b8
FG
10use super::utils::{get_sys_value_str, WrapMap};
11
12#[doc(hidden)]
13impl From<libc::c_char> for ProcessStatus {
14 fn from(status: libc::c_char) -> ProcessStatus {
15 match status {
16 libc::SIDL => ProcessStatus::Idle,
17 libc::SRUN => ProcessStatus::Run,
18 libc::SSLEEP => ProcessStatus::Sleep,
19 libc::SSTOP => ProcessStatus::Stop,
20 libc::SZOMB => ProcessStatus::Zombie,
21 libc::SWAIT => ProcessStatus::Dead,
22 libc::SLOCK => ProcessStatus::LockBlocked,
23 x => ProcessStatus::Unknown(x as _),
24 }
25 }
26}
27
28impl fmt::Display for ProcessStatus {
29 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30 f.write_str(match *self {
31 ProcessStatus::Idle => "Idle",
32 ProcessStatus::Run => "Runnable",
33 ProcessStatus::Sleep => "Sleeping",
34 ProcessStatus::Stop => "Stopped",
35 ProcessStatus::Zombie => "Zombie",
36 ProcessStatus::Dead => "Dead",
37 ProcessStatus::LockBlocked => "LockBlocked",
38 _ => "Unknown",
39 })
40 }
41}
42
43#[doc = include_str!("../../md_doc/process.md")]
44pub struct Process {
45 pub(crate) name: String,
46 pub(crate) cmd: Vec<String>,
47 pub(crate) exe: PathBuf,
48 pub(crate) pid: Pid,
49 parent: Option<Pid>,
50 pub(crate) environ: Vec<String>,
51 pub(crate) cwd: PathBuf,
52 pub(crate) root: PathBuf,
53 pub(crate) memory: u64,
54 pub(crate) virtual_memory: u64,
55 pub(crate) updated: bool,
56 cpu_usage: f32,
57 start_time: u64,
58 run_time: u64,
59 pub(crate) status: ProcessStatus,
60 user_id: Uid,
61 group_id: Gid,
62 read_bytes: u64,
63 old_read_bytes: u64,
64 written_bytes: u64,
65 old_written_bytes: u64,
66}
67
68impl ProcessExt for Process {
69 fn kill_with(&self, signal: Signal) -> Option<bool> {
70 let c_signal = super::system::convert_signal(signal)?;
71 unsafe { Some(libc::kill(self.pid.0, c_signal) == 0) }
72 }
73
74 fn name(&self) -> &str {
75 &self.name
76 }
77
78 fn cmd(&self) -> &[String] {
79 &self.cmd
80 }
81
82 fn exe(&self) -> &Path {
83 self.exe.as_path()
84 }
85
86 fn pid(&self) -> Pid {
87 self.pid
88 }
89
90 fn environ(&self) -> &[String] {
91 &self.environ
92 }
93
94 fn cwd(&self) -> &Path {
95 self.cwd.as_path()
96 }
97
98 fn root(&self) -> &Path {
99 self.root.as_path()
100 }
101
102 fn memory(&self) -> u64 {
103 self.memory
104 }
105
106 fn virtual_memory(&self) -> u64 {
107 self.virtual_memory
108 }
109
110 fn parent(&self) -> Option<Pid> {
111 self.parent
112 }
113
114 fn status(&self) -> ProcessStatus {
115 self.status
116 }
117
118 fn start_time(&self) -> u64 {
119 self.start_time
120 }
121
122 fn run_time(&self) -> u64 {
123 self.run_time
124 }
125
126 fn cpu_usage(&self) -> f32 {
127 self.cpu_usage
128 }
129
130 fn disk_usage(&self) -> DiskUsage {
131 DiskUsage {
132 written_bytes: self.written_bytes.saturating_sub(self.old_written_bytes),
133 total_written_bytes: self.written_bytes,
134 read_bytes: self.read_bytes.saturating_sub(self.old_read_bytes),
135 total_read_bytes: self.read_bytes,
136 }
137 }
138
139 fn user_id(&self) -> Option<&Uid> {
140 Some(&self.user_id)
141 }
142
143 fn group_id(&self) -> Option<Gid> {
144 Some(self.group_id)
145 }
487cf647
FG
146
147 fn wait(&self) {
148 let mut status = 0;
149 // attempt waiting
150 unsafe {
151 if libc::waitpid(self.pid.0, &mut status, 0) < 0 {
152 // attempt failed (non-child process) so loop until process ends
153 let duration = std::time::Duration::from_millis(10);
154 while kill(self.pid.0, 0) == 0 {
155 std::thread::sleep(duration);
156 }
157 }
158 }
159 }
923072b8
FG
160}
161
162pub(crate) unsafe fn get_process_data(
163 kproc: &libc::kinfo_proc,
164 wrap: &WrapMap,
165 page_size: isize,
166 fscale: f32,
167 now: u64,
168 refresh_kind: ProcessRefreshKind,
169) -> Result<Option<Process>, ()> {
170 if kproc.ki_pid != 1 && (kproc.ki_flag as libc::c_int & libc::P_SYSTEM) != 0 {
171 // We filter out the kernel threads.
172 return Err(());
173 }
174
175 // We now get the values needed for both new and existing process.
176 let cpu_usage = if refresh_kind.cpu() {
177 (100 * kproc.ki_pctcpu) as f32 / fscale
178 } else {
179 0.
180 };
181 // Processes can be reparented apparently?
182 let parent = if kproc.ki_ppid != 0 {
183 Some(Pid(kproc.ki_ppid))
184 } else {
185 None
186 };
187 let status = ProcessStatus::from(kproc.ki_stat);
188
189 // from FreeBSD source /src/usr.bin/top/machine.c
487cf647
FG
190 let virtual_memory = kproc.ki_size as _;
191 let memory = (kproc.ki_rssize as u64).saturating_mul(page_size as _);
923072b8
FG
192 // FIXME: This is to get the "real" run time (in micro-seconds).
193 // let run_time = (kproc.ki_runtime + 5_000) / 10_000;
194
487cf647
FG
195 let start_time = kproc.ki_start.tv_sec as u64;
196
923072b8 197 if let Some(proc_) = (*wrap.0.get()).get_mut(&Pid(kproc.ki_pid)) {
923072b8 198 proc_.updated = true;
487cf647
FG
199 // If the `start_time` we just got is different from the one stored, it means it's not the
200 // same process.
201 if proc_.start_time == start_time {
202 proc_.cpu_usage = cpu_usage;
203 proc_.parent = parent;
204 proc_.status = status;
205 proc_.virtual_memory = virtual_memory;
206 proc_.memory = memory;
207 proc_.run_time = now.saturating_sub(proc_.start_time);
208
209 if refresh_kind.disk_usage() {
210 proc_.old_read_bytes = proc_.read_bytes;
211 proc_.read_bytes = kproc.ki_rusage.ru_inblock as _;
212 proc_.old_written_bytes = proc_.written_bytes;
213 proc_.written_bytes = kproc.ki_rusage.ru_oublock as _;
214 }
215
216 return Ok(None);
923072b8 217 }
923072b8
FG
218 }
219
220 // This is a new process, we need to get more information!
221 let mut buffer = [0; libc::PATH_MAX as usize + 1];
222
223 let exe = get_sys_value_str(
224 &[
225 libc::CTL_KERN,
226 libc::KERN_PROC,
227 libc::KERN_PROC_PATHNAME,
228 kproc.ki_pid,
229 ],
230 &mut buffer,
231 )
232 .unwrap_or_default();
233 // For some reason, it can return completely invalid path like `p\u{5}`. So we need to use
234 // procstat to get around this problem.
235 // let cwd = get_sys_value_str(
236 // &[
237 // libc::CTL_KERN,
238 // libc::KERN_PROC,
239 // libc::KERN_PROC_CWD,
240 // kproc.ki_pid,
241 // ],
242 // &mut buffer,
243 // )
244 // .map(|s| s.into())
245 // .unwrap_or_else(PathBuf::new);
246
923072b8
FG
247 Ok(Some(Process {
248 pid: Pid(kproc.ki_pid),
249 parent,
250 user_id: Uid(kproc.ki_ruid),
251 group_id: Gid(kproc.ki_rgid),
252 start_time,
253 run_time: now.saturating_sub(start_time),
254 cpu_usage,
255 virtual_memory,
256 memory,
257 // procstat_getfiles
258 cwd: PathBuf::new(),
259 exe: exe.into(),
260 // kvm_getargv isn't thread-safe so we get it in the main thread.
261 name: String::new(),
262 // kvm_getargv isn't thread-safe so we get it in the main thread.
263 cmd: Vec::new(),
264 // kvm_getargv isn't thread-safe so we get it in the main thread.
265 root: PathBuf::new(),
266 // kvm_getenvv isn't thread-safe so we get it in the main thread.
267 environ: Vec::new(),
268 status,
269 read_bytes: kproc.ki_rusage.ru_inblock as _,
270 old_read_bytes: 0,
271 written_bytes: kproc.ki_rusage.ru_oublock as _,
272 old_written_bytes: 0,
487cf647 273 updated: false,
923072b8
FG
274 }))
275}