1use crate::Result;
2use miette::IntoDiagnostic;
3use once_cell::sync::Lazy;
4use std::sync::Mutex;
5use sysinfo::ProcessesToUpdate;
6#[cfg(unix)]
7use sysinfo::Signal;
8
9pub struct Procs {
10 system: Mutex<sysinfo::System>,
11}
12
13pub static PROCS: Lazy<Procs> = Lazy::new(Procs::new);
14
15impl Default for Procs {
16 fn default() -> Self {
17 Self::new()
18 }
19}
20
21impl Procs {
22 pub fn new() -> Self {
23 let procs = Self {
24 system: Mutex::new(sysinfo::System::new()),
25 };
26 procs.refresh_processes();
27 procs
28 }
29
30 pub fn title(&self, pid: u32) -> Option<String> {
31 self.system
32 .lock()
33 .unwrap()
34 .process(sysinfo::Pid::from_u32(pid))
35 .map(|p| p.name().to_string_lossy().to_string())
36 }
37
38 pub fn is_running(&self, pid: u32) -> bool {
39 self.system
40 .lock()
41 .unwrap()
42 .process(sysinfo::Pid::from_u32(pid))
43 .is_some()
44 }
45
46 pub fn all_children(&self, pid: u32) -> Vec<u32> {
47 let system = self.system.lock().unwrap();
48 let all = system.processes();
49 let mut children = vec![];
50 for (child_pid, process) in all {
51 let mut process = process;
52 while let Some(parent) = process.parent() {
53 if parent == sysinfo::Pid::from_u32(pid) {
54 children.push(child_pid.as_u32());
55 break;
56 }
57 process = system.process(parent).unwrap();
58 }
59 }
60 children
61 }
62
63 pub async fn kill_async(&self, pid: u32) -> Result<bool> {
64 let result = tokio::task::spawn_blocking(move || PROCS.kill(pid))
65 .await
66 .into_diagnostic()?;
67 Ok(result)
68 }
69
70 fn kill(&self, pid: u32) -> bool {
71 if let Some(process) = self
72 .system
73 .lock()
74 .unwrap()
75 .process(sysinfo::Pid::from_u32(pid))
76 {
77 debug!("killing process {}", pid);
78 #[cfg(windows)]
79 process.kill();
80 #[cfg(unix)]
81 process.kill_with(Signal::Term);
82 process.wait();
83 true
84 } else {
85 false
86 }
87 }
88
89 pub(crate) fn refresh_processes(&self) {
90 self.system
91 .lock()
92 .unwrap()
93 .refresh_processes(ProcessesToUpdate::All, true);
94 }
95}