Repository: GuillaumeGomez/sysinfo (language: rust)

Issue:
Old process data is displayed, and refresh doesn't work
I'm unable to properly track the status of a program. If the program exits, its last data remains displayed, and calling `refresh` does not work. Only reinitializing the `System` instance resolves the issue(~~Well, almost~~).

Here's an example code snippet to demonstrate the issue:

```rust
// [dependencies]
// sysinfo = "0.33.1"
use sysinfo::{Pid, System};
use std::env;
use std::thread;
use std::time::Duration;

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() != 2 {
        println!("Usage: {} <pid>", args[0]);
        return;
    }

    let pid = match args[1].parse::<u32>() {
        Ok(pid) => pid as usize,
        Err(_) => {
            println!("Invalid PID format");
            return;
        }
    };

    let mut system_refresh = System::new();
    println!("Starting process monitoring...\n");
    
    loop {
        print!("Refresh method: ");
        system_refresh.refresh_all();
        match system_refresh.process(Pid::from(pid)) {
            Some(process) => println!("Status: {:?}", process.status()),
            None => println!("Status: Not Found"),
        }

        print!("New instance: ");
        let mut system_new = System::new();
        system_new.refresh_all();
        match system_new.process(Pid::from(pid)) {
            Some(process) => println!("Status: {:?}", process.status()),
            None => println!("Status: Not Found"),
        }

        println!("----------------------------------------");
        thread::sleep(Duration::from_secs(2));
    }
}
```

![Image](https://github.com/user-attachments/assets/8a2894f4-a523-42e3-bb70-7354bc9cc357)
And as can be seen in the image, the new initialization correctly detects that the process is no longer running(~~not found~~), while refresh still considers the program to be Run.
I would like the process status to be tracked correctly.And I think my question aligns with [this](https://github.com/GuillaumeGomez/sysinfo/issues/1452).



Discussion / hints:
So you want a "exists" field. Sounds like a good idea. 

Fix patch:
diff --git a/src/common/system.rs b/src/common/system.rs
index 2353a6c27..8f098cb65 100644
--- a/src/common/system.rs
+++ b/src/common/system.rs
@@ -351,7 +351,9 @@ impl System {
         }
         fn update(pid: &Pid, processes: &mut HashMap<Pid, Process>) {
             if let Some(proc) = processes.get_mut(pid) {
-                proc.inner.switch_updated();
+                if !proc.inner.switch_updated() {
+                    proc.inner.set_nonexistent();
+                }
             }
         }
 
@@ -1688,6 +1690,29 @@ impl Process {
             }
         }
     }
+
+    /// Returns `true` if the process doesn't exist anymore but was not yet removed from
+    /// the processes list because the `remove_dead_processes` argument was set to `false`
+    /// in methods like [`System::refresh_processes`].
+    ///
+    /// ```no_run
+    /// use sysinfo::{ProcessesToUpdate, System};
+    ///
+    /// let mut s = System::new_all();
+    /// // We set the `remove_dead_processes` to `false`.
+    /// s.refresh_processes(ProcessesToUpdate::All, false);
+    ///
+    /// for (_, process) in s.processes() {
+    ///     println!(
+    ///         "Process {:?} {}",
+    ///         process.pid(),
+    ///         if process.exists() { "exists" } else { "doesn't exist" },
+    ///     );
+    /// }
+    /// ```
+    pub fn exists(&self) -> bool {
+        self.inner.exists()
+    }
 }
 
 macro_rules! pid_decl {
diff --git a/src/unix/apple/app_store/process.rs b/src/unix/apple/app_store/process.rs
index dc7006dc9..6d0589e7c 100644
--- a/src/unix/apple/app_store/process.rs
+++ b/src/unix/apple/app_store/process.rs
@@ -104,4 +104,10 @@ impl ProcessInner {
     pub(crate) fn switch_updated(&mut self) -> bool {
         false
     }
+
+    pub(crate) fn set_nonexistent(&mut self) {}
+
+    pub(crate) fn exists(&self) -> bool {
+        false
+    }
 }
diff --git a/src/unix/apple/macos/process.rs b/src/unix/apple/macos/process.rs
index 2f9c94fd2..93b8263a5 100644
--- a/src/unix/apple/macos/process.rs
+++ b/src/unix/apple/macos/process.rs
@@ -46,6 +46,7 @@ pub(crate) struct ProcessInner {
     pub(crate) read_bytes: u64,
     pub(crate) written_bytes: u64,
     accumulated_cpu_time: u64,
+    exists: bool,
 }
 
 impl ProcessInner {
@@ -78,6 +79,7 @@ impl ProcessInner {
             read_bytes: 0,
             written_bytes: 0,
             accumulated_cpu_time: 0,
+            exists: true,
         }
     }
 
@@ -110,6 +112,7 @@ impl ProcessInner {
             read_bytes: 0,
             written_bytes: 0,
             accumulated_cpu_time: 0,
+            exists: true,
         }
     }
 
@@ -228,6 +231,14 @@ impl ProcessInner {
     pub(crate) fn switch_updated(&mut self) -> bool {
         std::mem::replace(&mut self.updated, false)
     }
+
+    pub(crate) fn set_nonexistent(&mut self) {
+        self.exists = false;
+    }
+
+    pub(crate) fn exists(&self) -> bool {
+        self.exists
+    }
 }
 
 #[allow(deprecated)] // Because of libc::mach_absolute_time.
diff --git a/src/unix/freebsd/process.rs b/src/unix/freebsd/process.rs
index 2aae0ba86..4b95e5cef 100644
--- a/src/unix/freebsd/process.rs
+++ b/src/unix/freebsd/process.rs
@@ -65,6 +65,7 @@ pub(crate) struct ProcessInner {
     written_bytes: u64,
     old_written_bytes: u64,
     accumulated_cpu_time: u64,
+    exists: bool,
 }
 
 impl ProcessInner {
@@ -176,6 +177,14 @@ impl ProcessInner {
     pub(crate) fn switch_updated(&mut self) -> bool {
         std::mem::replace(&mut self.updated, false)
     }
+
+    pub(crate) fn set_nonexistent(&mut self) {
+        self.exists = false;
+    }
+
+    pub(crate) fn exists(&self) -> bool {
+        self.exists
+    }
 }
 
 #[inline]
@@ -306,6 +315,7 @@ pub(crate) unsafe fn get_process_data(
                 0
             },
             updated: true,
+            exists: true,
         },
     }))
 }
diff --git a/src/unix/linux/process.rs b/src/unix/linux/process.rs
index cb62c2276..a3e83e21e 100644
--- a/src/unix/linux/process.rs
+++ b/src/unix/linux/process.rs
@@ -127,6 +127,7 @@ pub(crate) struct ProcessInner {
     thread_kind: Option<ThreadKind>,
     proc_path: PathBuf,
     accumulated_cpu_time: u64,
+    exists: bool,
 }
 
 impl ProcessInner {
@@ -165,6 +166,7 @@ impl ProcessInner {
             thread_kind: None,
             proc_path,
             accumulated_cpu_time: 0,
+            exists: true,
         }
     }
 
@@ -280,6 +282,14 @@ impl ProcessInner {
     pub(crate) fn switch_updated(&mut self) -> bool {
         std::mem::replace(&mut self.updated, false)
     }
+
+    pub(crate) fn set_nonexistent(&mut self) {
+        self.exists = false;
+    }
+
+    pub(crate) fn exists(&self) -> bool {
+        self.exists
+    }
 }
 
 pub(crate) fn compute_cpu_usage(p: &mut ProcessInner, total_time: f32, max_value: f32) {
diff --git a/src/unknown/process.rs b/src/unknown/process.rs
index 7a82131f4..ce122fd3c 100644
--- a/src/unknown/process.rs
+++ b/src/unknown/process.rs
@@ -114,4 +114,10 @@ impl ProcessInner {
     pub(crate) fn switch_updated(&mut self) -> bool {
         false
     }
+
+    pub(crate) fn set_nonexistent(&mut self) {}
+
+    pub(crate) fn exists(&self) -> bool {
+        false
+    }
 }
diff --git a/src/windows/process.rs b/src/windows/process.rs
index 428312b3b..83e328ef4 100644
--- a/src/windows/process.rs
+++ b/src/windows/process.rs
@@ -197,6 +197,7 @@ pub(crate) struct ProcessInner {
     read_bytes: u64,
     written_bytes: u64,
     accumulated_cpu_time: u64,
+    exists: bool,
 }
 
 struct CPUsageCalculationValues {
@@ -278,6 +279,7 @@ impl ProcessInner {
             read_bytes: 0,
             written_bytes: 0,
             accumulated_cpu_time: 0,
+            exists: true,
         }
     }
 
@@ -491,6 +493,14 @@ impl ProcessInner {
     pub(crate) fn switch_updated(&mut self) -> bool {
         std::mem::replace(&mut self.updated, false)
     }
+
+    pub(crate) fn set_nonexistent(&mut self) {
+        self.exists = false;
+    }
+
+    pub(crate) fn exists(&self) -> bool {
+        self.exists
+    }
 }
 
 #[inline]


Test patch:
diff --git a/tests/process.rs b/tests/process.rs
index e2e8d6179..8af922bd1 100644
--- a/tests/process.rs
+++ b/tests/process.rs
@@ -977,3 +977,32 @@ fn accumulated_cpu_time() {
         acc_time
     );
 }
+
+#[test]
+fn test_exists() {
+    if !sysinfo::IS_SUPPORTED_SYSTEM || cfg!(feature = "apple-sandbox") {
+        return;
+    }
+
+    let file_name = "target/test_binary4";
+    build_test_binary(file_name);
+    let mut p = std::process::Command::new(format!("./{file_name}"))
+        .arg("1")
+        .spawn()
+        .unwrap();
+    let pid = Pid::from_u32(p.id() as _);
+
+    let mut s = System::new();
+    let process_refresh_kind = ProcessRefreshKind::nothing().with_memory();
+    s.refresh_processes_specifics(ProcessesToUpdate::Some(&[pid]), false, process_refresh_kind);
+    assert!(s.process(pid).unwrap().exists());
+
+    p.kill().expect("Unable to kill process.");
+    // We need this, otherwise the process will still be around as a zombie on linux.
+    let _ = p.wait();
+    // Let's give some time to the system to clean up...
+    std::thread::sleep(std::time::Duration::from_secs(1));
+
+    s.refresh_processes_specifics(ProcessesToUpdate::Some(&[pid]), false, process_refresh_kind);
+    assert!(!s.process(pid).unwrap().exists());
+}