From 69f439eff387a6ecb52734e400b297a3c85f2285 Mon Sep 17 00:00:00 2001 From: Daniel Lange Date: Tue, 21 Sep 2021 08:35:19 +0200 Subject: New upstream version 3.1.0 --- freebsd/FreeBSDProcessList.c | 332 ++++++++++++++++++++++++------------------- 1 file changed, 182 insertions(+), 150 deletions(-) (limited to 'freebsd/FreeBSDProcessList.c') diff --git a/freebsd/FreeBSDProcessList.c b/freebsd/FreeBSDProcessList.c index 679f640..48c0648 100644 --- a/freebsd/FreeBSDProcessList.c +++ b/freebsd/FreeBSDProcessList.c @@ -5,11 +5,13 @@ Released under the GNU GPLv2, see the COPYING file in the source distribution for its full text. */ -#include "FreeBSDProcessList.h" +#include "config.h" // IWYU pragma: keep + +#include "freebsd/FreeBSDProcessList.h" #include -#include #include +#include #include #include #include @@ -19,7 +21,6 @@ in the source distribution for its full text. #include #include #include -#include #include #include #include @@ -34,11 +35,9 @@ in the source distribution for its full text. #include "ProcessList.h" #include "Settings.h" #include "XUtils.h" +#include "generic/openzfs_sysctl.h" #include "zfs/ZfsArcStats.h" -#include "zfs/openzfs_sysctl.h" - -char jail_errmsg[JAIL_ERRMSGLEN]; static int MIB_hw_physmem[2]; static int MIB_vm_stats_vm_v_page_count[4]; @@ -57,12 +56,12 @@ static int MIB_kern_cp_time[2]; static int MIB_kern_cp_times[2]; static int kernelFScale; -ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) { +ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* DynamicColumns, Hashtable* pidMatchList, uid_t userId) { size_t len; char errbuf[_POSIX2_LINE_MAX]; FreeBSDProcessList* fpl = xCalloc(1, sizeof(FreeBSDProcessList)); ProcessList* pl = (ProcessList*) fpl; - ProcessList_init(pl, Class(FreeBSDProcess), usersTable, pidMatchList, userId); + ProcessList_init(pl, Class(FreeBSDProcess), usersTable, dynamicMeters, DynamicColumns, pidMatchList, userId); // physical memory in system: hw.physmem // physical page size: hw.pagesize @@ -126,13 +125,15 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui sysctl(MIB_kern_cp_times, 2, fpl->cp_times_o, &len, NULL, 0); } - pl->cpuCount = MAXIMUM(cpus, 1); + pl->existingCPUs = MAXIMUM(cpus, 1); + // TODO: support offline CPUs and hot swapping + pl->activeCPUs = pl->existingCPUs; if (cpus == 1 ) { fpl->cpus = xRealloc(fpl->cpus, sizeof(CPUData)); } else { // on smp we need CPUs + 1 to store averages too (as kernel kindly provides that as well) - fpl->cpus = xRealloc(fpl->cpus, (pl->cpuCount + 1) * sizeof(CPUData)); + fpl->cpus = xRealloc(fpl->cpus, (pl->existingCPUs + 1) * sizeof(CPUData)); } @@ -147,16 +148,12 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui CRT_fatalError("kvm_openfiles() failed"); } - fpl->ttys = Hashtable_new(20, true); - return pl; } void ProcessList_delete(ProcessList* this) { const FreeBSDProcessList* fpl = (FreeBSDProcessList*) this; - Hashtable_delete(fpl->ttys); - if (fpl->kd) { kvm_close(fpl->kd); } @@ -171,11 +168,11 @@ void ProcessList_delete(ProcessList* this) { free(this); } -static inline void FreeBSDProcessList_scanCPUTime(ProcessList* pl) { +static inline void FreeBSDProcessList_scanCPU(ProcessList* pl) { const FreeBSDProcessList* fpl = (FreeBSDProcessList*) pl; - int cpus = pl->cpuCount; // actual CPU count - int maxcpu = cpus; // max iteration (in case we have average + smp) + unsigned int cpus = pl->existingCPUs; // actual CPU count + unsigned int maxcpu = cpus; // max iteration (in case we have average + smp) int cp_times_offset; assert(cpus > 0); @@ -202,7 +199,7 @@ static inline void FreeBSDProcessList_scanCPUTime(ProcessList* pl) { sysctl(MIB_kern_cp_times, 2, fpl->cp_times_n, &sizeof_cp_time_array, NULL, 0); } - for (int i = 0; i < maxcpu; i++) { + for (unsigned int i = 0; i < maxcpu; i++) { if (cpus == 1) { // single CPU box cp_time_n = fpl->cp_time_n; @@ -248,8 +245,69 @@ static inline void FreeBSDProcessList_scanCPUTime(ProcessList* pl) { cpuData->systemPercent = cp_time_p[CP_SYS]; cpuData->irqPercent = cp_time_p[CP_INTR]; cpuData->systemAllPercent = cp_time_p[CP_SYS] + cp_time_p[CP_INTR]; - // this one is not really used, but we store it anyway - cpuData->idlePercent = cp_time_p[CP_IDLE]; + // this one is not really used + //cpuData->idlePercent = cp_time_p[CP_IDLE]; + + cpuData->temperature = NAN; + cpuData->frequency = NAN; + + const int coreId = (cpus == 1) ? 0 : ((int)i - 1); + if (coreId < 0) + continue; + + // TODO: test with hyperthreading and multi-cpu systems + if (pl->settings->showCPUTemperature) { + int temperature; + size_t len = sizeof(temperature); + char mibBuffer[32]; + xSnprintf(mibBuffer, sizeof(mibBuffer), "dev.cpu.%d.temperature", coreId); + int r = sysctlbyname(mibBuffer, &temperature, &len, NULL, 0); + if (r == 0) + cpuData->temperature = (double)(temperature - 2732) / 10.0; // convert from deci-Kelvin to Celsius + } + + // TODO: test with hyperthreading and multi-cpu systems + if (pl->settings->showCPUFrequency) { + int frequency; + size_t len = sizeof(frequency); + char mibBuffer[32]; + xSnprintf(mibBuffer, sizeof(mibBuffer), "dev.cpu.%d.freq", coreId); + int r = sysctlbyname(mibBuffer, &frequency, &len, NULL, 0); + if (r == 0) + cpuData->frequency = frequency; // keep in MHz + } + } + + // calculate max temperature and avg frequency for average meter and + // propagate frequency to all cores if only supplied for CPU 0 + if (cpus > 1) { + if (pl->settings->showCPUTemperature) { + double maxTemp = NAN; + for (unsigned int i = 1; i < maxcpu; i++) { + const double coreTemp = fpl->cpus[i].temperature; + if (isnan(coreTemp)) + continue; + + maxTemp = MAXIMUM(maxTemp, coreTemp); + } + + fpl->cpus[0].temperature = maxTemp; + } + + if (pl->settings->showCPUFrequency) { + const double coreZeroFreq = fpl->cpus[1].frequency; + double freqSum = coreZeroFreq; + if (!isnan(coreZeroFreq)) { + for (unsigned int i = 2; i < maxcpu; i++) { + if (isnan(fpl->cpus[i].frequency)) + fpl->cpus[i].frequency = coreZeroFreq; + + freqSum += fpl->cpus[i].frequency; + } + + fpl->cpus[0].frequency = freqSum / (maxcpu - 1); + } + } } } @@ -321,132 +379,96 @@ static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) { pl->usedSwap *= pageSizeKb; } -static void FreeBSDProcessList_scanTTYs(ProcessList* pl) { - FreeBSDProcessList* fpl = (FreeBSDProcessList*) pl; - - // scan /dev/tty* - { - DIR* dirPtr = opendir("/dev"); - if (!dirPtr) - return; - - int dirFd = dirfd(dirPtr); - if (dirFd < 0) - goto err1; - - const struct dirent* entry; - while ((entry = readdir(dirPtr))) { - if (!String_startsWith(entry->d_name, "tty")) - continue; - - struct stat info; - if (Compat_fstatat(dirFd, "/dev", entry->d_name, &info, 0) < 0) - continue; +static void FreeBSDProcessList_updateExe(const struct kinfo_proc* kproc, Process* proc) { + if (Process_isKernelThread(proc)) { + Process_updateExe(proc, NULL); + return; + } - if (!S_ISCHR(info.st_mode)) - continue; + 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; + } - if (!Hashtable_get(fpl->ttys, info.st_rdev)) - Hashtable_put(fpl->ttys, info.st_rdev, xStrdup(entry->d_name)); - } + Process_updateExe(proc, buffer); +} -err1: - closedir(dirPtr); +static void FreeBSDProcessList_updateCwd(const struct kinfo_proc* kproc, Process* proc) { + 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; } - // scan /dev/pts/* - { - DIR* dirPtr = opendir("/dev/pts"); - if (!dirPtr) - return; - - int dirFd = dirfd(dirPtr); - if (dirFd < 0) - goto err2; - - const struct dirent* entry; - while ((entry = readdir(dirPtr))) { - struct stat info; - if (Compat_fstatat(dirFd, "/dev/pts", entry->d_name, &info, 0) < 0) - continue; - - if (!S_ISCHR(info.st_mode)) - continue; - - if (!Hashtable_get(fpl->ttys, info.st_rdev)) { - char* path; - xAsprintf(&path, "pts/%s", entry->d_name); - Hashtable_put(fpl->ttys, info.st_rdev, path); - } - } - -err2: - closedir(dirPtr); + /* Kernel threads return an empty buffer */ + if (buffer[0] == '\0') { + free(proc->procCwd); + proc->procCwd = NULL; + return; } + + free_and_xStrdup(&proc->procCwd, buffer); } -static char* FreeBSDProcessList_readProcessName(kvm_t* kd, const struct kinfo_proc* kproc, int* basenameEnd) { +static void FreeBSDProcessList_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) { - return xStrdup(kproc->ki_comm); + if (!argv || !argv[0]) { + Process_updateCmdline(proc, kproc->ki_comm, 0, strlen(kproc->ki_comm)); + return; } - int len = 0; + + size_t len = 0; for (int i = 0; argv[i]; i++) { len += strlen(argv[i]) + 1; } - char* comm = xMalloc(len); - char* at = comm; - *basenameEnd = 0; + + char* cmdline = xMalloc(len); + char* at = cmdline; + int end = 0; for (int i = 0; argv[i]; i++) { at = stpcpy(at, argv[i]); - if (!*basenameEnd) { - *basenameEnd = at - comm; + if (end == 0) { + end = at - cmdline; } - *at = ' '; - at++; + *at++ = ' '; } at--; *at = '\0'; - return comm; + + Process_updateCmdline(proc, cmdline, 0, end); } static char* FreeBSDProcessList_readJailName(const struct kinfo_proc* kproc) { - char* jname = NULL; - char jnamebuf[MAXHOSTNAMELEN]; + if (kproc->ki_jid == 0) + return xStrdup("-"); - if (kproc->ki_jid != 0) { - struct iovec jiov[6]; + char jnamebuf[MAXHOSTNAMELEN] = {0}; + struct iovec jiov[4]; - memset(jnamebuf, 0, sizeof(jnamebuf)); 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); - *(const void**)&jiov[4].iov_base = "errmsg"; - jiov[4].iov_len = sizeof("errmsg"); - jiov[5].iov_base = jail_errmsg; - jiov[5].iov_len = JAIL_ERRMSGLEN; + *(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 - jail_errmsg[0] = 0; - int jid = jail_get(jiov, 6, 0); - if (jid < 0) { - if (!jail_errmsg[0]) { - xSnprintf(jail_errmsg, JAIL_ERRMSGLEN, "jail_get: %s", strerror(errno)); - } - } else if (jid == kproc->ki_jid) { - jname = xStrdup(jnamebuf); - } - } else { - jname = xStrdup("-"); - } + int jid = jail_get(jiov, 4, 0); + if (jid == kproc->ki_jid) + return xStrdup(jnamebuf); - return jname; + return NULL; } void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { @@ -457,37 +479,27 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { openzfs_sysctl_updateArcStats(&fpl->zfs); FreeBSDProcessList_scanMemoryInfo(super); - FreeBSDProcessList_scanCPUTime(super); + FreeBSDProcessList_scanCPU(super); // in pause mode only gather global data for meters (CPU/memory/...) if (pauseProcessUpdate) { return; } - if (settings->flags & PROCESS_FLAG_FREEBSD_TTY) { - FreeBSDProcessList_scanTTYs(super); - } - int count = 0; - struct kinfo_proc* kprocs = kvm_getprocs(fpl->kd, KERN_PROC_PROC, 0, &count); + const struct kinfo_proc* kprocs = kvm_getprocs(fpl->kd, KERN_PROC_PROC, 0, &count); for (int i = 0; i < count; i++) { - struct kinfo_proc* kproc = &kprocs[i]; + const struct kinfo_proc* kproc = &kprocs[i]; bool preExisting = false; - // TODO: bool isIdleProcess = false; Process* proc = ProcessList_getProcess(super, kproc->ki_pid, &preExisting, FreeBSDProcess_new); FreeBSDProcess* fp = (FreeBSDProcess*) proc; - proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc))); - if (!preExisting) { fp->jid = kproc->ki_jid; proc->pid = kproc->ki_pid; - if ( ! ((kproc->ki_pid == 0) || (kproc->ki_pid == 1) ) && kproc->ki_flag & P_SYSTEM) { - fp->kernel = 1; - } else { - fp->kernel = 0; - } + proc->isKernelThread = kproc->ki_pid != 1 && (kproc->ki_flag & P_SYSTEM); + proc->isUserlandThread = false; proc->ppid = kproc->ki_ppid; proc->tpgid = kproc->ki_tpgid; proc->tgid = kproc->ki_pid; @@ -498,8 +510,24 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { Process_fillStarttimeBuffer(proc); proc->user = UsersTable_getRef(super->usersTable, proc->st_uid); ProcessList_add(super, proc); - proc->comm = FreeBSDProcessList_readProcessName(fpl->kd, kproc, &proc->basenameOffset); + + FreeBSDProcessList_updateExe(kproc, proc); + FreeBSDProcessList_updateProcessName(fpl->kd, kproc, proc); + + if (settings->flags & PROCESS_FLAG_CWD) { + FreeBSDProcessList_updateCwd(kproc, proc); + } + fp->jname = FreeBSDProcessList_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 @@ -515,8 +543,7 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { proc->user = UsersTable_getRef(super->usersTable, proc->st_uid); } if (settings->updateProcessNames) { - free(proc->comm); - proc->comm = FreeBSDProcessList_readProcessName(fpl->kd, kproc, &proc->basenameOffset); + FreeBSDProcessList_updateProcessName(fpl->kd, kproc, proc); } } @@ -529,19 +556,17 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { proc->percent_cpu = 100.0 * ((double)kproc->ki_pctcpu / (double)kernelFScale); proc->percent_mem = 100.0 * proc->m_resident / (double)(super->totalMem); - /* - * TODO - * if (proc->percent_cpu > 0.1) { - * // system idle process should own all CPU time left regardless of CPU count - * if ( strcmp("idle", kproc->ki_comm) == 0 ) { - * isIdleProcess = true; - * } - * } - */ + 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 (strcmp("intr", kproc->ki_comm) == 0 && kproc->ki_flag & P_SYSTEM) { + 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; @@ -562,16 +587,23 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { default: proc->state = '?'; } - if (settings->flags & PROCESS_FLAG_FREEBSD_TTY) { - fp->ttyPath = (kproc->ki_tdev == NODEV) ? nodevStr : Hashtable_get(fpl->ttys, kproc->ki_tdev); - } - if (Process_isKernelThread(proc)) super->kernelThreads++; + proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc))); + super->totalTasks++; if (proc->state == 'R') super->runningTasks++; proc->updated = true; } } + +bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id) { + assert(id < super->existingCPUs); + + // TODO: support offline CPUs and hot swapping + (void) super; (void) id; + + return true; +} -- cgit v1.2.3