ohmu
·
2026-10-15
1#include "top.h"
2#include "common/debug.h"
3#include "common/mallocHelper.h"
4
5#include <sys/types.h>
6#include <sys/param.h>
7#include <sys/sysctl.h>
8#include <errno.h>
9#include <string.h>
10
11const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes showTypes) {
12 int request[] = { CTL_KERN, KERN_PROC2, KERN_PROC_ALL, -1, sizeof(struct kinfo_proc2), INT_MAX };
13 size_t length;
14
15 if (sysctl(request, ARRAY_SIZE(request), nullptr, &length, nullptr, 0) != 0) {
16 FF_DEBUG("sysctl({CTL_KERN, KERN_PROC2, KERN_PROC_ALL, nullptr}) failed: %s", strerror(errno));
17 return "sysctl({CTL_KERN, KERN_PROC2, KERN_PROC_ALL, nullptr}) failed";
18 }
19
20 // The process table may change between the two sysctl calls; retry with a larger buffer.
21 length += length / 8 + sizeof(struct kinfo_proc2);
22
23 FF_AUTO_FREE struct kinfo_proc2* processes = malloc(length);
24 if (sysctl(request, ARRAY_SIZE(request), processes, &length, nullptr, 0) != 0) {
25 FF_DEBUG("sysctl({CTL_KERN, KERN_PROC2, KERN_PROC_ALL, processes}) failed: %s", strerror(errno));
26 return "sysctl({CTL_KERN, KERN_PROC2, KERN_PROC_ALL, processes}) failed";
27 }
28 uint32_t count = (uint32_t) (length / sizeof(struct kinfo_proc2));
29
30 const uint32_t pageSizeShift = instance.state.platform.sysinfo.pageSizeShift;
31
32 for (uint32_t i = 0; i < count; ++i) {
33 const struct kinfo_proc2* proc = &processes[i];
34
35 if ((proc->p_flag & P_SYSTEM) || !proc->p_uvalid) { // Kernel process or zombie
36 continue;
37 }
38
39 FFTopProcessSnapshot* item = FF_LIST_ADD(FFTopProcessSnapshot, *snapshots);
40
41 ffStrbufInitS(&item->name, proc->p_comm);
42 item->pid = (uint32_t) proc->p_pid;
43
44 uint64_t userMs = (uint64_t) proc->p_uutime_sec * 1000 +
45 (uint64_t) proc->p_uutime_usec / 1000;
46 uint64_t sysMs = (uint64_t) proc->p_ustime_sec * 1000 +
47 (uint64_t) proc->p_ustime_usec / 1000;
48 item->cpuTime = userMs + sysMs;
49
50 item->memBytes = (uint64_t) proc->p_vm_rssize << pageSizeShift;
51
52 item->startTime = (uint64_t) proc->p_ustart_sec * 1000 +
53 (uint64_t) proc->p_ustart_usec / 1000;
54
55 item->bytesRead = (uint64_t) proc->p_uru_inblock * DEV_BSIZE;
56 item->bytesWritten = (uint64_t) proc->p_uru_oublock * DEV_BSIZE;
57 item->threads = 0;
58 if (showTypes & FF_TOP_TYPE_THREADS) {
59 int lwpRequest[] = { CTL_KERN, KERN_LWP, proc->p_pid, sizeof(struct kinfo_lwp), 0 };
60 size_t lwpLength = 0;
61 if (sysctl(lwpRequest, ARRAY_SIZE(lwpRequest), nullptr, &lwpLength, nullptr, 0) == 0) {
62 item->threads = (uint32_t) (lwpLength / sizeof(struct kinfo_lwp));
63 }
64 }
65 }
66
67 return NULL;
68}