ohmu
·
2026-10-15
1#include "top.h"
2
3#include "common/debug.h"
4#include "common/io.h"
5#include "common/strutil.h"
6
7#include <errno.h>
8#include <stdio.h>
9#include <string.h>
10#include <procfs.h>
11#include <sys/param.h> // DEV_BSIZE
12
13const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes showTypes) {
14 FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/proc");
15 if (!dirp) {
16 FF_DEBUG("opendir(\"/proc\") failed: %s", strerror(errno));
17 return "opendir(\"/proc\") failed";
18 }
19
20 int procfd = dirfd(dirp);
21
22 struct dirent* dp;
23 while ((dp = readdir(dirp))) {
24 if (!ffCharIsDigit(dp->d_name[0])) { // Skip "." and ".."
25 continue;
26 }
27
28 FF_AUTO_CLOSE_FD int subfd = openat(procfd, dp->d_name, O_RDONLY | O_DIRECTORY);
29 if (subfd < 0) {
30 continue;
31 }
32
33 pstatus_t status;
34 if (ffReadFileDataRelative(subfd, "status", sizeof(status), &status) != (ssize_t) sizeof(status) ||
35 status.pr_flags & PR_ISSYS) {
36 continue; // The process may have exited, no permission or is a kernel process
37 }
38
39 // The data model of the returned structure depends on the data model of
40 // the calling process, not of the observed process.
41 psinfo_t psinfo;
42 if (ffReadFileDataRelative(subfd, "psinfo", sizeof(psinfo), &psinfo) != (ssize_t) sizeof(psinfo)) {
43 continue;
44 }
45
46 // zombies
47 if (psinfo.pr_lwp.pr_sname == 'Z') {
48 continue;
49 }
50
51 FFTopProcessSnapshot* item = FF_LIST_ADD(FFTopProcessSnapshot, *snapshots);
52
53 ffStrbufInitS(&item->name, psinfo.pr_fname);
54
55 item->pid = (uint32_t) psinfo.pr_pid;
56
57 item->cpuTime = (uint64_t) psinfo.pr_time.tv_sec * 1000 +
58 (uint64_t) psinfo.pr_time.tv_nsec / 1000000;
59
60 item->memBytes = (uint64_t) psinfo.pr_rssize * 1024;
61
62 item->startTime = (uint64_t) psinfo.pr_start.tv_sec * 1000 +
63 (uint64_t) psinfo.pr_start.tv_nsec / 1000000;
64
65 item->bytesRead = 0;
66 item->bytesWritten = 0;
67 item->threads = (uint32_t) psinfo.pr_nlwp;
68 if (showTypes & FF_TOP_TYPE_DISK) {
69 prusage_t usage;
70 if (ffReadFileDataRelative(subfd, "usage", sizeof(usage), &usage) == (ssize_t) sizeof(usage)) {
71 item->bytesRead = (uint64_t) usage.pr_inblk * DEV_BSIZE;
72 item->bytesWritten = (uint64_t) usage.pr_oublk * DEV_BSIZE;
73 }
74 }
75 }
76
77 return nullptr;
78}