diff options
Diffstat (limited to 'solaris/SolarisProcessTable.c')
-rw-r--r-- | solaris/SolarisProcessTable.c | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/solaris/SolarisProcessTable.c b/solaris/SolarisProcessTable.c new file mode 100644 index 0000000..549c753 --- /dev/null +++ b/solaris/SolarisProcessTable.c @@ -0,0 +1,268 @@ +/* +htop - SolarisProcessTable.c +(C) 2014 Hisham H. Muhammad +(C) 2017,2018 Guy M. Broome +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include "config.h" // IWYU pragma: keep + +#include "solaris/SolarisProcessTable.h" + +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/user.h> +#include <limits.h> +#include <string.h> +#include <procfs.h> +#include <errno.h> +#include <pwd.h> +#include <math.h> +#include <time.h> + +#include "CRT.h" +#include "solaris/Platform.h" +#include "solaris/SolarisProcess.h" + + +#define GZONE "global " +#define UZONE "unknown " + +static char* SolarisProcessTable_readZoneName(kstat_ctl_t* kd, SolarisProcess* sproc) { + char* zname; + + if ( sproc->zoneid == 0 ) { + zname = xStrdup(GZONE); + } else if ( kd == NULL ) { + zname = xStrdup(UZONE); + } else { + kstat_t* ks = kstat_lookup_wrapper( kd, "zones", sproc->zoneid, NULL ); + zname = xStrdup(ks == NULL ? UZONE : ks->ks_name); + } + + return zname; +} + +ProcessTable* ProcessTable_new(Machine* host, Hashtable* pidMatchList) { + SolarisProcessTable* this = xCalloc(1, sizeof(SolarisProcessTable)); + Object_setClass(this, Class(ProcessTable)); + + ProcessTable* super = &this->super; + ProcessTable_init(super, Class(SolarisProcess), host, pidMatchList); + + return super; +} + +void ProcessTable_delete(Object* cast) { + SolarisProcessTable* this = (SolarisProcessTable*) cast; + ProcessTable_done(&this->super); + free(this); +} + +static void SolarisProcessTable_updateExe(pid_t pid, Process* proc) { + char path[32]; + xSnprintf(path, sizeof(path), "/proc/%d/path/a.out", pid); + + char target[PATH_MAX]; + ssize_t ret = readlink(path, target, sizeof(target) - 1); + if (ret <= 0) + return; + + target[ret] = '\0'; + Process_updateExe(proc, target); +} + +static void SolarisProcessTable_updateCwd(pid_t pid, Process* proc) { + char path[32]; + xSnprintf(path, sizeof(path), "/proc/%d/cwd", pid); + + char target[PATH_MAX]; + ssize_t ret = readlink(path, target, sizeof(target) - 1); + if (ret <= 0) + return; + + target[ret] = '\0'; + free_and_xStrdup(&proc->procCwd, target); +} + +/* Taken from: https://docs.oracle.com/cd/E19253-01/817-6223/6mlkidlom/index.html#tbl-sched-state */ +static inline ProcessState SolarisProcessTable_getProcessState(char state) { + switch (state) { + case 'S': return SLEEPING; + case 'R': return RUNNABLE; + case 'O': return RUNNING; + case 'Z': return ZOMBIE; + case 'T': return STOPPED; + case 'I': return IDLE; + default: return UNKNOWN; + } +} + +/* NOTE: the following is a callback function of type proc_walk_f + * and MUST conform to the appropriate definition in order + * to work. See libproc(3LIB) on a Solaris or Illumos + * system for more info. + */ + +static int SolarisProcessTable_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo, void* listptr) { + bool preExisting; + pid_t getpid; + + // Setup process list + ProcessTable* pt = (ProcessTable*) listptr; + SolarisProcessTable* spt = (SolarisProcessTable*) listptr; + Machine* host = pt->host; + + id_t lwpid_real = _lwpsinfo->pr_lwpid; + if (lwpid_real > 1023) { + return 0; + } + + pid_t lwpid = (_psinfo->pr_pid * 1024) + lwpid_real; + bool onMasterLWP = (_lwpsinfo->pr_lwpid == _psinfo->pr_lwp.pr_lwpid); + if (onMasterLWP) { + getpid = _psinfo->pr_pid * 1024; + } else { + getpid = lwpid; + } + + Process* proc = ProcessTable_getProcess(pt, getpid, &preExisting, SolarisProcess_new); + SolarisProcess* sproc = (SolarisProcess*) proc; + const Settings* settings = host->settings; + + // Common code pass 1 + proc->show = false; + sproc->taskid = _psinfo->pr_taskid; + sproc->projid = _psinfo->pr_projid; + sproc->poolid = _psinfo->pr_poolid; + sproc->contid = _psinfo->pr_contract; + proc->priority = _lwpsinfo->pr_pri; + proc->nice = _lwpsinfo->pr_nice - NZERO; + proc->processor = _lwpsinfo->pr_onpro; + proc->state = SolarisProcessTable_getProcessState(_lwpsinfo->pr_sname); + // NOTE: This 'percentage' is a 16-bit BINARY FRACTIONS where 1.0 = 0x8000 + // Source: https://docs.oracle.com/cd/E19253-01/816-5174/proc-4/index.html + // (accessed on 18 November 2017) + proc->percent_mem = ((uint16_t)_psinfo->pr_pctmem / (double)32768) * (double)100.0; + proc->pgrp = _psinfo->pr_pgid; + proc->nlwp = _psinfo->pr_nlwp; + proc->session = _psinfo->pr_sid; + + proc->tty_nr = _psinfo->pr_ttydev; + const char* name = (_psinfo->pr_ttydev != PRNODEV) ? ttyname(_psinfo->pr_ttydev) : NULL; + if (!name) { + free(proc->tty_name); + proc->tty_name = NULL; + } else { + free_and_xStrdup(&proc->tty_name, name); + } + + proc->m_resident = _psinfo->pr_rssize; // KB + proc->m_virt = _psinfo->pr_size; // KB + + if (proc->st_uid != _psinfo->pr_euid) { + proc->st_uid = _psinfo->pr_euid; + proc->user = UsersTable_getRef(host->usersTable, proc->st_uid); + } + + if (!preExisting) { + sproc->realpid = _psinfo->pr_pid; + sproc->lwpid = lwpid_real; + sproc->zoneid = _psinfo->pr_zoneid; + sproc->zname = SolarisProcessTable_readZoneName(spt->kd, sproc); + SolarisProcessTable_updateExe(_psinfo->pr_pid, proc); + + Process_updateComm(proc, _psinfo->pr_fname); + Process_updateCmdline(proc, _psinfo->pr_psargs, 0, 0); + + if (settings->ss->flags & PROCESS_FLAG_CWD) { + SolarisProcessTable_updateCwd(_psinfo->pr_pid, proc); + } + } + + // End common code pass 1 + + if (onMasterLWP) { // Are we on the representative LWP? + Process_setParent(proc, (_psinfo->pr_ppid * 1024)); + Process_setThreadGroup(proc, (_psinfo->pr_ppid * 1024)); + sproc->realppid = _psinfo->pr_ppid; + sproc->realtgid = _psinfo->pr_ppid; + + // See note above (in common section) about this BINARY FRACTION + proc->percent_cpu = ((uint16_t)_psinfo->pr_pctcpu / (double)32768) * (double)100.0; + Process_updateCPUFieldWidths(proc->percent_cpu); + + proc->time = _psinfo->pr_time.tv_sec * 100 + _psinfo->pr_time.tv_nsec / 10000000; + if (!preExisting) { // Tasks done only for NEW processes + proc->isUserlandThread = false; + proc->starttime_ctime = _psinfo->pr_start.tv_sec; + } + + // Update proc and thread counts based on settings + if (proc->isKernelThread && !settings->hideKernelThreads) { + pt->kernelThreads += proc->nlwp; + pt->totalTasks += proc->nlwp + 1; + if (proc->state == RUNNING) { + pt->runningTasks++; + } + } else if (!proc->isKernelThread) { + if (proc->state == RUNNING) { + pt->runningTasks++; + } + if (settings->hideUserlandThreads) { + pt->totalTasks++; + } else { + pt->userlandThreads += proc->nlwp; + pt->totalTasks += proc->nlwp + 1; + } + } + proc->show = !(settings->hideKernelThreads && proc->isKernelThread); + } else { // We are not in the master LWP, so jump to the LWP handling code + proc->percent_cpu = ((uint16_t)_lwpsinfo->pr_pctcpu / (double)32768) * (double)100.0; + Process_updateCPUFieldWidths(proc->percent_cpu); + + proc->time = _lwpsinfo->pr_time.tv_sec * 100 + _lwpsinfo->pr_time.tv_nsec / 10000000; + if (!preExisting) { // Tasks done only for NEW LWPs + proc->isUserlandThread = true; + Process_setParent(proc, _psinfo->pr_pid * 1024); + Process_setThreadGroup(proc, _psinfo->pr_pid * 1024); + sproc->realppid = _psinfo->pr_pid; + sproc->realtgid = _psinfo->pr_pid; + proc->starttime_ctime = _lwpsinfo->pr_start.tv_sec; + } + + // Top-level process only gets this for the representative LWP + if (proc->isKernelThread && !settings->hideKernelThreads) { + proc->super.show = true; + } + if (!proc->isKernelThread && !settings->hideUserlandThreads) { + proc->super.show = true; + } + } // Top-level LWP or subordinate LWP + + // Common code pass 2 + + if (!preExisting) { + if ((sproc->realppid <= 0) && !(sproc->realpid <= 1)) { + proc->isKernelThread = true; + } else { + proc->isKernelThread = false; + } + + Process_fillStarttimeBuffer(proc); + ProcessTable_add(pt, proc); + } + + proc->super.updated = true; + + // End common code pass 2 + + return 0; +} + +void ProcessTable_goThroughEntries(ProcessTable* super) { + super->kernelThreads = 1; + proc_walk(&SolarisProcessTable_walkproc, super, PR_WALK_LWP); +} |