Repository: GuillaumeGomez/sysinfo
Pull request #1325 (2024-07-28 21:31:25)

Changes on refreshing processes


Patch:
diff --git a/benches/basic.rs b/benches/basic.rs
index 05a2a9c..4d0f22f 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 9a12a7a..0ac208d 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/migration_guide.md b/migration_guide.md
index 3edb021..40e7552 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();
 ```
 
diff --git a/src/c_interface.rs b/src/c_interface.rs
index 5178959..592949a 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<System> = 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<System> = 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 5fd0d05..0e42628 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 6a49986..4f208e2 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 140d17e..77aaf84 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 09e4d61..80d4c5e 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::<Vec<_>>()
         };
 
-        // 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 04d174a..80a97f3 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<OsString> {
diff --git a/src/unix/linux/system.rs b/src/unix/linux/system.rs
index 83eca3c..1112dfb 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 4528972..7395c86 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 a6c4a06..4cce483 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<u8> = 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));


Test patch:
diff --git a/tests/process.rs b/tests/process.rs
index e0963de..869cddf 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 279f063..11faf2e 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<T> 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!(