ohmu
·
2026-10-15
1#include "top.h"
2#include "common/mallocHelper.h"
3
4#include <sys/types.h>
5#include <sys/resource.h>
6#include <sys/sysctl.h>
7#include <sys/user.h>
8
9const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes showTypes) {
10 int request[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
11 size_t length;
12
13 if (sysctl(request, ARRAY_SIZE(request), nullptr, &length, nullptr, 0) != 0) {
14 return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL, nullptr}) failed";
15 }
16
17 // The process table may change between the two sysctl calls; retry with a larger buffer.
18 length += length / 8 + sizeof(struct kinfo_proc);
19
20 FF_AUTO_FREE struct kinfo_proc* processes = malloc(length);
21 if (sysctl(request, ARRAY_SIZE(request), processes, &length, nullptr, 0) != 0) {
22 return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL, processes}) failed";
23 }
24 uint32_t count = (uint32_t) (length / sizeof(struct kinfo_proc));
25
26 const uint32_t pageSizeShift = instance.state.platform.sysinfo.pageSizeShift;
27
28 for (uint32_t i = 0; i < count; ++i) {
29 const struct kinfo_proc* proc = &processes[i];
30
31 // KERN_PROC_ALL won't return kernel threads
32 if (proc->kp_stat == SZOMB) { // Ignore zombie processes
33 continue;
34 }
35
36 FFTopProcessSnapshot* item = FF_LIST_ADD(FFTopProcessSnapshot, *snapshots);
37
38 ffStrbufInitS(&item->name, proc->kp_comm);
39 item->pid = (uint32_t) proc->kp_pid;
40
41 // kp_ru only accounts for exited lwps; the cpu times of live lwps are
42 // kept in microseconds in kp_lwp.kl_uticks/kl_sticks (see calcru(9)).
43 uint64_t exitedMs = (uint64_t) (proc->kp_ru.ru_utime.tv_sec + proc->kp_ru.ru_stime.tv_sec) * 1000 +
44 (uint64_t) (proc->kp_ru.ru_utime.tv_usec + proc->kp_ru.ru_stime.tv_usec) / 1000;
45 uint64_t liveMs = (proc->kp_lwp.kl_uticks + proc->kp_lwp.kl_sticks) / 1000;
46 item->cpuTime = exitedMs + liveMs;
47
48 item->memBytes = (uint64_t) proc->kp_vm_rssize << pageSizeShift;
49
50 item->startTime = (uint64_t) proc->kp_start.tv_sec * 1000 +
51 (uint64_t) proc->kp_start.tv_usec / 1000;
52
53 item->bytesRead = (uint64_t) (proc->kp_ru.ru_inblock + proc->kp_lwp.kl_ru.ru_inblock) * DEV_BSIZE;
54 item->bytesWritten = (uint64_t) (proc->kp_ru.ru_oublock + proc->kp_lwp.kl_ru.ru_oublock) * DEV_BSIZE;
55 item->threads = (uint32_t) proc->kp_nthreads;
56 }
57
58 return nullptr;
59}