Processes: adds total thread count detection

This commit is contained in:
Carter Li
2026-08-28 15:21:52 +08:00
parent 14cf6bfdc1
commit 51b370a105
13 changed files with 202 additions and 54 deletions
+2 -2
View File
@@ -1065,7 +1065,7 @@ elseif(APPLE)
src/detection/packages/packages_apple.c
src/detection/packages/packages_nix.c
src/detection/poweradapter/poweradapter_apple.c
src/detection/processes/processes_bsd.c
src/detection/processes/processes_apple.c
src/detection/sound/sound_apple.c
src/detection/swap/swap_apple.c
src/detection/terminalfont/terminalfont_apple.m
@@ -1240,7 +1240,7 @@ elseif(SunOS)
src/detection/os/os_sunos.c
src/detection/packages/packages_sunos.c
src/detection/poweradapter/poweradapter_nosupport.c
src/detection/processes/processes_linux.c
src/detection/processes/processes_sunos.c
src/detection/gtk_qt/qt.c
src/detection/sound/sound_sunos.c
src/detection/swap/swap_sunos.c
+7 -1
View File
@@ -2,4 +2,10 @@
#include "fastfetch.h"
const char* ffDetectProcesses(uint32_t* result);
typedef struct FFProcessesResult
{
uint32_t processes;
uint32_t threads;
} FFProcessesResult;
const char* ffDetectProcesses(FFProcessesResult* result);
+21
View File
@@ -0,0 +1,21 @@
#include "processes.h"
#include "common/mallocHelper.h"
#import <libproc.h>
const char* ffDetectProcesses(FFProcessesResult* result) {
FF_AUTO_FREE pid_t* pids = malloc(sizeof(pid_t) * 0x1000);
int count = proc_listallpids(pids, 0x1000);
int trdCount = 0;
for (int index = 0; index < count; ++index) {
struct proc_taskinfo taskInfo;
if (proc_pidinfo(pids[index], PROC_PIDTASKINFO, 0, &taskInfo, sizeof(taskInfo)) != sizeof(taskInfo)) {
continue;
}
trdCount += taskInfo.pti_threadnum;
}
result->processes = (uint32_t) count;
result->threads = (uint32_t) trdCount;
return nullptr;
}
+14 -14
View File
@@ -1,23 +1,23 @@
#include "processes.h"
#include <sys/sysctl.h>
#ifdef __FreeBSD__
#include <sys/types.h>
#include <sys/user.h>
#endif
#include <sys/types.h>
#include <sys/user.h>
#ifndef KERN_PROC_PROC
#define KERN_PROC_PROC KERN_PROC_ALL // Apple
#endif
const char* ffDetectProcesses(uint32_t* result) {
int request[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC };
size_t length;
if (sysctl(request, ARRAY_SIZE(request), nullptr, &length, nullptr, 0) != 0) {
const char* ffDetectProcesses(FFProcessesResult* result) {
int procRequest[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC };
size_t procLength;
if (sysctl(procRequest, ARRAY_SIZE(procRequest), nullptr, &procLength, nullptr, 0) != 0) {
return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_PROC}) failed";
}
*result = (uint32_t) (length / sizeof(struct kinfo_proc));
int threadRequest[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
size_t threadLength;
if (sysctl(threadRequest, ARRAY_SIZE(threadRequest), nullptr, &threadLength, nullptr, 0) != 0) {
return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL}) failed";
}
result->processes = (uint32_t) (procLength / sizeof(struct kinfo_proc));
result->threads = (uint32_t) (threadLength / sizeof(struct kinfo_proc));
return nullptr;
}
+15 -4
View File
@@ -3,7 +3,7 @@
#include <hurd.h>
#include <ps.h>
const char* ffDetectProcesses(uint32_t* result) {
const char* ffDetectProcesses(FFProcessesResult* result) {
struct ps_context* context = nullptr;
if (ps_context_create(getproc(), &context) != 0) {
return "ps_context_create(getproc()) failed";
@@ -16,15 +16,26 @@ const char* ffDetectProcesses(uint32_t* result) {
goto done;
}
// No flags are needed; we only count the processes.
if (proc_stat_list_add_all(list, nullptr, nullptr) != 0) {
struct proc_stat **stats = nullptr;
unsigned int numProcs = 0;
if (proc_stat_list_add_all(list, &stats, &numProcs) != 0) {
error = "proc_stat_list_add_all() failed";
goto done;
}
*result = (uint32_t) list->num_procs;
uint32_t nthread = 0;
for (unsigned int i = 0; i < numProcs; i++) {
proc_stat_get_basic_info(stats[i]);
nthread += proc_stat_thread_count(stats[i]);
}
result->processes = (uint32_t) numProcs;
result->threads = nthread;
done:
if (stats) {
proc_stat_list_free_stats(stats, numProcs);
}
if (list) {
proc_stat_list_free(list);
}
+3 -2
View File
@@ -2,13 +2,14 @@
#include <OS.h>
const char* ffDetectProcesses(uint32_t* result) {
const char* ffDetectProcesses(FFProcessesResult* result) {
system_info info;
if (get_system_info(&info) != B_OK) {
return "Error getting system info";
}
*result = info.used_teams;
result->processes = info.used_teams;
result->threads = info.used_threads;
return nullptr;
}
+42 -9
View File
@@ -1,27 +1,60 @@
#include "processes.h"
#include "common/io.h"
#include "common/memrchr.h"
#include "common/strutil.h"
const char* ffDetectProcesses(uint32_t* result) {
const char* ffDetectProcesses(FFProcessesResult* result) {
FF_AUTO_CLOSE_DIR DIR* dir = opendir("/proc");
if (dir == nullptr) {
return "opendir(\"/proc\") failed";
}
uint32_t num = 0;
uint32_t processes = 0;
uint32_t threads = 0;
int procfd = dirfd(dir);
struct dirent* entry;
while ((entry = readdir(dir)) != nullptr) {
if (
#ifdef _DIRENT_HAVE_D_TYPE
(entry->d_type == DT_DIR || entry->d_type == DT_UNKNOWN) &&
#endif
ffCharIsDigit(entry->d_name[0]))
++num;
if ((entry->d_type == DT_DIR || entry->d_type == DT_UNKNOWN) && ffCharIsDigit(entry->d_name[0])) {
++processes;
char statPath[32];
strcpy(ffStrCopy(statPath, entry->d_name, sizeof(statPath)), "/stat");
char statBuffer[256];
ssize_t statLength = ffReadFileDataRelative(procfd, statPath, sizeof(statBuffer) - 1, statBuffer);
if (statLength < 0) {
continue;
}
statBuffer[statLength] = '\0';
const char* cursor = (const char*) memrchr(statBuffer, ')', (size_t) statLength);
if (!cursor) {
continue;
}
++cursor;
for (uint32_t field = 2 /*comm*/; field < 20 /*num_threads*/; ++field) {
while (*cursor != ' ' && __builtin_expect(*cursor != '\0', true)) {
++cursor;
}
++cursor;
if (__builtin_expect(*cursor == '\0', false)) {
break;
}
}
if (__builtin_expect(*cursor == '\0', false)) {
continue;
}
threads += (uint32_t) strtoul(cursor, nullptr, 10);
}
}
*result = num;
result->processes = processes;
result->threads = threads;
return nullptr;
}
+23 -4
View File
@@ -1,15 +1,34 @@
#include "processes.h"
#include "common/mallocHelper.h"
#include <sys/sysctl.h>
const char* ffDetectProcesses(uint32_t* result) {
int request[] = { CTL_KERN, KERN_PROC2, KERN_PROC_ALL, -1, sizeof(struct kinfo_proc2), 0 };
const char* ffDetectProcesses(FFProcessesResult* result) {
int request[] = { CTL_KERN, KERN_PROC2, KERN_PROC_ALL, -1, sizeof(struct kinfo_proc2), INT_MAX };
size_t length = 0;
if (sysctl(request, ARRAY_SIZE(request), nullptr, &length, nullptr, 0) != 0) {
return "sysctl({CTL_KERN, KERN_PROC2, KERN_PROC_ALL}) failed";
return "sysctl({CTL_KERN, KERN_PROC2, KERN_PROC_ALL, nullptr}) failed";
}
*result = (uint32_t) (length / sizeof(struct kinfo_proc2));
FF_AUTO_FREE struct kinfo_proc2* procs = malloc(length);
if (sysctl(request, ARRAY_SIZE(request), procs, &length, nullptr, 0) != 0) {
return "sysctl({CTL_KERN, KERN_PROC2, KERN_PROC_ALL, procs}) failed";
}
uint32_t procCount = (uint32_t) (length / sizeof(struct kinfo_proc2));
result->processes = procCount;
uint32_t threads = 0;
for (uint32_t i = 0; i < procCount; ++i) {
int lwpRequest[] = { CTL_KERN, KERN_LWP, procs[i].p_pid, sizeof(struct kinfo_lwp), 0 };
size_t lwpLength = 0;
if (sysctl(lwpRequest, ARRAY_SIZE(lwpRequest), nullptr, &lwpLength, nullptr, 0) == 0) {
threads += (uint32_t) (lwpLength / sizeof(struct kinfo_lwp));
}
}
result->threads = threads;
return nullptr;
}
@@ -1,5 +1,5 @@
#include "processes.h"
const char* ffDetectProcesses(uint32_t* result) {
const char* ffDetectProcesses([[maybe_unused]] FFProcessesResult* result) {
return "Not supported on this platform";
}
+18 -7
View File
@@ -2,14 +2,25 @@
#include <sys/param.h>
#include <sys/sysctl.h>
#include <kvm.h>
const char* ffDetectProcesses(uint32_t* result) {
kvm_t* kd = kvm_open(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr);
const void* ret = kvm_getprocs(kd, KERN_PROC_ALL, 0, 1, result);
kvm_close(kd);
if (!ret) {
return "kvm_getprocs() failed";
const char* ffDetectProcesses(FFProcessesResult* result) {
int procRequest[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), 0 };
size_t procLength = 0;
if (sysctl(procRequest, ARRAY_SIZE(procRequest), nullptr, &procLength, nullptr, 0) != 0) {
return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL}) failed";
}
result->processes = (uint32_t) (procLength / sizeof(struct kinfo_proc));
int threadRequest[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL | KERN_PROC_SHOW_THREADS, 0, sizeof(struct kinfo_proc), 0 };
size_t threadLength = 0;
if (sysctl(threadRequest, ARRAY_SIZE(threadRequest), nullptr, &threadLength, nullptr, 0) != 0) {
return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL | KERN_PROC_SHOW_THREADS}) failed";
}
result->threads = (uint32_t) (threadLength / sizeof(struct kinfo_proc));
return nullptr;
}
+38
View File
@@ -0,0 +1,38 @@
#include "processes.h"
#include "common/io.h"
#include "common/strutil.h"
#include <procfs.h>
const char* ffDetectProcesses(FFProcessesResult* result) {
FF_AUTO_CLOSE_DIR DIR* dir = opendir("/proc");
if (dir == nullptr) {
return "opendir(\"/proc\") failed";
}
uint32_t processes = 0;
uint32_t threads = 0;
int procfd = dirfd(dir);
struct dirent* entry;
while ((entry = readdir(dir)) != nullptr) {
if (ffCharIsDigit(entry->d_name[0])) {
++processes;
char psinfoPath[32];
strcpy(ffStrCopy(psinfoPath, entry->d_name, sizeof(psinfoPath)), "/psinfo");
psinfo_t info;
if (ffReadFileDataRelative(procfd, psinfoPath, sizeof(info), &info) == (ssize_t) sizeof(info)) {
threads += info.pr_nlwp;
}
}
}
result->processes = processes;
result->threads = threads;
return nullptr;
}
+11 -4
View File
@@ -4,7 +4,7 @@
#include <ntstatus.h>
#include <winternl.h>
const char* ffDetectProcesses(uint32_t* result) {
const char* ffDetectProcesses(FFProcessesResult* result) {
FF_AUTO_FREE SYSTEM_PROCESS_INFORMATION* pstart = nullptr;
// Multiple attempts in case processes change while
@@ -25,10 +25,17 @@ const char* ffDetectProcesses(uint32_t* result) {
}
}
*result = 1; // Init with 1 because we test for ptr->NextEntryOffset
for (SYSTEM_PROCESS_INFORMATION* ptr = pstart; ptr->NextEntryOffset; ptr = (SYSTEM_PROCESS_INFORMATION*) ((uint8_t*) ptr + ptr->NextEntryOffset)) {
++*result;
uint32_t processes = 0;
uint32_t threads = 0;
for (SYSTEM_PROCESS_INFORMATION* ptr = pstart; ; ptr = (SYSTEM_PROCESS_INFORMATION*) ((uint8_t*) ptr + ptr->NextEntryOffset)) {
++processes;
threads += ptr->NumberOfThreads;
if (ptr->NextEntryOffset == 0) {
break;
}
}
result->processes = processes;
result->threads = threads;
return nullptr;
}
+7 -6
View File
@@ -5,8 +5,8 @@
#include "modules/processes/processes.h"
bool ffPrintProcesses(FFProcessesOptions* options) {
uint32_t numProcesses = 0;
const char* error = ffDetectProcesses(&numProcesses);
FFProcessesResult result = {};
const char* error = ffDetectProcesses(&result);
if (error) {
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Processes), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
@@ -16,9 +16,9 @@ bool ffPrintProcesses(FFProcessesOptions* options) {
if (options->moduleArgs.outputFormat.length == 0) {
ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(Processes), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
printf("%u\n", numProcesses);
printf("%u (%u threads)\n", result.processes, result.threads);
} else {
FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(Processes), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) { FF_ARG(numProcesses, "result") }));
FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(Processes), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) { FF_ARG(result.processes, "result") }));
}
return true;
@@ -41,7 +41,7 @@ void ffGenerateProcessesJsonConfig(FFProcessesOptions* options, yyjson_mut_doc*
}
bool ffGenerateProcessesJsonResult([[maybe_unused]] FFProcessesOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
uint32_t result;
FFProcessesResult result = {};
const char* error = ffDetectProcesses(&result);
if (error) {
@@ -49,7 +49,8 @@ bool ffGenerateProcessesJsonResult([[maybe_unused]] FFProcessesOptions* options,
return false;
}
yyjson_mut_obj_add_uint(doc, module, "result", result);
yyjson_mut_obj_add_uint(doc, module, "processes", result.processes);
yyjson_mut_obj_add_uint(doc, module, "threads", result.threads);
return true;
}