⎇ cba3a9dd6e0a2f84bbf54d9c7c915fb0cb2c3aff
crates/runtime/sandokan-local/src/proc.rs
Historia
Quién tocó qué
crudo
feat(sandokan-local): B1.2 — LocalEngine
1//! Lectura de `/proc/<pid>/` para telemetría. Sin invocar binarios
2//! externos (`ps`, `free`): syscalls + lectura directa de procfs.
3
4/// RSS en bytes desde `/proc/<pid>/status` (línea `VmRSS:`).
5/// Devuelve 0 si el proceso ya no existe o la línea falta.
6pub fn read_mem_bytes(pid: i32) -> u64 {
7 let path = format!("/proc/{pid}/status");
8 let Ok(content) = std::fs::read_to_string(&path) else {
9 return 0;
10 };
11 for line in content.lines() {
12 if let Some(rest) = line.strip_prefix("VmRSS:") {
13 // formato: "VmRSS:\t 1234 kB"
14 let kb: u64 = rest
15 .split_whitespace()
16 .next()
17 .and_then(|s| s.parse().ok())
18 .unwrap_or(0);
19 return kb * 1024;
20 }
21 }
22 0
23}
24
25/// Número de threads desde `/proc/<pid>/status` (línea `Threads:`).
26/// Devuelve 0 si el proceso ya no existe.
27pub fn read_thread_count(pid: i32) -> u32 {
28 let path = format!("/proc/{pid}/status");
29 let Ok(content) = std::fs::read_to_string(&path) else {
30 return 0;
31 };
32 for line in content.lines() {
33 if let Some(rest) = line.strip_prefix("Threads:") {
34 return rest.trim().parse().unwrap_or(0);
35 }
36 }
37 0
38}
39
40/// `true` si `/proc/<pid>` existe (el proceso, vivo o zombie, está presente).
41pub fn proc_exists(pid: i32) -> bool {
42 std::path::Path::new(&format!("/proc/{pid}")).exists()
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48
49 #[test]
50 fn self_has_positive_rss_and_threads() {
51 let me = std::process::id() as i32;
52 assert!(read_mem_bytes(me) > 0, "el propio proceso debe tener RSS");
53 assert!(read_thread_count(me) >= 1);
54 assert!(proc_exists(me));
55 }
56
57 #[test]
58 fn nonexistent_pid_is_zero() {
59 // PID improbable de existir.
60 assert_eq!(read_mem_bytes(2_000_000_000), 0);
61 assert!(!proc_exists(2_000_000_000));
62 }
63}