Repository: GuillaumeGomez/sysinfo (Rust)

Issue:
[MacOs] Creating new System vs refreshing existing system does not have the same behavior for processes terminated after the original system was created
Thank you for this great crate!

**Describe the bug**
System: Apple M3 Pro
OS: MacOs Sequoia 15.3.1
Sysinfo version: 0.33.0

creating a new System has different behavior than refreshing for processes that are not yet waited for on Mac.

**To Reproduce**
Created a example main that reproduces the issue on mac where it fails on the last assertion.

On linux, the first old_system.process fails because the process is a Zombie which is expected

```rust
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let process_handle = tokio::process::Command::new("sleep")
        .arg("1")
        .spawn()
        .unwrap();

    let pid = Pid::from_u32(process_handle.id().unwrap());
    let mut old_system = sysinfo::System::new_with_specifics(RefreshKind::nothing());
    old_system.refresh_processes_specifics(
        ProcessesToUpdate::Some(&[pid]),
        true,
        ProcessRefreshKind::nothing(),
    );

    assert!(old_system.process(pid).unwrap().status() == ProcessStatus::Run);

    // Let the process finish
    sleep(Duration::from_secs(2)).await;

    // If we create a new system instance, the process is not found as would be expected
    let mut new_system = sysinfo::System::new_with_specifics(RefreshKind::nothing());
    new_system.refresh_processes_specifics(
        ProcessesToUpdate::Some(&[pid]),
        true,
        ProcessRefreshKind::nothing(),
    );

    // Passes on Mac, fails on linux with process.status == Zombie (which is expected)
    assert!(new_system.process(pid).is_none());

    // But refreshing a old system instance, the terminated process is not removed
    old_system.refresh_processes_specifics(
        ProcessesToUpdate::Some(&[pid]),
        true,
        ProcessRefreshKind::nothing(),
    );

    // Fails on Mac
    assert!(old_system.process(pid).is_none());

    drop(process_handle);

    Ok(())
}
```




Discussion: Reminds me of https://github.com/GuillaumeGomez/sysinfo/issues/1459. Can you check if it works with the current `master` branch please?
I pulled master and it fails at the last assertion as well. exists() is returning true.

Here is a dbg of the process in the last assertion:
```
old_system.process(pid).unwrap() = Process {
    pid: Pid(
        44006,
    ),
    parent: Some(
        Pid(
            43991,
        ),
    ),
    name: "sleep",
    environ: [],
    command: [],
    executable path: None,
    current working directory: None,
    memory usage: 0,
    virtual memory usage: 0,
    CPU usage: 0.0,
    accumulated CPU time: 0,
    status: Run,
    root: None,
    disk_usage: DiskUsage {
        total_written_bytes: 0,
        written_bytes: 0,
        total_read_bytes: 0,
        read_bytes: 0,
    },
    user_id: Some(
        Uid(
            XXX,
        ),
    ),
    effective_user_id: Some(
        Uid(
            XXX,
        ),
    ),
}
```

Is there any other info that could be useful that I can pull while I have master locally?
Found the issue: the system is still listing the PID, however the "new system" cannot get access to the process information, making it skip it. Quite the corner case. ^^'

Writing a fix.
Should be fixed now. If you could confirm it'd be awesome. :)



Fix (patch):
diff --git a/src/unix/apple/macos/process.rs b/src/unix/apple/macos/process.rs
index bf4fe2d31..b17d600ae 100644
--- a/src/unix/apple/macos/process.rs
+++ b/src/unix/apple/macos/process.rs
@@ -366,10 +366,11 @@ unsafe fn create_new_process(
         Some(info) => info,
         None => {
             let mut p = ProcessInner::new_empty(pid);
-            if get_exe_and_name_backup(&mut p, refresh_kind) {
+            if get_exe_and_name_backup(&mut p, refresh_kind, false) {
                 get_cwd_root(&mut p, refresh_kind);
                 return Ok(Some(Process { inner: p }));
             }
+            eprintln!("No name, let's leave");
             // If we can't even have the name, no point in keeping it.
             return Err(());
         }
@@ -381,7 +382,9 @@ unsafe fn create_new_process(
     let run_time = now.saturating_sub(start_time);
 
     let mut p = ProcessInner::new(pid, parent, start_time, run_time);
-    if !get_process_infos(&mut p, refresh_kind) && !get_exe_and_name_backup(&mut p, refresh_kind) {
+    if !get_process_infos(&mut p, refresh_kind)
+        && !get_exe_and_name_backup(&mut p, refresh_kind, false)
+    {
         // If we can't even have the name, no point in keeping it.
         return Err(());
     }
@@ -418,10 +421,11 @@ unsafe fn create_new_process(
 unsafe fn get_exe_and_name_backup(
     process: &mut ProcessInner,
     refresh_kind: ProcessRefreshKind,
+    force_check: bool,
 ) -> bool {
     let exe_needs_update = refresh_kind.exe().needs_update(|| process.exe.is_none());
-    if !process.name.is_empty() && !exe_needs_update {
-        return false;
+    if !process.name.is_empty() && !exe_needs_update && !force_check {
+        return true;
     }
     let mut buffer: Vec<u8> = Vec::with_capacity(libc::PROC_PIDPATHINFO_MAXSIZE as _);
     match libc::proc_pidpath(
@@ -665,10 +669,15 @@ pub(crate) fn update_process(
         if let Some(ref mut p) = (*wrap.0.get()).get_mut(&pid) {
             let p = &mut p.inner;
 
+            let mut extra_checked = false;
+
             if let Some(info) = get_bsd_info(pid) {
                 if info.pbi_start_tvsec != p.start_time {
-                    // We don't it to be removed, just replaced.
+                    // We don't want it to be removed, just replaced.
                     p.updated = true;
+                    // To ensure the name and exe path will be updated.
+                    p.name.clear();
+                    p.exe = None;
                     // The owner of this PID changed.
                     return create_new_process(pid, now, refresh_kind, Some(info), timebase_to_ms);
                 }
@@ -677,10 +686,19 @@ pub(crate) fn update_process(
                 if p.parent != parent {
                     p.parent = parent;
                 }
+            } else {
+                // Weird that we can't get this information. Sometimes, mac can list PIDs that do
+                // not exist anymore. So let's ensure that the process is actually still alive.
+                if !get_exe_and_name_backup(p, refresh_kind, true) {
+                    // So it's not actually alive, then let's un-update it so it will be removed.
+                    p.updated = false;
+                    return Ok(None);
+                }
+                extra_checked = true;
             }
 
-            if !get_process_infos(p, refresh_kind) {
-                get_exe_and_name_backup(p, refresh_kind);
+            if !get_process_infos(p, refresh_kind) && !extra_checked {
+                get_exe_and_name_backup(p, refresh_kind, false);
             }
             get_cwd_root(p, refresh_kind);
 
diff --git a/src/unix/apple/system.rs b/src/unix/apple/system.rs
index 3f224fd9a..7912e00e7 100644
--- a/src/unix/apple/system.rs
+++ b/src/unix/apple/system.rs
@@ -269,11 +269,11 @@ impl SystemInner {
                 &(dyn Fn(Pid, &[Pid]) -> bool + Sync + Send),
             ) = match processes_to_update {
                 ProcessesToUpdate::All => (&[], &empty_filter),
-                ProcessesToUpdate::Some(pids) => {
-                    if pids.is_empty() {
+                ProcessesToUpdate::Some(pids_to_refresh) => {
+                    if pids_to_refresh.is_empty() {
                         return 0;
                     }
-                    (pids, &real_filter)
+                    (pids_to_refresh, &real_filter)
                 }
             };