pub(crate) fn refresh_procs(
    proc_list: &mut HashMap<Pid, Process>,
    path: &Path,
    uptime: u64,
    info: &SystemInfo,
    processes_to_update: ProcessesToUpdate<'_>,
    refresh_kind: ProcessRefreshKind,
) -> usize {
    #[cfg(feature = "multithread")]
    use rayon::iter::ParallelIterator;

    #[inline(always)]
    fn real_filter(e: &ProcAndTasks, filter: &[Pid]) -> bool {
        filter.contains(&e.pid)
    }

    #[inline(always)]
    fn empty_filter(_e: &ProcAndTasks, _filter: &[Pid]) -> bool {
        true
    }

    #[allow(clippy::type_complexity)]
    let (filter, filter_callback): (
        &[Pid],
        &(dyn Fn(&ProcAndTasks, &[Pid]) -> bool + Sync + Send),
    ) = 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);

    // This code goes through processes (listed in `/proc`) and through tasks (listed in
    // `/proc/[PID]/task`). However, the stored tasks information is supposed to be already present
    // in the PIDs listed from `/proc` so there will be no duplicates between PIDs and tasks PID.
    //
    // If a task is not listed in `/proc`, then we don't retrieve its information.
    //
    // So in short: since we update the `HashMap` itself by adding/removing entries outside of the
    // parallel iterator, we can safely use it inside the parallel iterator and update its entries
    // concurrently.
    let procs = {
        let d = match fs::read_dir(path) {
            Ok(d) => d,
            Err(_err) => {
                sysinfo_debug!("Failed to read folder {path:?}: {_err:?}");
                return 0;
            }
        };
        let proc_list = Wrap(UnsafeCell::new(proc_list));

        iter(d)
            .flat_map(|entry| {
                let Ok(entry) = entry else { return Vec::new() };
                let mut entries = Vec::new();
                get_all_pid_entries(None, None, entry, &mut entries, refresh_kind.tasks());
                entries
            })
            .filter(|e| filter_callback(e, filter))
            .filter_map(|e| {
                let proc_list = proc_list.get();
                let new_process = _get_process_data(
                    e.path.as_path(),
                    proc_list,
                    e.pid,
                    e.parent_pid,
                    uptime,
                    info,
                    refresh_kind,
                    e.tasks,
                )
                .ok()?;
                nb_updated.fetch_add(1, Ordering::Relaxed);
                new_process
            })
            .collect::<Vec<_>>()
    };
    for proc_ in procs {
        proc_list.insert(proc_.pid(), proc_);
    }
    nb_updated.into_inner()
}
We're forced to read the whole `/proc` folder because if a process died and another took its
place, we need to get the task parent (if it's a task).
src/unix/linux/process.rs