From 10eea2ab1bae2a8ec159d81c0446fd8061b33e2b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 21:58:07 +0200 Subject: Adding upstream version 3.3.0. Signed-off-by: Daniel Baumann --- freebsd/FreeBSDProcessTable.c | 288 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 freebsd/FreeBSDProcessTable.c (limited to 'freebsd/FreeBSDProcessTable.c') diff --git a/freebsd/FreeBSDProcessTable.c b/freebsd/FreeBSDProcessTable.c new file mode 100644 index 0000000..9e18b8a --- /dev/null +++ b/freebsd/FreeBSDProcessTable.c @@ -0,0 +1,288 @@ +/* +htop - FreeBSDProcessTable.c +(C) 2014 Hisham H. Muhammad +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include "config.h" // IWYU pragma: keep + +#include "freebsd/FreeBSDProcessTable.h" + +#include +#include +#include +#include +#include +#include +#include +#include // needs to be included before for MAXPATHLEN +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CRT.h" +#include "Compat.h" +#include "Macros.h" +#include "Object.h" +#include "Process.h" +#include "ProcessTable.h" +#include "Scheduling.h" +#include "Settings.h" +#include "XUtils.h" + +#include "freebsd/FreeBSDMachine.h" +#include "freebsd/FreeBSDProcess.h" + + +ProcessTable* ProcessTable_new(Machine* host, Hashtable* pidMatchList) { + FreeBSDProcessTable* this = xCalloc(1, sizeof(FreeBSDProcessTable)); + Object_setClass(this, Class(ProcessTable)); + + ProcessTable* super = &this->super; + ProcessTable_init(super, Class(FreeBSDProcess), host, pidMatchList); + + return super; +} + +void ProcessTable_delete(Object* cast) { + FreeBSDProcessTable* this = (FreeBSDProcessTable*) cast; + ProcessTable_done(&this->super); + free(this); +} + +static void FreeBSDProcessTable_updateExe(const struct kinfo_proc* kproc, Process* proc) { + if (Process_isKernelThread(proc)) { + Process_updateExe(proc, NULL); + return; + } + + const int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, kproc->ki_pid }; + char buffer[2048]; + size_t size = sizeof(buffer); + if (sysctl(mib, 4, buffer, &size, NULL, 0) != 0) { + Process_updateExe(proc, NULL); + return; + } + + Process_updateExe(proc, buffer); +} + +static void FreeBSDProcessTable_updateCwd(const struct kinfo_proc* kproc, Process* proc) { +#ifdef KERN_PROC_CWD + const int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_CWD, kproc->ki_pid }; + char buffer[2048]; + size_t size = sizeof(buffer); + if (sysctl(mib, 4, buffer, &size, NULL, 0) != 0) { + free(proc->procCwd); + proc->procCwd = NULL; + return; + } + + /* Kernel threads return an empty buffer */ + if (buffer[0] == '\0') { + free(proc->procCwd); + proc->procCwd = NULL; + return; + } + + free_and_xStrdup(&proc->procCwd, buffer); +#else + proc->procCwd = NULL; +#endif +} + +static void FreeBSDProcessTable_updateProcessName(kvm_t* kd, const struct kinfo_proc* kproc, Process* proc) { + Process_updateComm(proc, kproc->ki_comm); + + char** argv = kvm_getargv(kd, kproc, 0); + if (!argv || !argv[0]) { + Process_updateCmdline(proc, kproc->ki_comm, 0, strlen(kproc->ki_comm)); + return; + } + + size_t len = 0; + for (int i = 0; argv[i]; i++) { + len += strlen(argv[i]) + 1; + } + + char* cmdline = xMalloc(len); + char* at = cmdline; + int end = 0; + for (int i = 0; argv[i]; i++) { + at = stpcpy(at, argv[i]); + if (end == 0) { + end = at - cmdline; + } + *at++ = ' '; + } + at--; + *at = '\0'; + + Process_updateCmdline(proc, cmdline, 0, end); + + free(cmdline); +} + +static char* FreeBSDProcessTable_readJailName(const struct kinfo_proc* kproc) { + if (kproc->ki_jid == 0) + return xStrdup("-"); + + char jnamebuf[MAXHOSTNAMELEN] = {0}; + struct iovec jiov[4]; + +IGNORE_WCASTQUAL_BEGIN + *(const void**)&jiov[0].iov_base = "jid"; + jiov[0].iov_len = sizeof("jid"); + jiov[1].iov_base = (void*) &kproc->ki_jid; + jiov[1].iov_len = sizeof(kproc->ki_jid); + *(const void**)&jiov[2].iov_base = "name"; + jiov[2].iov_len = sizeof("name"); + jiov[3].iov_base = jnamebuf; + jiov[3].iov_len = sizeof(jnamebuf); +IGNORE_WCASTQUAL_END + + int jid = jail_get(jiov, 4, 0); + if (jid == kproc->ki_jid) + return xStrdup(jnamebuf); + + return NULL; +} + +void ProcessTable_goThroughEntries(ProcessTable* super) { + const Machine* host = super->super.host; + const FreeBSDMachine* fhost = (const FreeBSDMachine*) host; + const Settings* settings = host->settings; + bool hideKernelThreads = settings->hideKernelThreads; + bool hideUserlandThreads = settings->hideUserlandThreads; + + int count = 0; + const struct kinfo_proc* kprocs = kvm_getprocs(fhost->kd, KERN_PROC_PROC, 0, &count); + + for (int i = 0; i < count; i++) { + const struct kinfo_proc* kproc = &kprocs[i]; + bool preExisting = false; + Process* proc = ProcessTable_getProcess(super, kproc->ki_pid, &preExisting, FreeBSDProcess_new); + FreeBSDProcess* fp = (FreeBSDProcess*) proc; + + if (!preExisting) { + fp->jid = kproc->ki_jid; + Process_setPid(proc, kproc->ki_pid); + Process_setThreadGroup(proc, kproc->ki_pid); + Process_setParent(proc, kproc->ki_ppid); + proc->isKernelThread = kproc->ki_pid != 1 && (kproc->ki_flag & P_SYSTEM); + proc->isUserlandThread = false; + proc->tpgid = kproc->ki_tpgid; + proc->session = kproc->ki_sid; + proc->pgrp = kproc->ki_pgid; + proc->st_uid = kproc->ki_uid; + proc->starttime_ctime = kproc->ki_start.tv_sec; + if (proc->starttime_ctime < 0) { + proc->starttime_ctime = host->realtimeMs / 1000; + } + Process_fillStarttimeBuffer(proc); + proc->user = UsersTable_getRef(host->usersTable, proc->st_uid); + ProcessTable_add(super, proc); + + FreeBSDProcessTable_updateExe(kproc, proc); + FreeBSDProcessTable_updateProcessName(fhost->kd, kproc, proc); + + if (settings->ss->flags & PROCESS_FLAG_CWD) { + FreeBSDProcessTable_updateCwd(kproc, proc); + } + + fp->jname = FreeBSDProcessTable_readJailName(kproc); + + proc->tty_nr = kproc->ki_tdev; + const char* name = (kproc->ki_tdev != NODEV) ? devname(kproc->ki_tdev, S_IFCHR) : NULL; + if (!name) { + free(proc->tty_name); + proc->tty_name = NULL; + } else { + free_and_xStrdup(&proc->tty_name, name); + } + } else { + if (fp->jid != kproc->ki_jid) { + // process can enter jail anytime + fp->jid = kproc->ki_jid; + free(fp->jname); + fp->jname = FreeBSDProcessTable_readJailName(kproc); + } + // if there are reapers in the system, process can get reparented anytime + Process_setParent(proc, kproc->ki_ppid); + if (proc->st_uid != kproc->ki_uid) { + // some processes change users (eg. to lower privs) + proc->st_uid = kproc->ki_uid; + proc->user = UsersTable_getRef(host->usersTable, proc->st_uid); + } + if (settings->updateProcessNames) { + FreeBSDProcessTable_updateProcessName(fhost->kd, kproc, proc); + } + } + + free_and_xStrdup(&fp->emul, kproc->ki_emul); + + // from FreeBSD source /src/usr.bin/top/machine.c + proc->m_virt = kproc->ki_size / ONE_K; + proc->m_resident = kproc->ki_rssize * fhost->pageSizeKb; + proc->nlwp = kproc->ki_numthreads; + proc->time = (kproc->ki_runtime + 5000) / 10000; + + proc->percent_cpu = 100.0 * ((double)kproc->ki_pctcpu / (double)fhost->kernelFScale); + proc->percent_mem = 100.0 * proc->m_resident / (double)(host->totalMem); + Process_updateCPUFieldWidths(proc->percent_cpu); + + if (kproc->ki_stat == SRUN && kproc->ki_oncpu != NOCPU) { + proc->processor = kproc->ki_oncpu; + } else { + proc->processor = kproc->ki_lastcpu; + } + + proc->majflt = kproc->ki_cow; + + proc->priority = kproc->ki_pri.pri_level - PZERO; + + if (String_eq("intr", kproc->ki_comm) && (kproc->ki_flag & P_SYSTEM)) { + proc->nice = 0; //@etosan: intr kernel process (not thread) has weird nice value + } else if (kproc->ki_pri.pri_class == PRI_TIMESHARE) { + proc->nice = kproc->ki_nice - NZERO; + } else if (PRI_IS_REALTIME(kproc->ki_pri.pri_class)) { + proc->nice = PRIO_MIN - 1 - (PRI_MAX_REALTIME - kproc->ki_pri.pri_level); + } else { + proc->nice = PRIO_MAX + 1 + kproc->ki_pri.pri_level - PRI_MIN_IDLE; + } + + /* Taken from: https://github.com/freebsd/freebsd-src/blob/1ad2d87778970582854082bcedd2df0394fd4933/sys/sys/proc.h#L851 */ + switch (kproc->ki_stat) { + case SIDL: proc->state = IDLE; break; + case SRUN: proc->state = RUNNING; break; + case SSLEEP: proc->state = SLEEPING; break; + case SSTOP: proc->state = STOPPED; break; + case SZOMB: proc->state = ZOMBIE; break; + case SWAIT: proc->state = WAITING; break; + case SLOCK: proc->state = BLOCKED; break; + default: proc->state = UNKNOWN; + } + + if (Process_isKernelThread(proc)) + super->kernelThreads++; + +#ifdef SCHEDULER_SUPPORT + if (settings->ss->flags & PROCESS_FLAG_SCHEDPOL) + Scheduling_readProcessPolicy(proc); +#endif + + proc->super.show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc))); + + super->totalTasks++; + if (proc->state == RUNNING) + super->runningTasks++; + proc->super.updated = true; + } +} -- cgit v1.2.3