ListProcesses returns all running processes with the columns the TUI renders (PID, PPID, command, user, start time, CPU%, RSS, mem%, command line). It reads /proc directly instead of forking `ps -axo`, computing the same lifetime-average CPU% that ps reports — no subprocess per refresh.
()
| 17 | // reads /proc directly instead of forking `ps -axo`, computing the same |
| 18 | // lifetime-average CPU% that ps reports — no subprocess per refresh. |
| 19 | func ListProcesses() ([]model.Process, error) { |
| 20 | entries, err := os.ReadDir("/proc") |
| 21 | if err != nil { |
| 22 | return nil, fmt.Errorf("read /proc: %w", err) |
| 23 | } |
| 24 | |
| 25 | // Per-list invariants, computed once rather than per process. |
| 26 | ticks := ticksPerSecond() |
| 27 | boot := bootTime() |
| 28 | totalMem := float64(totalMemoryBytes()) |
| 29 | pageSize := float64(os.Getpagesize()) |
| 30 | |
| 31 | processes := make([]model.Process, 0, len(entries)) |
| 32 | for _, entry := range entries { |
| 33 | if !entry.IsDir() { |
| 34 | continue |
| 35 | } |
| 36 | pid, err := strconv.Atoi(entry.Name()) |
| 37 | if err != nil { |
| 38 | continue |
| 39 | } |
| 40 | if p, ok := readProcessListEntry(pid, ticks, boot, totalMem, pageSize); ok { |
| 41 | processes = append(processes, p) |
| 42 | } |
| 43 | } |
| 44 | return processes, nil |
| 45 | } |
| 46 | |
| 47 | // readProcessListEntry reads the TUI list columns for one PID from /proc, |
| 48 | // mirroring the fields the old `ps -axo` invocation produced. Returns ok=false |