Repository: GuillaumeGomez/sysinfo (rust)

Issue:
[Feature Request] Process session id
A session id is used to group processes within a session.

For mac/bsd/linix it can be obtained from the [getsid](https://docs.rs/libc/0.2.124/i686-unknown-linux-gnu/libc/fn.getsid.html) system call

For windows it can be found in the [SYSTEM_PROCESS_INFORMATION](https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/WindowsProgramming/struct.SYSTEM_PROCESS_INFORMATION.html) struct from NtQuerySystemInformation which is already being called. It can be obtained individually from [ProcessIdToSessionId](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-processidtosessionid) but this may sometimes give access denied.


Pull request description:
Add ProcessExt::session_id
Fixes #783.

Patch:
diff --git a/md_doc/pid.md b/md_doc/pid.md
index d80e1ab..0513153 100644
--- a/md_doc/pid.md
+++ b/md_doc/pid.md
@@ -1,4 +1,4 @@
-Process id
+Process ID.
 
 Can be used as an integer type by simple casting. For example:
 
diff --git a/src/apple/app_store/process.rs b/src/apple/app_store/process.rs
index 7c43697..b5de095 100644
--- a/src/apple/app_store/process.rs
+++ b/src/apple/app_store/process.rs
@@ -81,4 +81,8 @@ impl ProcessExt for Process {
     }
 
     fn wait(&self) {}
+
+    fn session_id(&self) -> Option<Pid> {
+        None
+    }
 }
diff --git a/src/apple/macos/process.rs b/src/apple/macos/process.rs
index fff9c1f..eea205b 100644
--- a/src/apple/macos/process.rs
+++ b/src/apple/macos/process.rs
@@ -198,6 +198,17 @@ impl ProcessExt for Process {
             }
         }
     }
+
+    fn session_id(&self) -> Option<Pid> {
+        unsafe {
+            let session_id = libc::getsid(self.pid.0);
+            if session_id < 0 {
+                None
+            } else {
+                Some(Pid(session_id))
+            }
+        }
+    }
 }
 
 #[allow(deprecated)] // Because of libc::mach_absolute_time.
diff --git a/src/freebsd/process.rs b/src/freebsd/process.rs
index b0dda0f..5c06dfa 100644
--- a/src/freebsd/process.rs
+++ b/src/freebsd/process.rs
@@ -157,6 +157,17 @@ impl ProcessExt for Process {
             }
         }
     }
+
+    fn session_id(&self) -> Option<Pid> {
+        unsafe {
+            let session_id = libc::getsid(self.pid.0);
+            if session_id < 0 {
+                None
+            } else {
+                Some(Pid(session_id))
+            }
+        }
+    }
 }
 
 pub(crate) unsafe fn get_process_data(
diff --git a/src/linux/process.rs b/src/linux/process.rs
index d7d61b5..eeb66ad 100644
--- a/src/linux/process.rs
+++ b/src/linux/process.rs
@@ -233,6 +233,17 @@ impl ProcessExt for Process {
             }
         }
     }
+
+    fn session_id(&self) -> Option<Pid> {
+        unsafe {
+            let session_id = libc::getsid(self.pid.0);
+            if session_id < 0 {
+                None
+            } else {
+                Some(Pid(session_id))
+            }
+        }
+    }
 }
 
 pub(crate) fn compute_cpu_usage(p: &mut Process, total_time: f32, max_value: f32) {
diff --git a/src/traits.rs b/src/traits.rs
index 16e394c..fa24cb4 100644
--- a/src/traits.rs
+++ b/src/traits.rs
@@ -408,7 +408,7 @@ pub trait ProcessExt: Debug {
     /// let mut s = System::new_all();
     ///
     /// if let Some(process) = s.process(Pid::from(1337)) {
-    ///     eprintln!("Group id for process 1337: {:?}", process.group_id());
+    ///     eprintln!("Group ID for process 1337: {:?}", process.group_id());
     /// }
     /// ```
     fn group_id(&self) -> Option<Gid>;
@@ -427,6 +427,21 @@ pub trait ProcessExt: Debug {
     /// }
     /// ```
     fn wait(&self);
+
+    /// Returns the session ID for the current process or `None` if it couldn't be retrieved.
+    ///
+    /// ⚠️ This information is computed every time this method is called.
+    ///
+    /// ```no_run
+    /// use sysinfo::{Pid, ProcessExt, System, SystemExt};
+    ///
+    /// let mut s = System::new_all();
+    ///
+    /// if let Some(process) = s.process(Pid::from(1337)) {
+    ///     eprintln!("Session ID for process 1337: {:?}", process.session_id());
+    /// }
+    /// ```
+    fn session_id(&self) -> Option<Pid>;
 }
 
 /// Contains all the methods of the [`Cpu`][crate::Cpu] struct.
diff --git a/src/unknown/process.rs b/src/unknown/process.rs
index 4a12ec8..61caae0 100644
--- a/src/unknown/process.rs
+++ b/src/unknown/process.rs
@@ -91,4 +91,8 @@ impl ProcessExt for Process {
     }
 
     fn wait(&self) {}
+
+    fn session_id(&self) -> Option<Pid> {
+        None
+    }
 }
diff --git a/src/windows/process.rs b/src/windows/process.rs
index 7561c65..8d42e86 100644
--- a/src/windows/process.rs
+++ b/src/windows/process.rs
@@ -2,7 +2,9 @@
 
 use crate::sys::system::is_proc_running;
 use crate::sys::utils::to_str;
-use crate::{DiskUsage, Gid, Pid, ProcessExt, ProcessRefreshKind, ProcessStatus, Signal, Uid};
+use crate::{
+    DiskUsage, Gid, Pid, PidExt, ProcessExt, ProcessRefreshKind, ProcessStatus, Signal, Uid,
+};
 
 use std::ffi::OsString;
 use std::fmt;
@@ -39,7 +41,7 @@ use winapi::um::handleapi::CloseHandle;
 use winapi::um::heapapi::{GetProcessHeap, HeapAlloc, HeapFree};
 use winapi::um::memoryapi::{ReadProcessMemory, VirtualQueryEx};
 use winapi::um::processthreadsapi::{
-    GetProcessTimes, GetSystemTimes, OpenProcess, OpenProcessToken,
+    GetProcessTimes, GetSystemTimes, OpenProcess, OpenProcessToken, ProcessIdToSessionId,
 };
 use winapi::um::psapi::{
     EnumProcessModulesEx, GetModuleBaseNameW, GetModuleFileNameExW, GetProcessMemoryInfo,
@@ -563,6 +565,17 @@ impl ProcessExt for Process {
             sysinfo_debug!("can't wait on this process so returning");
         }
     }
+
+    fn session_id(&self) -> Option<Pid> {
+        unsafe {
+            let mut out = 0;
+            if ProcessIdToSessionId(self.pid.as_u32(), &mut out) != 0 {
+                return Some(Pid(out as _));
+            }
+            sysinfo_debug!("ProcessIdToSessionId failed, error: {:?}", GetLastError());
+            None
+        }
+    }
 }
 
 #[inline]


Test patch:
diff --git a/tests/process.rs b/tests/process.rs
index 2b88c7b..efaaaa0 100644
--- a/tests/process.rs
+++ b/tests/process.rs
@@ -293,6 +293,17 @@ fn test_process_times() {
     }
 }
 
+// Checks that `session_id` is working.
+#[test]
+fn test_process_session_id() {
+    if !sysinfo::System::IS_SUPPORTED || cfg!(feature = "apple-sandbox") {
+        return;
+    }
+    let mut s = sysinfo::System::new();
+    s.refresh_processes();
+    assert!(s.processes().values().any(|p| p.session_id().is_some()));
+}
+
 // Checks that `refresh_processes` is removing dead processes.
 #[test]
 fn test_refresh_processes() {