From 6fc7c7c52ec6609da1f3fe863101078980d7b979 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 28 Jul 2024 23:29:43 +0200 Subject: [PATCH 1/2] Remove `System::refresh_process` and `System::refresh_process_specifics` methods. Create new `ProcessToUpdate` enum. Make `System::refresh_processes` and `System::refresh_processes_specifics` methods return the number of updated processes. --- benches/basic.rs | 8 +- examples/simple.rs | 2 +- src/c_interface.rs | 14 ++- src/common/system.rs | 212 +++++++++++-------------------------- src/lib.rs | 5 +- src/unix/apple/system.rs | 71 +++++-------- src/unix/freebsd/system.rs | 110 ++++++------------- src/unix/linux/process.rs | 30 ++++-- src/unix/linux/system.rs | 64 ++--------- src/unknown/system.rs | 15 +-- src/windows/system.rs | 71 +++++-------- tests/process.rs | 94 +++++++++------- tests/system.rs | 20 ++-- 13 files changed, 268 insertions(+), 448 deletions(-) diff --git a/benches/basic.rs b/benches/basic.rs index 05a2a9c54..4d0f22fef 100644 --- a/benches/basic.rs +++ b/benches/basic.rs @@ -33,9 +33,9 @@ fn bench_refresh_all(b: &mut test::Bencher) { fn bench_refresh_processes(b: &mut test::Bencher) { let mut s = sysinfo::System::new(); - s.refresh_processes(); // to load the whole processes list a first time. + s.refresh_processes(sysinfo::ProcessesToUpdate::All); // to load the whole processes list a first time. b.iter(move || { - s.refresh_processes(); + s.refresh_processes(sysinfo::ProcessesToUpdate::All); }); } @@ -44,7 +44,7 @@ fn bench_refresh_processes(b: &mut test::Bencher) { fn bench_first_refresh_processes(b: &mut test::Bencher) { b.iter(move || { let mut s = sysinfo::System::new(); - s.refresh_processes(); + s.refresh_processes(sysinfo::ProcessesToUpdate::All); }); } @@ -57,7 +57,7 @@ fn bench_refresh_process(b: &mut test::Bencher) { // to be sure it'll exist for at least as long as we run let pid = sysinfo::get_current_pid().expect("failed to get current pid"); b.iter(move || { - s.refresh_process(pid); + s.refresh_processes(sysinfo::ProcessesToUpdate::Some(&[pid])); }); } diff --git a/examples/simple.rs b/examples/simple.rs index 9a12a7a3c..0ac208db4 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -409,7 +409,7 @@ fn interpret_input( .take(1) .next() { - if sys.refresh_process(pid) { + if sys.refresh_processes(sysinfo::ProcessesToUpdate::Some(&[pid])) != 0 { writeln!(&mut io::stdout(), "Process `{pid}` updated successfully"); } else { writeln!(&mut io::stdout(), "Process `{pid}` couldn't be updated..."); diff --git a/src/c_interface.rs b/src/c_interface.rs index 517895977..592949a9c 100644 --- a/src/c_interface.rs +++ b/src/c_interface.rs @@ -1,6 +1,6 @@ // Take a look at the license at the top of the repository in the LICENSE file. -use crate::{Disks, Networks, Pid, Process, System}; +use crate::{Disks, Networks, Pid, Process, ProcessesToUpdate, System}; use libc::{self, c_char, c_float, c_uint, c_void, size_t}; use std::borrow::BorrowMut; use std::ffi::CString; @@ -86,7 +86,9 @@ pub extern "C" fn sysinfo_refresh_all(system: CSystem) { } } -/// Equivalent of [`System::refresh_processes()`][crate::System#method.refresh_processes]. +/// Equivalent of [`System::refresh_processes(ProcessesToUpdate::All)`]. +/// +/// [`System::refresh_processes(ProcessesToUpdate::All)`]: crate::System#method.refresh_processes #[no_mangle] pub extern "C" fn sysinfo_refresh_processes(system: CSystem) { assert!(!system.is_null()); @@ -94,13 +96,15 @@ pub extern "C" fn sysinfo_refresh_processes(system: CSystem) { let mut system: Box = Box::from_raw(system as *mut System); { let system: &mut System = system.borrow_mut(); - system.refresh_processes(); + system.refresh_processes(ProcessesToUpdate::All); } Box::into_raw(system); } } -/// Equivalent of [`System::refresh_process()`][crate::System#method.refresh_process]. +/// Equivalent of [`System::refresh_processes(ProcessesToUpdate::Some(pid))`]. +/// +/// [`System::refresh_processes(ProcessesToUpdate::Some(pid))`]: crate::System#method.refresh_processes #[no_mangle] pub extern "C" fn sysinfo_refresh_process(system: CSystem, pid: PID) { assert!(!system.is_null()); @@ -108,7 +112,7 @@ pub extern "C" fn sysinfo_refresh_process(system: CSystem, pid: PID) { let mut system: Box = Box::from_raw(system as *mut System); { let system: &mut System = system.borrow_mut(); - system.refresh_process(Pid(pid as _)); + system.refresh_processes(ProcessesToUpdate::Some(&[Pid::from_u32(pid as _)])); } Box::into_raw(system); } diff --git a/src/common/system.rs b/src/common/system.rs index 5fd0d0548..0e42628ef 100644 --- a/src/common/system.rs +++ b/src/common/system.rs @@ -107,7 +107,7 @@ impl System { self.refresh_cpu_specifics(kind); } if let Some(kind) = refreshes.processes() { - self.refresh_processes_specifics(kind); + self.refresh_processes_specifics(ProcessesToUpdate::All, kind); } } @@ -258,9 +258,10 @@ impl System { /// It does the same as: /// /// ```no_run - /// # use sysinfo::{ProcessRefreshKind, System, UpdateKind}; + /// # use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System, UpdateKind}; /// # let mut system = System::new(); /// system.refresh_processes_specifics( + /// ProcessesToUpdate::All, /// ProcessRefreshKind::new() /// .with_memory() /// .with_cpu() @@ -269,171 +270,54 @@ impl System { /// ); /// ``` /// + /// ⚠️ Unless `ProcessesToUpdate::All` is used, dead processes are not removed from + /// the set of processes kept in [`System`]. + /// /// ⚠️ On Linux, `sysinfo` keeps the `stat` files open by default. You can change this behaviour /// by using [`set_open_files_limit`][crate::set_open_files_limit]. /// /// Example: /// /// ```no_run - /// use sysinfo::System; + /// use sysinfo::{ProcessesToUpdate, System}; /// /// let mut s = System::new_all(); - /// s.refresh_processes(); + /// s.refresh_processes(ProcessesToUpdate::All); /// ``` - pub fn refresh_processes(&mut self) { + pub fn refresh_processes(&mut self, processes_to_update: ProcessesToUpdate<'_>) -> usize { self.refresh_processes_specifics( + processes_to_update, ProcessRefreshKind::new() .with_memory() .with_cpu() .with_disk_usage() .with_exe(UpdateKind::OnlyIfNotSet), - ); + ) } /// Gets all processes and updates the specified information. /// - /// ⚠️ On Linux, `sysinfo` keeps the `stat` files open by default. You can change this behaviour - /// by using [`set_open_files_limit`][crate::set_open_files_limit]. - /// - /// ```no_run - /// use sysinfo::{ProcessRefreshKind, System}; + /// Returns the number of updated processes. /// - /// let mut s = System::new_all(); - /// s.refresh_processes_specifics(ProcessRefreshKind::new()); - /// ``` - pub fn refresh_processes_specifics(&mut self, refresh_kind: ProcessRefreshKind) { - self.inner.refresh_processes_specifics(None, refresh_kind) - } - - /// Gets specified processes and updates their information. - /// - /// It does the same as: - /// - /// ```no_run - /// # use sysinfo::{Pid, ProcessRefreshKind, System, UpdateKind}; - /// # let mut system = System::new(); - /// system.refresh_pids_specifics( - /// &[Pid::from(1), Pid::from(2)], - /// ProcessRefreshKind::new() - /// .with_memory() - /// .with_cpu() - /// .with_disk_usage() - /// .with_exe(UpdateKind::OnlyIfNotSet), - /// ); - /// ``` + /// ⚠️ Unless `ProcessesToUpdate::All` is used, dead processes are not removed from + /// the set of processes kept in [`System`]. /// /// ⚠️ On Linux, `sysinfo` keeps the `stat` files open by default. You can change this behaviour /// by using [`set_open_files_limit`][crate::set_open_files_limit]. /// - /// Example: - /// /// ```no_run - /// use sysinfo::System; + /// use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System}; /// /// let mut s = System::new_all(); - /// s.refresh_processes(); + /// s.refresh_processes_specifics(ProcessesToUpdate::All, ProcessRefreshKind::new()); /// ``` - pub fn refresh_pids(&mut self, pids: &[Pid]) { - self.refresh_pids_specifics( - pids, - ProcessRefreshKind::new() - .with_memory() - .with_cpu() - .with_disk_usage() - .with_exe(UpdateKind::OnlyIfNotSet), - ); - } - - /// Gets specified processes and updates the specified information. - /// - /// ⚠️ On Linux, `sysinfo` keeps the `stat` files open by default. You can change this behaviour - /// by using [`set_open_files_limit`][crate::set_open_files_limit]. - /// - /// ```no_run - /// use sysinfo::{Pid, ProcessRefreshKind, System}; - /// - /// let mut s = System::new_all(); - /// s.refresh_pids_specifics(&[Pid::from(1), Pid::from(2)], ProcessRefreshKind::new()); - /// ``` - pub fn refresh_pids_specifics(&mut self, pids: &[Pid], refresh_kind: ProcessRefreshKind) { - if pids.is_empty() { - return; - } - self.inner - .refresh_processes_specifics(Some(pids), refresh_kind) - } - - /// Refreshes *only* the process corresponding to `pid`. Returns `false` if the process doesn't - /// exist (it will **NOT** be removed from the processes if it doesn't exist anymore). If it - /// isn't listed yet, it'll be added. - /// - /// ⚠️ If you need to refresh multiple processes at once, use [`refresh_pids`] instead! It has - /// much better performance. - /// - /// It is the same as calling: - /// - /// ```no_run - /// # use sysinfo::{Pid, ProcessRefreshKind, System, UpdateKind}; - /// # let mut system = System::new(); - /// # let pid = Pid::from(0); - /// system.refresh_process_specifics( - /// pid, - /// ProcessRefreshKind::new() - /// .with_memory() - /// .with_cpu() - /// .with_disk_usage() - /// .with_exe(UpdateKind::OnlyIfNotSet), - /// ); - /// ``` - /// - /// ⚠️ On Linux, `sysinfo` keeps the `stat` files open by default. You can change this behaviour - /// by using [`set_open_files_limit`][crate::set_open_files_limit]. - /// - /// Example: - /// - /// ```no_run - /// use sysinfo::{Pid, System}; - /// - /// let mut s = System::new_all(); - /// s.refresh_process(Pid::from(1337)); - /// ``` - /// - /// [`refresh_pids`]: #method.refresh_pids - pub fn refresh_process(&mut self, pid: Pid) -> bool { - self.refresh_process_specifics( - pid, - ProcessRefreshKind::new() - .with_memory() - .with_cpu() - .with_disk_usage() - .with_exe(UpdateKind::OnlyIfNotSet), - ) - } - - /// Refreshes *only* the process corresponding to `pid`. Returns `false` if the process doesn't - /// exist (it will **NOT** be removed from the processes if it doesn't exist anymore). If it - /// isn't listed yet, it'll be added. - /// - /// ⚠️ If you need to refresh multiple processes at once, use [`refresh_pids_specifics`] - /// instead! It has much better performance. - /// - /// ⚠️ On Linux, `sysinfo` keeps the `stat` files open by default. You can change this behaviour - /// by using [`set_open_files_limit`][crate::set_open_files_limit]. - /// - /// ```no_run - /// use sysinfo::{Pid, ProcessRefreshKind, System}; - /// - /// let mut s = System::new_all(); - /// s.refresh_process_specifics(Pid::from(1337), ProcessRefreshKind::new()); - /// ``` - /// - /// [`refresh_pids_specifics`]: #method.refresh_pids_specifics - pub fn refresh_process_specifics( + pub fn refresh_processes_specifics( &mut self, - pid: Pid, + processes_to_update: ProcessesToUpdate<'_>, refresh_kind: ProcessRefreshKind, - ) -> bool { - self.inner.refresh_process_specifics(pid, refresh_kind) + ) -> usize { + self.inner + .refresh_processes_specifics(processes_to_update, refresh_kind) } /// Returns the process list. @@ -1479,13 +1363,14 @@ impl Process { /// more information). /// /// ```no_run - /// use sysinfo::{Pid, ProcessRefreshKind, System}; + /// use sysinfo::{Pid, ProcessesToUpdate, ProcessRefreshKind, System}; /// /// let mut s = System::new_all(); /// // Wait a bit because CPU usage is based on diff. /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL); /// // Refresh CPU usage to get actual value. /// s.refresh_processes_specifics( + /// ProcessesToUpdate::All, /// ProcessRefreshKind::new().with_cpu() /// ); /// if let Some(process) = s.process(Pid::from(1337)) { @@ -1954,10 +1839,11 @@ assert_eq!(r.", stringify!($name), "().is_some(), false); /// already set: /// /// ```no_run -/// use sysinfo::{ProcessRefreshKind, System, UpdateKind}; +/// use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System, UpdateKind}; /// /// let mut system = System::new(); /// system.refresh_processes_specifics( +/// ProcessesToUpdate::All, /// ProcessRefreshKind::new().with_exe(UpdateKind::OnlyIfNotSet), /// ); /// ``` @@ -1984,6 +1870,33 @@ impl UpdateKind { } } +/// This enum allows you to specify if you want all processes to be updated or just +/// some of them. +/// +/// Example: +/// +/// ```no_run +/// use sysinfo::{ProcessesToUpdate, System, get_current_pid}; +/// +/// let mut system = System::new(); +/// // To refresh all processes: +/// system.refresh_processes(ProcessesToUpdate::All); +/// +/// // To refresh only the current one: +/// system.refresh_processes( +/// ProcessesToUpdate::Some(&[get_current_pid().unwrap()]), +/// ); +/// ``` +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ProcessesToUpdate<'a> { + /// To refresh all processes. + All, + /// To refresh only the processes with the listed [`Pid`]. + /// + /// [`Pid`]: crate::Pid + Some(&'a [Pid]), +} + /// Used to determine what you want to refresh specifically on the [`Process`] type. /// /// When all refresh are ruled out, a [`Process`] will still retrieve the following information: @@ -1997,12 +1910,15 @@ impl UpdateKind { /// extra computation. /// /// ``` -/// use sysinfo::{ProcessRefreshKind, System}; +/// use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System}; /// /// let mut system = System::new(); /// /// // We don't want to update the CPU information. -/// system.refresh_processes_specifics(ProcessRefreshKind::everything().without_cpu()); +/// system.refresh_processes_specifics( +/// ProcessesToUpdate::All, +/// ProcessRefreshKind::everything().without_cpu(), +/// ); /// /// for (_, proc_) in system.processes() { /// // We use a `==` comparison on float only because we know it's set to 0 here. @@ -2477,7 +2393,7 @@ mod test { } let mut s = System::new_all(); let total = s.processes().len() as isize; - s.refresh_processes(); + s.refresh_processes(ProcessesToUpdate::All); let new_total = s.processes().len() as isize; // There should be almost no difference in the processes count. assert!( @@ -2499,7 +2415,7 @@ mod test { return; } let mut s = System::new(); - s.refresh_processes(); + s.refresh_processes(ProcessesToUpdate::All); for proc_ in s.cpus() { assert_eq!(proc_.frequency(), 0); } @@ -2574,7 +2490,7 @@ mod test { } let mut s = System::new(); - s.refresh_processes(); + s.refresh_processes(ProcessesToUpdate::All); // All CPU usage will start at zero until the second refresh assert!(s .processes() @@ -2583,7 +2499,7 @@ mod test { // Wait a bit to update CPU usage values std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL); - s.refresh_processes(); + s.refresh_processes(ProcessesToUpdate::All); assert!(s .processes() .iter() @@ -2655,9 +2571,9 @@ mod test { { let mut s = System::new(); // First check what happens in case the process isn't already in our process list. - assert!(s.refresh_process(_pid)); - // Then check that it still returns true if the process is already in our process list. - assert!(s.refresh_process(_pid)); + assert_eq!(s.refresh_processes(ProcessesToUpdate::Some(&[_pid])), 1); + // Then check that it still returns 1 if the process is already in our process list. + assert_eq!(s.refresh_processes(ProcessesToUpdate::Some(&[_pid])), 1); } } } diff --git a/src/lib.rs b/src/lib.rs index 6a4998641..4f208e258 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,8 +77,8 @@ pub use crate::common::network::{IpNetwork, MacAddr, NetworkData, Networks}; #[cfg(feature = "system")] pub use crate::common::system::{ get_current_pid, CGroupLimits, Cpu, CpuRefreshKind, DiskUsage, LoadAvg, MemoryRefreshKind, Pid, - Process, ProcessRefreshKind, ProcessStatus, RefreshKind, Signal, System, ThreadKind, - UpdateKind, + Process, ProcessRefreshKind, ProcessStatus, ProcessesToUpdate, RefreshKind, Signal, System, + ThreadKind, UpdateKind, }; #[cfg(feature = "user")] pub use crate::common::user::{Group, Groups, User, Users}; @@ -191,6 +191,7 @@ use sysinfo::", stringify!($imports), r"; MemoryRefreshKind, Pid, Process, + ProcessesToUpdate, ProcessRefreshKind, ProcessStatus, RefreshKind, diff --git a/src/unix/apple/system.rs b/src/unix/apple/system.rs index 140d17eee..77aaf84f5 100644 --- a/src/unix/apple/system.rs +++ b/src/unix/apple/system.rs @@ -5,7 +5,7 @@ use crate::sys::cpu::*; use crate::sys::process::*; use crate::sys::utils::{get_sys_value, get_sys_value_by_name}; -use crate::{Cpu, CpuRefreshKind, LoadAvg, MemoryRefreshKind, Pid, Process, ProcessRefreshKind}; +use crate::{Cpu, CpuRefreshKind, LoadAvg, MemoryRefreshKind, Pid, Process, ProcessesToUpdate, ProcessRefreshKind}; #[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))] use std::cell::UnsafeCell; @@ -227,23 +227,25 @@ impl SystemInner { #[cfg(any(target_os = "ios", feature = "apple-sandbox"))] pub(crate) fn refresh_processes_specifics( &mut self, - _filter: Option<&[Pid]>, + processes_to_update: ProcessesToUpdate<'_>, _refresh_kind: ProcessRefreshKind, - ) { + ) -> usize { + 0 } #[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))] pub(crate) fn refresh_processes_specifics( &mut self, - filter: Option<&[Pid]>, + processes_to_update: ProcessesToUpdate<'_>, refresh_kind: ProcessRefreshKind, - ) { + ) -> usize { use crate::utils::into_iter; + use std::sync::atomic::{AtomicUsize, Ordering}; unsafe { let count = libc::proc_listallpids(::std::ptr::null_mut(), 0); if count < 1 { - return; + return 0; } } if let Some(pids) = get_proc_list() { @@ -258,15 +260,21 @@ impl SystemInner { } #[allow(clippy::type_complexity)] - let (filter, filter_callback): ( + let (filter, filter_callback, remove_processes): ( &[Pid], &(dyn Fn(Pid, &[Pid]) -> bool + Sync + Send), - ) = if let Some(filter) = filter { - (filter, &real_filter) - } else { - (&[], &empty_filter) + bool, + ) = match processes_to_update { + ProcessesToUpdate::All => (&[], &empty_filter, true), + ProcessesToUpdate::Some(pids) => { + if pids.is_empty() { + return 0; + } + (pids, &real_filter, false) + } }; + let nb_updated = AtomicUsize::new(0); let now = get_now(); let port = self.port; let time_interval = self.clock_info.as_mut().map(|c| c.get_time_interval(port)); @@ -281,6 +289,7 @@ impl SystemInner { if !filter_callback(pid, filter) { return None; } + nb_updated.fetch_add(1, Ordering::Relaxed); update_process(wrap, pid, time_interval, now, refresh_kind, false) .unwrap_or_default() }) @@ -289,41 +298,13 @@ impl SystemInner { entries.into_iter().for_each(|entry| { self.process_list.insert(entry.pid(), entry); }); - self.process_list - .retain(|_, proc_| std::mem::replace(&mut proc_.inner.updated, false)); - } - } - - #[cfg(any(target_os = "ios", feature = "apple-sandbox"))] - pub(crate) fn refresh_process_specifics( - &mut self, - _pid: Pid, - _refresh_kind: ProcessRefreshKind, - ) -> bool { - false - } - - #[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))] - pub(crate) fn refresh_process_specifics( - &mut self, - pid: Pid, - refresh_kind: ProcessRefreshKind, - ) -> bool { - let mut time_interval = None; - let now = get_now(); - - if refresh_kind.cpu() { - let port = self.port; - time_interval = self.clock_info.as_mut().map(|c| c.get_time_interval(port)); - } - let wrap = Wrap(UnsafeCell::new(&mut self.process_list)); - match update_process(&wrap, pid, time_interval, now, refresh_kind, true) { - Ok(Some(p)) => { - self.process_list.insert(p.pid(), p); - true + if remove_processes { + self.process_list + .retain(|_, proc_| std::mem::replace(&mut proc_.inner.updated, false)); } - Ok(_) => true, - Err(_) => false, + nb_updated.into_inner() + } else { + 0 } } diff --git a/src/unix/freebsd/system.rs b/src/unix/freebsd/system.rs index 09e4d612d..80d4c5e5d 100644 --- a/src/unix/freebsd/system.rs +++ b/src/unix/freebsd/system.rs @@ -1,7 +1,7 @@ // Take a look at the license at the top of the repository in the LICENSE file. use crate::{ - Cpu, CpuRefreshKind, LoadAvg, MemoryRefreshKind, Pid, Process, ProcessInner, ProcessRefreshKind, + Cpu, CpuRefreshKind, LoadAvg, MemoryRefreshKind, Pid, Process, ProcessesToUpdate, ProcessInner, ProcessRefreshKind, }; use std::cell::UnsafeCell; @@ -10,6 +10,7 @@ use std::ffi::CStr; use std::mem::MaybeUninit; use std::path::{Path, PathBuf}; use std::ptr::NonNull; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::{Duration, SystemTime}; use crate::sys::cpu::{physical_core_count, CpusWrapper}; @@ -116,71 +117,10 @@ impl SystemInner { pub(crate) fn refresh_processes_specifics( &mut self, - filter: Option<&[Pid]>, + processes_to_update: ProcessesToUpdate<'_>, refresh_kind: ProcessRefreshKind, - ) { - unsafe { self.refresh_procs(filter, refresh_kind) } - } - - pub(crate) fn refresh_process_specifics( - &mut self, - pid: Pid, - refresh_kind: ProcessRefreshKind, - ) -> bool { - unsafe { - let kd = self.system_info.kd.as_ptr(); - let mut count = 0; - let procs = libc::kvm_getprocs(kd, libc::KERN_PROC_PROC, 0, &mut count); - if count < 1 { - sysinfo_debug!("kvm_getprocs returned nothing..."); - return false; - } - let now = get_now(); - - let fscale = self.system_info.fscale; - let page_size = self.system_info.page_size as isize; - let proc_list = utils::WrapMap(UnsafeCell::new(&mut self.process_list)); - let procs: &mut [utils::KInfoProc] = - std::slice::from_raw_parts_mut(procs as _, count as _); - - #[cfg(feature = "multithread")] - use rayon::iter::ParallelIterator; - - macro_rules! multi_iter { - ($name:ident, $($iter:tt)+) => { - $name = crate::utils::into_iter(procs).$($iter)+; - } - } - - let ret; - #[cfg(not(feature = "multithread"))] - multi_iter!(ret, find(|kproc| kproc.ki_pid == pid.0)); - #[cfg(feature = "multithread")] - multi_iter!(ret, find_any(|kproc| kproc.ki_pid == pid.0)); - - let kproc = if let Some(kproc) = ret { - kproc - } else { - return false; - }; - match super::process::get_process_data( - kproc, - &proc_list, - page_size, - fscale, - now, - refresh_kind, - ) { - Ok(Some(process)) => { - self.process_list.insert(process.inner.pid, process); - } - Ok(None) => {} - Err(_) => return false, - } - let process = self.process_list.get_mut(&Pid(kproc.ki_pid)).unwrap(); - add_missing_proc_info(&mut self.system_info, kproc, process, refresh_kind); - true - } + ) -> usize { + unsafe { self.refresh_procs(processes_to_update, refresh_kind) } } // COMMON PART @@ -326,7 +266,11 @@ impl SystemInner { } impl SystemInner { - unsafe fn refresh_procs(&mut self, filter: Option<&[Pid]>, refresh_kind: ProcessRefreshKind) { + unsafe fn refresh_procs( + &mut self, + processes_to_update: ProcessesToUpdate<'_>, + refresh_kind: ProcessRefreshKind, + ) -> usize { let mut count = 0; let kvm_procs = libc::kvm_getprocs( self.system_info.kd.as_ptr(), @@ -336,7 +280,7 @@ impl SystemInner { ); if count < 1 { sysinfo_debug!("kvm_getprocs returned nothing..."); - return; + return 0; } #[inline(always)] @@ -350,15 +294,22 @@ impl SystemInner { } #[allow(clippy::type_complexity)] - let (filter, filter_callback): ( + let (filter, filter_callback, remove_processes): ( &[Pid], &(dyn Fn(&libc::kinfo_proc, &[Pid]) -> bool + Sync + Send), - ) = if let Some(filter) = filter { - (filter, &real_filter) - } else { - (&[], &empty_filter) + bool, + ) = match processes_to_update { + ProcessesToUpdate::All => (&[], &empty_filter, true), + ProcessesToUpdate::Some(pids) => { + if pids.is_empty() { + return 0; + } + (pids, &real_filter, false) + } }; + let nb_updated = AtomicUsize::new(0); + let new_processes = { #[cfg(feature = "multithread")] use rayon::iter::{ParallelIterator, ParallelIterator as IterTrait}; @@ -377,7 +328,7 @@ impl SystemInner { if !filter_callback(kproc, filter) { return None; } - super::process::get_process_data( + let ret = super::process::get_process_data( kproc, &proc_list, page_size, @@ -385,14 +336,18 @@ impl SystemInner { now, refresh_kind, ) - .ok()? + .ok()?; + nb_updated.fetch_add(1, Ordering::Relaxed); + ret }) .collect::>() }; - // We remove all processes that don't exist anymore. - self.process_list - .retain(|_, v| std::mem::replace(&mut v.inner.updated, false)); + if remove_processes { + // We remove all processes that don't exist anymore. + self.process_list + .retain(|_, v| std::mem::replace(&mut v.inner.updated, false)); + } for process in new_processes { self.process_list.insert(process.inner.pid, process); @@ -405,6 +360,7 @@ impl SystemInner { add_missing_proc_info(&mut self.system_info, kproc, process, refresh_kind); } } + nb_updated.into_inner() } } diff --git a/src/unix/linux/process.rs b/src/unix/linux/process.rs index 04d174ad4..80a97f3ab 100644 --- a/src/unix/linux/process.rs +++ b/src/unix/linux/process.rs @@ -9,7 +9,7 @@ use std::io::Read; use std::os::unix::ffi::OsStrExt; use std::path::{Path, PathBuf}; use std::str::{self, FromStr}; -use std::sync::atomic::Ordering; +use std::sync::atomic::{AtomicUsize, Ordering}; use bstr::ByteSlice; use libc::{c_ulong, gid_t, kill, uid_t}; @@ -19,7 +19,7 @@ use crate::sys::utils::{ get_all_data_from_file, get_all_utf8_data, realpath, PathHandler, PathPush, }; use crate::{ - DiskUsage, Gid, Pid, Process, ProcessRefreshKind, ProcessStatus, Signal, ThreadKind, Uid, + DiskUsage, Gid, Pid, Process, ProcessesToUpdate, ProcessRefreshKind, ProcessStatus, Signal, ThreadKind, Uid, }; use crate::sys::system::remaining_files; @@ -725,9 +725,9 @@ pub(crate) fn refresh_procs( path: &Path, uptime: u64, info: &SystemInfo, - filter: Option<&[Pid]>, + processes_to_update: ProcessesToUpdate<'_>, refresh_kind: ProcessRefreshKind, -) -> bool { +) -> usize { #[cfg(feature = "multithread")] use rayon::iter::ParallelIterator; @@ -745,18 +745,27 @@ pub(crate) fn refresh_procs( let (filter, filter_callback): ( &[Pid], &(dyn Fn(&ProcAndTasks, &[Pid]) -> bool + Sync + Send), - ) = if let Some(filter) = filter { - (filter, &real_filter) - } else { - (&[], &empty_filter) + ) = match processes_to_update { + ProcessesToUpdate::All => (&[], &empty_filter), + ProcessesToUpdate::Some(pids) => { + if pids.is_empty() { + return 0; + } + (pids, &real_filter) + } }; + let nb_updated = AtomicUsize::new(0); + // FIXME: To prevent retrieving a task more than once (it can be listed in `/proc/[PID]/task` // subfolder and directly in `/proc` at the same time), might be interesting to use a `HashSet`. let procs = { let d = match fs::read_dir(path) { Ok(d) => d, - Err(_) => return false, + Err(_err) => { + sysinfo_debug!("Failed to read folder {path:?}: {_err:?}"); + return 0 + }, }; let proc_list = Wrap(UnsafeCell::new(proc_list)); @@ -780,6 +789,7 @@ pub(crate) fn refresh_procs( refresh_kind, ) .ok()?; + nb_updated.fetch_add(1, Ordering::Relaxed); if let Some(ref mut p) = p { p.inner.tasks = e.tasks; } @@ -790,7 +800,7 @@ pub(crate) fn refresh_procs( for proc_ in procs { proc_list.insert(proc_.pid(), proc_); } - true + nb_updated.into_inner() } fn copy_from_file(entry: &Path) -> Vec { diff --git a/src/unix/linux/system.rs b/src/unix/linux/system.rs index 83eca3cb0..1112dfbe1 100644 --- a/src/unix/linux/system.rs +++ b/src/unix/linux/system.rs @@ -1,9 +1,9 @@ // Take a look at the license at the top of the repository in the LICENSE file. use crate::sys::cpu::{get_physical_core_count, CpusWrapper}; -use crate::sys::process::{_get_process_data, compute_cpu_usage, refresh_procs, unset_updated}; +use crate::sys::process::{compute_cpu_usage, refresh_procs, unset_updated}; use crate::sys::utils::{get_all_utf8_data, to_u64}; -use crate::{Cpu, CpuRefreshKind, LoadAvg, MemoryRefreshKind, Pid, Process, ProcessRefreshKind}; +use crate::{Cpu, CpuRefreshKind, LoadAvg, MemoryRefreshKind, Pid, Process, ProcessesToUpdate, ProcessRefreshKind}; use libc::{self, c_char, sysconf, _SC_CLK_TCK, _SC_HOST_NAME_MAX, _SC_PAGESIZE}; @@ -278,67 +278,23 @@ impl SystemInner { pub(crate) fn refresh_processes_specifics( &mut self, - filter: Option<&[Pid]>, + processes_to_update: ProcessesToUpdate<'_>, refresh_kind: ProcessRefreshKind, - ) { + ) -> usize { let uptime = Self::uptime(); - refresh_procs( + let nb_updated = refresh_procs( &mut self.process_list, Path::new("/proc"), uptime, &self.info, - filter, + processes_to_update, refresh_kind, ); - self.clear_procs(refresh_kind); - self.cpus.set_need_cpus_update(); - } - - pub(crate) fn refresh_process_specifics( - &mut self, - pid: Pid, - refresh_kind: ProcessRefreshKind, - ) -> bool { - let uptime = Self::uptime(); - match _get_process_data( - &Path::new("/proc/").join(pid.to_string()), - &mut self.process_list, - pid, - None, - uptime, - &self.info, - refresh_kind, - ) { - Ok((Some(p), pid)) => { - self.process_list.insert(pid, p); - } - Ok(_) => {} - Err(_e) => { - sysinfo_debug!("Cannot get information for PID {:?}: {:?}", pid, _e); - return false; - } - }; - if refresh_kind.cpu() { - self.refresh_cpus(true, CpuRefreshKind::new().with_cpu_usage()); - - if self.cpus.is_empty() { - eprintln!("Cannot compute process CPU usage: no cpus found..."); - return true; - } - let (new, old) = self.cpus.get_global_raw_times(); - let total_time = (if old >= new { 1 } else { new - old }) as f32; - let total_time = total_time / self.cpus.len() as f32; - - let max_cpu_usage = self.get_max_process_cpu_usage(); - if let Some(p) = self.process_list.get_mut(&pid) { - let p = &mut p.inner; - compute_cpu_usage(p, total_time, max_cpu_usage); - unset_updated(p); - } - } else if let Some(p) = self.process_list.get_mut(&pid) { - unset_updated(&mut p.inner); + if matches!(processes_to_update, ProcessesToUpdate::All) { + self.clear_procs(refresh_kind); + self.cpus.set_need_cpus_update(); } - true + nb_updated } // COMMON PART diff --git a/src/unknown/system.rs b/src/unknown/system.rs index 4528972d1..7395c864a 100644 --- a/src/unknown/system.rs +++ b/src/unknown/system.rs @@ -1,6 +1,6 @@ // Take a look at the license at the top of the repository in the LICENSE file. -use crate::{Cpu, CpuRefreshKind, LoadAvg, MemoryRefreshKind, Pid, Process, ProcessRefreshKind}; +use crate::{Cpu, CpuRefreshKind, LoadAvg, MemoryRefreshKind, Pid, Process, ProcessesToUpdate, ProcessRefreshKind}; use std::collections::HashMap; use std::time::Duration; @@ -38,17 +38,10 @@ impl SystemInner { pub(crate) fn refresh_processes_specifics( &mut self, - _filter: Option<&[Pid]>, + _processes_to_update: ProcessesToUpdate<'_>, _refresh_kind: ProcessRefreshKind, - ) { - } - - pub(crate) fn refresh_process_specifics( - &mut self, - _pid: Pid, - _refresh_kind: ProcessRefreshKind, - ) -> bool { - false + ) -> usize { + 0 } // COMMON PART diff --git a/src/windows/system.rs b/src/windows/system.rs index a6c4a0621..4cce483ba 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -1,6 +1,6 @@ // Take a look at the license at the top of the repository in the LICENSE file. -use crate::{Cpu, CpuRefreshKind, LoadAvg, MemoryRefreshKind, Pid, ProcessRefreshKind}; +use crate::{Cpu, CpuRefreshKind, LoadAvg, MemoryRefreshKind, Pid, ProcessesToUpdate, ProcessRefreshKind}; use crate::sys::cpu::*; use crate::{Process, ProcessInner}; @@ -182,34 +182,37 @@ impl SystemInner { None } - pub(crate) fn refresh_process_specifics( - &mut self, - pid: Pid, - refresh_kind: ProcessRefreshKind, - ) -> bool { - self.refresh_processes_specifics_inner(Some(&[pid]), refresh_kind) != 0 - } - - pub(crate) fn refresh_processes_specifics( - &mut self, - filter: Option<&[Pid]>, - refresh_kind: ProcessRefreshKind, - ) { - self.refresh_processes_specifics_inner(filter, refresh_kind); - } - #[allow(clippy::cast_ptr_alignment)] - pub(crate) fn refresh_processes_specifics_inner( + pub(crate) fn refresh_processes_specifics( &mut self, - filter: Option<&[Pid]>, + processes_to_update: ProcessesToUpdate<'_>, refresh_kind: ProcessRefreshKind, ) -> usize { - if let Some(filter) = filter { - if filter.is_empty() { - return 0; - } + #[inline(always)] + fn real_filter(e: Pid, filter: &[Pid]) -> bool { + filter.contains(&e) + } + + #[inline(always)] + fn empty_filter(_e: Pid, _filter: &[Pid]) -> bool { + true } + #[allow(clippy::type_complexity)] + let (filter_array, filter_callback, remove_processes): ( + &[Pid], + &(dyn Fn(Pid, &[Pid]) -> bool + Sync + Send), + bool, + ) = match processes_to_update { + ProcessesToUpdate::All => (&[], &empty_filter, true), + ProcessesToUpdate::Some(pids) => { + if pids.is_empty() { + return 0; + } + (pids, &real_filter, false) + } + }; + // Windows 10 notebook requires at least 512KiB of memory to make it in one go let mut buffer_size = 512 * 1024; let mut process_information: Vec = Vec::with_capacity(buffer_size); @@ -252,26 +255,6 @@ impl SystemInner { } } - #[inline(always)] - fn real_filter(e: Pid, filter: &[Pid]) -> bool { - filter.contains(&e) - } - - #[inline(always)] - fn empty_filter(_e: Pid, _filter: &[Pid]) -> bool { - true - } - - #[allow(clippy::type_complexity)] - let (filter_array, filter_callback): ( - &[Pid], - &(dyn Fn(Pid, &[Pid]) -> bool + Sync + Send), - ) = if let Some(filter) = filter { - (filter, &real_filter) - } else { - (&[], &empty_filter) - }; - // If we reach this point NtQuerySystemInformation succeeded // and the buffer contents are initialized process_information.set_len(buffer_size); @@ -354,7 +337,7 @@ impl SystemInner { for p in processes.into_iter() { self.process_list.insert(p.pid(), p); } - if filter.is_none() { + if remove_processes { // If it comes from `refresh_process` or `refresh_pids`, we don't remove // dead processes. self.process_list.retain(|_, v| replace(&mut v.inner.updated, false)); diff --git a/tests/process.rs b/tests/process.rs index e0963de56..869cddfe0 100644 --- a/tests/process.rs +++ b/tests/process.rs @@ -3,7 +3,7 @@ #![cfg(feature = "system")] use bstr::ByteSlice; -use sysinfo::{Pid, ProcessRefreshKind, RefreshKind, System, UpdateKind}; +use sysinfo::{Pid, ProcessRefreshKind, ProcessesToUpdate, RefreshKind, System, UpdateKind}; macro_rules! start_proc { ($time:literal, $name:literal) => { @@ -35,7 +35,10 @@ fn test_cwd() { let pid = Pid::from_u32(p.id() as _); std::thread::sleep(std::time::Duration::from_secs(1)); let mut s = System::new(); - s.refresh_processes_specifics(ProcessRefreshKind::new().with_cwd(UpdateKind::Always)); + s.refresh_processes_specifics( + ProcessesToUpdate::All, + ProcessRefreshKind::new().with_cwd(UpdateKind::Always), + ); p.kill().expect("Unable to kill process."); let processes = s.processes(); @@ -58,7 +61,10 @@ fn test_cmd() { std::thread::sleep(std::time::Duration::from_millis(500)); let mut s = System::new(); assert!(s.processes().is_empty()); - s.refresh_processes_specifics(ProcessRefreshKind::new().with_cmd(UpdateKind::Always)); + s.refresh_processes_specifics( + ProcessesToUpdate::All, + ProcessRefreshKind::new().with_cmd(UpdateKind::Always), + ); p.kill().expect("Unable to kill process"); assert!(!s.processes().is_empty()); if let Some(process) = s.process(Pid::from_u32(p.id() as _)) { @@ -104,7 +110,10 @@ fn test_environ() { let pid = Pid::from_u32(p.id() as _); let mut s = System::new(); - s.refresh_process_specifics(pid, sysinfo::ProcessRefreshKind::everything()); + s.refresh_processes_specifics( + ProcessesToUpdate::Some(&[pid]), + sysinfo::ProcessRefreshKind::everything(), + ); p.kill().expect("Unable to kill process."); let processes = s.processes(); @@ -134,7 +143,10 @@ fn test_environ() { let pid = Pid::from_u32(p.id() as _); let mut s = System::new(); - s.refresh_processes_specifics(ProcessRefreshKind::new().with_environ(UpdateKind::Always)); + s.refresh_processes_specifics( + ProcessesToUpdate::All, + ProcessRefreshKind::new().with_environ(UpdateKind::Always), + ); let processes = s.processes(); let proc_ = processes.get(&pid); @@ -157,7 +169,9 @@ fn test_process_refresh() { if !sysinfo::IS_SUPPORTED_SYSTEM || cfg!(feature = "apple-sandbox") { return; } - s.refresh_process(sysinfo::get_current_pid().expect("failed to get current pid")); + s.refresh_processes(ProcessesToUpdate::Some(&[ + sysinfo::get_current_pid().expect("failed to get current pid") + ])); assert!(s .process(sysinfo::get_current_pid().expect("failed to get current pid")) .is_some()); @@ -199,7 +213,7 @@ fn test_process_disk_usage() { std::thread::sleep(std::time::Duration::from_millis(250)); let mut system = System::new(); assert!(system.processes().is_empty()); - system.refresh_processes(); + system.refresh_processes(ProcessesToUpdate::All); assert!(!system.processes().is_empty()); system } @@ -235,7 +249,7 @@ fn test_process_disk_usage() { #[test] fn cpu_usage_is_not_nan() { let mut system = System::new(); - system.refresh_processes(); + system.refresh_processes(ProcessesToUpdate::All); if !sysinfo::IS_SUPPORTED_SYSTEM || cfg!(feature = "apple-sandbox") { return; @@ -252,7 +266,7 @@ fn cpu_usage_is_not_nan() { let mut checked = 0; first_pids.into_iter().for_each(|pid| { - system.refresh_process(pid); + system.refresh_processes(ProcessesToUpdate::Some(&[pid])); if let Some(p) = system.process(pid) { assert!(!p.cpu_usage().is_nan()); checked += 1; @@ -275,7 +289,7 @@ fn test_process_times() { let pid = Pid::from_u32(p.id() as _); std::thread::sleep(std::time::Duration::from_secs(1)); let mut s = System::new(); - s.refresh_processes(); + s.refresh_processes(ProcessesToUpdate::All); p.kill().expect("Unable to kill process."); if let Some(p) = s.process(pid) { @@ -305,7 +319,7 @@ fn test_process_session_id() { return; } let mut s = System::new(); - s.refresh_processes(); + s.refresh_processes(ProcessesToUpdate::All); assert!(s.processes().values().any(|p| p.session_id().is_some())); } @@ -322,7 +336,7 @@ fn test_refresh_processes() { // Checks that the process is listed as it should. let mut s = System::new(); - s.refresh_processes(); + s.refresh_processes(ProcessesToUpdate::All); assert!(s.process(pid).is_some()); // Check that the process name is not empty. @@ -334,7 +348,7 @@ fn test_refresh_processes() { // Let's give some time to the system to clean up... std::thread::sleep(std::time::Duration::from_secs(1)); - s.refresh_processes(); + s.refresh_processes(ProcessesToUpdate::All); // Checks that the process isn't listed anymore. assert!(s.process(pid).is_none()); } @@ -356,7 +370,7 @@ fn test_refresh_process_doesnt_remove() { let mut s = System::new_with_specifics( RefreshKind::new().with_processes(sysinfo::ProcessRefreshKind::new()), ); - s.refresh_processes(); + s.refresh_processes(ProcessesToUpdate::All); assert!(s.process(pid1).is_some()); assert!(s.process(pid2).is_some()); @@ -370,7 +384,7 @@ fn test_refresh_process_doesnt_remove() { // Let's give some time to the system to clean up... std::thread::sleep(std::time::Duration::from_secs(1)); - assert!(!s.refresh_process(pid1)); + assert_eq!(s.refresh_processes(ProcessesToUpdate::Some(&[pid1])), 0); // We check that none of the two processes were removed. assert!(s.process(pid1).is_some()); @@ -399,7 +413,7 @@ fn test_refresh_tasks() { // Checks that the task is listed as it should. let mut s = System::new(); - s.refresh_processes(); + s.refresh_processes(ProcessesToUpdate::All); assert!(s .process(pid) @@ -418,7 +432,7 @@ fn test_refresh_tasks() { // Let's give some time to the system to clean up... std::thread::sleep(std::time::Duration::from_secs(2)); - s.refresh_processes(); + s.refresh_processes(ProcessesToUpdate::All); assert!(!s .process(pid) @@ -448,7 +462,7 @@ fn test_refresh_process() { // Checks that the process is listed as it should. let mut s = System::new(); - s.refresh_process(pid); + s.refresh_processes(ProcessesToUpdate::Some(&[pid])); assert!(s.process(pid).is_some()); // Check that the process name is not empty. @@ -460,7 +474,7 @@ fn test_refresh_process() { // Let's give some time to the system to clean up... std::thread::sleep(std::time::Duration::from_secs(1)); - assert!(!s.refresh_process(pid)); + assert_eq!(s.refresh_processes(ProcessesToUpdate::Some(&[pid])), 0); // Checks that the process is still listed. assert!(s.process(pid).is_some()); } @@ -476,7 +490,7 @@ fn test_wait_child() { let pid = Pid::from_u32(p.id() as _); let mut s = System::new(); - s.refresh_process(pid); + s.refresh_processes(ProcessesToUpdate::Some(&[pid])); let process = s.process(pid).unwrap(); // Kill the child process. @@ -485,7 +499,7 @@ fn test_wait_child() { process.wait(); // Child process should not be present. - assert!(!s.refresh_process(pid)); + assert_eq!(s.refresh_processes(ProcessesToUpdate::Some(&[pid])), 0); assert!(before.elapsed() < std::time::Duration::from_millis(1000)); } @@ -512,14 +526,14 @@ fn test_wait_non_child() { let pid = Pid::from_u32(p.id()); let mut s = System::new(); - s.refresh_process(pid); + s.refresh_processes(ProcessesToUpdate::Some(&[pid])); let process = s.process(pid).expect("Process not found!"); // Wait for a non child process. process.wait(); // Child process should not be present. - assert!(!s.refresh_process(pid)); + assert_eq!(s.refresh_processes(ProcessesToUpdate::Some(&[pid])), 0); // should wait for 2s. assert!( @@ -654,13 +668,13 @@ fn test_process_specific_refresh() { macro_rules! update_specific_and_check { (memory) => { - s.refresh_process_specifics(pid, ProcessRefreshKind::new()); + s.refresh_processes_specifics(ProcessesToUpdate::Some(&[pid]), ProcessRefreshKind::new()); { let p = s.process(pid).unwrap(); assert_eq!(p.memory(), 0, "failed 0 check for memory"); assert_eq!(p.virtual_memory(), 0, "failed 0 check for virtual memory"); } - s.refresh_process_specifics(pid, ProcessRefreshKind::new().with_memory()); + s.refresh_processes_specifics(ProcessesToUpdate::Some(&[pid]), ProcessRefreshKind::new().with_memory()); { let p = s.process(pid).unwrap(); assert_ne!(p.memory(), 0, "failed non-0 check for memory"); @@ -668,7 +682,7 @@ fn test_process_specific_refresh() { } // And now we check that re-refreshing nothing won't remove the // information. - s.refresh_process_specifics(pid, ProcessRefreshKind::new()); + s.refresh_processes_specifics(ProcessesToUpdate::Some(&[pid]), ProcessRefreshKind::new()); { let p = s.process(pid).unwrap(); assert_ne!(p.memory(), 0, "failed non-0 check (number 2) for memory"); @@ -676,7 +690,7 @@ fn test_process_specific_refresh() { } }; ($name:ident, $method:ident, $($extra:tt)+) => { - s.refresh_process_specifics(pid, ProcessRefreshKind::new()); + s.refresh_processes_specifics(ProcessesToUpdate::Some(&[pid]), ProcessRefreshKind::new()); { let p = s.process(pid).unwrap(); assert_eq!( @@ -684,7 +698,7 @@ fn test_process_specific_refresh() { concat!("failed 0 check check for ", stringify!($name)), ); } - s.refresh_process_specifics(pid, ProcessRefreshKind::new().$method(UpdateKind::Always)); + s.refresh_processes_specifics(ProcessesToUpdate::Some(&[pid]), ProcessRefreshKind::new().$method(UpdateKind::Always)); { let p = s.process(pid).unwrap(); assert_ne!( @@ -693,7 +707,7 @@ fn test_process_specific_refresh() { } // And now we check that re-refreshing nothing won't remove the // information. - s.refresh_process_specifics(pid, ProcessRefreshKind::new()); + s.refresh_processes_specifics(ProcessesToUpdate::Some(&[pid]), ProcessRefreshKind::new()); { let p = s.process(pid).unwrap(); assert_ne!( @@ -703,10 +717,10 @@ fn test_process_specific_refresh() { } } - s.refresh_process_specifics(pid, ProcessRefreshKind::new()); + s.refresh_processes_specifics(ProcessesToUpdate::Some(&[pid]), ProcessRefreshKind::new()); check_empty(&s, pid); - s.refresh_process_specifics(pid, ProcessRefreshKind::new()); + s.refresh_processes_specifics(ProcessesToUpdate::Some(&[pid]), ProcessRefreshKind::new()); check_empty(&s, pid); update_specific_and_check!(memory); @@ -736,7 +750,7 @@ fn test_refresh_pids() { let child_pid = Pid::from_u32(p.id() as _); let pids = &[child_pid, self_pid]; std::thread::sleep(std::time::Duration::from_millis(500)); - s.refresh_pids(pids); + s.refresh_processes(ProcessesToUpdate::Some(pids)); p.kill().expect("Unable to kill process."); assert_eq!(s.processes().len(), 2); @@ -752,10 +766,10 @@ fn test_process_run_time() { } let mut s = System::new(); let current_pid = sysinfo::get_current_pid().expect("failed to get current pid"); - s.refresh_process(current_pid); + s.refresh_processes(ProcessesToUpdate::Some(&[current_pid])); let run_time = s.process(current_pid).expect("no process found").run_time(); std::thread::sleep(std::time::Duration::from_secs(2)); - s.refresh_process(current_pid); + s.refresh_processes(ProcessesToUpdate::Some(&[current_pid])); let new_run_time = s.process(current_pid).expect("no process found").run_time(); assert!( new_run_time > run_time, @@ -785,7 +799,7 @@ fn test_parent_change() { let pid = Pid::from_u32(p.id() as _); let mut s = System::new(); - s.refresh_processes(); + s.refresh_processes(ProcessesToUpdate::All); assert_eq!( s.process(pid).expect("process was not created").parent(), @@ -802,7 +816,7 @@ fn test_parent_change() { // Waiting for the parent process to stop. p.wait().expect("wait failed"); - s.refresh_processes(); + s.refresh_processes(ProcessesToUpdate::All); // Parent should not be around anymore. assert!(s.process(pid).is_none()); @@ -839,12 +853,12 @@ fn test_multiple_single_process_refresh() { let mut s = System::new(); let process_refresh_kind = ProcessRefreshKind::new().with_cpu(); - s.refresh_process_specifics(pid_a, process_refresh_kind); - s.refresh_process_specifics(pid_b, process_refresh_kind); + s.refresh_processes_specifics(ProcessesToUpdate::Some(&[pid_a]), process_refresh_kind); + s.refresh_processes_specifics(ProcessesToUpdate::Some(&[pid_b]), process_refresh_kind); std::thread::sleep(std::time::Duration::from_secs(1)); - s.refresh_process_specifics(pid_a, process_refresh_kind); - s.refresh_process_specifics(pid_b, process_refresh_kind); + s.refresh_processes_specifics(ProcessesToUpdate::Some(&[pid_a]), process_refresh_kind); + s.refresh_processes_specifics(ProcessesToUpdate::Some(&[pid_b]), process_refresh_kind); let cpu_a = s.process(pid_a).unwrap().cpu_usage(); let cpu_b = s.process(pid_b).unwrap().cpu_usage(); diff --git a/tests/system.rs b/tests/system.rs index 279f06314..11faf2e4d 100644 --- a/tests/system.rs +++ b/tests/system.rs @@ -3,7 +3,7 @@ #![cfg(feature = "system")] #![allow(clippy::assertions_on_constants)] -use sysinfo::System; +use sysinfo::{ProcessesToUpdate, System}; #[test] fn test_refresh_system() { @@ -27,8 +27,11 @@ fn test_refresh_process() { #[cfg(not(feature = "apple-sandbox"))] if sysinfo::IS_SUPPORTED_SYSTEM { - assert!( - sys.refresh_process(sysinfo::get_current_pid().expect("failed to get current pid")), + assert_eq!( + sys.refresh_processes(ProcessesToUpdate::Some(&[ + sysinfo::get_current_pid().expect("failed to get current pid") + ])), + 1, "process not listed", ); // Ensure that the process was really added to the list! @@ -41,7 +44,7 @@ fn test_refresh_process() { #[test] fn test_get_process() { let mut sys = System::new(); - sys.refresh_processes(); + sys.refresh_processes(ProcessesToUpdate::All); let current_pid = match sysinfo::get_current_pid() { Ok(pid) => pid, _ => { @@ -73,7 +76,7 @@ fn check_if_send_and_sync() { impl Bar for T where T: Sync {} let mut sys = System::new(); - sys.refresh_processes(); + sys.refresh_processes(ProcessesToUpdate::All); let current_pid = match sysinfo::get_current_pid() { Ok(pid) => pid, _ => { @@ -134,7 +137,7 @@ fn test_consecutive_cpu_usage_update() { let mut sys = System::new_all(); assert!(!sys.cpus().is_empty()); - sys.refresh_processes_specifics(ProcessRefreshKind::new().with_cpu()); + sys.refresh_processes_specifics(ProcessesToUpdate::All, ProcessRefreshKind::new().with_cpu()); let stop = Arc::new(AtomicBool::new(false)); // Spawning a few threads to ensure that it will actually have an impact on the CPU usage. @@ -163,7 +166,10 @@ fn test_consecutive_cpu_usage_update() { for it in 0..3 { std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL + Duration::from_millis(1)); for pid in &pids { - sys.refresh_process_specifics(*pid, ProcessRefreshKind::new().with_cpu()); + sys.refresh_processes_specifics( + ProcessesToUpdate::Some(&[*pid]), + ProcessRefreshKind::new().with_cpu(), + ); } // To ensure that Linux doesn't give too high numbers. assert!( From 10fc52bb04658597076758eaec2b380b5d61d19a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 29 Jul 2024 19:58:41 +0200 Subject: [PATCH 2/2] Add migration for 0.31 version --- migration_guide.md | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/migration_guide.md b/migration_guide.md index 3edb021ce..40e755224 100644 --- a/migration_guide.md +++ b/migration_guide.md @@ -1,5 +1,36 @@ # Migration guide +## 0.30 to 0.31 + +With this update, the minimum supported Rust version goes up to 1.74. + +### Major changes + +`System::refresh_process`, `System::refresh_process_specifics` and `System::refresh_pids` +methods were removed. The `System::refresh_processes` and `System::refresh_processes_specifics` +methods take a new argument of type `ProcessesToUpdate`. + +The equivalent of `System::refresh_process`, `System::refresh_process_specifics` and +`System::refresh_pids` looks like this: + +```rust +use sysinfo::{ProcessesToUpdate, System}; + +let pid = 1337; +let mut s = System::new(); +s.refresh_processes(ProcessesToUpdate::Some(&[pid.into()])); +``` + +The equivalent of `System::refresh_processes` and `System::refresh_processes_specifics` looks +like this: + +```rust +use sysinfo::{ProcessesToUpdate, System}; + +let mut s = System::new(); +s.refresh_processes(ProcessesToUpdate::All); +``` + ## 0.29 to 0.30 With this update, the minimum supported Rust version goes up to 1.69. @@ -16,7 +47,7 @@ So before you had: use sysinfo::{System, SystemExt}; // `SystemExt` is needed for both `new` and `refresh_processes`. -let s = System::new(); +let mut s = System::new(); s.refresh_processes(); ```