ohmu
·
2026-10-15
1#include "top.h"
2
3#include "common/debug.h"
4#include "common/mallocHelper.h"
5
6#include <errno.h>
7#include <string.h>
8#include <sys/types.h>
9#include <sys/param.h> // DEV_BSIZE
10#include <sys/sysctl.h>
11
12const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes showTypes) {
13 int request[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0, (int) sizeof(struct kinfo_proc), 0 };
14 size_t length = 0;
15
16 if (sysctl(request, ARRAY_SIZE(request), nullptr, &length, nullptr, 0) != 0) {
17 FF_DEBUG("sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL}, nullptr) failed: %s", strerror(errno));
18 return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL}, nullptr) failed";
19 }
20
21 FF_AUTO_FREE struct kinfo_proc* processes = (struct kinfo_proc*) malloc(length);
22 request[5] = (int) (length / sizeof(struct kinfo_proc)); // count must be non-zero for data fetch
23 if (sysctl(request, ARRAY_SIZE(request), processes, &length, nullptr, 0) != 0) {
24 FF_DEBUG("sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL}, processes) failed: %s", strerror(errno));
25 return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL}, processes) failed";
26 }
27
28 int count = (int) (length / sizeof(struct kinfo_proc));
29 const uint32_t pageSizeShift = instance.state.platform.sysinfo.pageSizeShift;
30
31 for (int i = 0; i < count; ++i) {
32 const struct kinfo_proc* proc = &processes[i];
33
34 if (!proc->p_uvalid) { // Zombie process; p_u* members are invalid
35 continue;
36 }
37
38 FFTopProcessSnapshot* item = FF_LIST_ADD(FFTopProcessSnapshot, *snapshots);
39 ffStrbufInitS(&item->name, proc->p_comm);
40 item->pid = (uint32_t) proc->p_pid;
41 item->cpuTime = ((uint64_t) proc->p_uutime_sec * 1000 + (uint64_t) proc->p_uutime_usec / 1000) +
42 ((uint64_t) proc->p_ustime_sec * 1000 + (uint64_t) proc->p_ustime_usec / 1000);
43 item->memBytes = (uint64_t) proc->p_vm_rssize << pageSizeShift;
44 item->startTime = (uint64_t) proc->p_ustart_sec * 1000 + (uint64_t) proc->p_ustart_usec / 1000;
45 item->bytesRead = (uint64_t) proc->p_uru_inblock * DEV_BSIZE;
46 item->bytesWritten = (uint64_t) proc->p_uru_oublock * DEV_BSIZE;
47 item->threads = 0;
48 }
49
50 if (showTypes & FF_TOP_TYPE_THREADS) {
51 int threadRequest[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL | KERN_PROC_SHOW_THREADS, 0, (int) sizeof(struct kinfo_proc), 0 };
52 size_t threadLength = 0;
53 if (sysctl(threadRequest, ARRAY_SIZE(threadRequest), nullptr, &threadLength, nullptr, 0) == 0 && threadLength > 0) {
54 FF_AUTO_FREE struct kinfo_proc* threads = (struct kinfo_proc*) malloc(threadLength);
55 threadRequest[5] = (int) (threadLength / sizeof(struct kinfo_proc)); // count must be non-zero for data fetch
56 if (sysctl(threadRequest, ARRAY_SIZE(threadRequest), threads, &threadLength, nullptr, 0) == 0) {
57 int threadCount = (int) (threadLength / sizeof(struct kinfo_proc));
58 for (uint32_t i = 0; i < snapshots->length; ++i) {
59 FFTopProcessSnapshot* item = FF_LIST_GET(FFTopProcessSnapshot, *snapshots, i);
60 for (int j = 0; j < threadCount; ++j) {
61 if (threads[j].p_pid == (pid_t) item->pid && threads[j].p_tid != -1) {
62 ++item->threads;
63 }
64 }
65 }
66 }
67 }
68 }
69
70 return nullptr;
71}