nx_os_proc.nx
buildroot/runtime/nx_os_proc.nx
about
nx_os_proc.nx -- OS PROCESS-INTROSPECTION abstraction (the PORTABILITY SEAM). THE ONE place OS-specific
process access lives, so every tool above it (nx_heal, ...) stays OS-AGNOSTIC + portable. Interop by
construction: ONE source compiles to BOTH backends via the @ifdef target guard --
LINUX backend = procfs (/proc/<pid>/{stat,cmdline}, getdents on /proc) [current NAS deploy]
NISHIOS backend = native process table (@ifdef TARGET_NISHI seam) -- superior: a direct kernel
query, NO text-parsing of /proc, NO USER_HZ guesswork. FAILS LOUD until wired,
so a NishiOS build never silently inherits Linux assumptions.
LAW (portability): NEVER scatter raw /proc, /sys, /dev, or hardcoded syscall numbers through the LOGIC
layer -- put OS-specifics behind an nx_os_* seam like this one. The sovereign core (seg_store, tool
logic) already only touches nx_syscalls (ABI-abstracted); this extends the same discipline to OS features.
license_tier: ORIGINAL
dependencies 1 imports · 3 importers
imports: nx_syscalls.nx
imported by: nx_fsops_lib.nxnx_heal_lib.nxnx_leak_check_lib.nx
structs
| none |
consts
| 14 | const OSP_HZ_LINUX: i64 = 100 // Linux USER_HZ: /proc/<pid>/stat starttime ticks/sec |
| 15 | const OSP_PATH_CAP: i64 = 256 |
| 16 | const OSP_RD_CAP: i64 = 4096 |
| 17 | const OSP_STAT_CAP: i64 = 262144 // /proc/stat whole-file read cap (btime scan) |
| 18 | const OSP_DENT_BUF: i64 = 65536 // getdents64 batch buffer (proven sizing) |
| 19 | const OSP_F_PPID: i64 = 2 // /proc/<pid>/stat field after ')': state=1 ppid=2 ... utime=12 stime=13 ... starttime=20 |
| 20 | const OSP_F_START: i64 = 20 |
| 21 | const OSP_F_UTIME: i64 = 12 // user-mode CPU ticks (cumulative) |
| 22 | const OSP_F_STIME: i64 = 13 // kernel-mode CPU ticks (cumulative) |
| 23 | const OSP_ASCII_0: i64 = 48 |
| 24 | const OSP_ASCII_9: i64 = 57 |
| 25 | const OSP_SP: i64 = 32 |
| 26 | const OSP_NL: i64 = 10 |
| 27 | const OSP_RP: i64 = 41 // ')' |
| 28 | const OSP_SLASH: i64 = 47 |
| 29 | const OSP_NUL: i64 = 0 |
| 30 | const OSP_SENTINEL: i64 = 0 - 1 // "not available on this OS backend" |
functions
| 32 | func osp_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (OSP_NUL as u8) { n = n + 1 } return n } called by 1: osp_list_pids |
| 34 | func osp_itoa(v: i64, out: *u8) -> i64 |
| 47 | func osp_num(buf: *u8, n: i64, off: i64, endp: *i64) -> i64 |
| 58 | func osp_basename(s: *u8) -> *u8 called by 1: osp_cmd_argv0 |
| 72 | func osp_bread(path: *u8, buf: *u8, cap: i64) -> i64 called by 4: osp_stat_fieldosp_cmd_argv0osp_selfpidosp_boot_epoch calls 3: sys_openat_rdsys_readsys_close |
| 81 | func osp_ppath(out: *u8, pid: i64, leaf: *u8) -> i64 |
| 93 | func osp_list_pids(pids: *i64, cap: i64) -> i64 called by 2: nh_scanmain calls 8: sys_openat_rdsys_mmapsys_getdents64dirent_reclendirent_nameosp_num+2 |
| 122 | func osp_fd_count(pid: i64) -> i64 |
| 151 | func osp_stat_field(pid: i64, fidx: i64) -> i64 |
| 174 | func osp_ppid(pid: i64) -> i64 { return osp_stat_field(pid, OSP_F_PPID) } |
| 175 | func osp_starttime_ticks(pid: i64) -> i64 { return osp_stat_field(pid, OSP_F_START) } |
| 179 | func osp_cpu_ticks(pid: i64) -> i64 |
| 187 | func osp_cmd_argv0(pid: i64, out: *u8, cap: i64) -> i64 |
| 200 | func osp_hz() -> i64 { return OSP_HZ_LINUX } |
| 203 | func osp_supervisor_log() -> *u8 { return "/tmp/supervisor.log" as *u8 } called by 1: nh_diagnose |
| 204 | func osp_uptime_s() -> i64 { let ts: *i64 = sys_mmap(16) as *i64; sys_clock_gettime_mono(ts); return ts[0] } |
| 205 | func osp_selfpid() -> i64 |
| 213 | func osp_boot_epoch() -> i64 |