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 --- solaris/Platform.c | 81 ++++++++------- solaris/Platform.h | 80 ++++++++++++-- solaris/ProcessField.h | 2 + solaris/SolarisProcess.c | 49 ++++----- solaris/SolarisProcess.h | 22 ++-- solaris/SolarisProcessList.c | 243 ++++++++++++++++++++++++++++++------------- solaris/SolarisProcessList.h | 33 +++--- 7 files changed, 344 insertions(+), 166 deletions(-) (limited to 'solaris') diff --git a/solaris/Platform.c b/solaris/Platform.c index 968e013..7439195 100644 --- a/solaris/Platform.c +++ b/solaris/Platform.c @@ -7,11 +7,24 @@ Released under the GNU GPLv2, see the COPYING file in the source distribution for its full text. */ -#include "Platform.h" +#include "solaris/Platform.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "Macros.h" #include "Meter.h" #include "CPUMeter.h" #include "MemoryMeter.h" +#include "MemorySwapMeter.h" #include "SwapMeter.h" #include "TasksMeter.h" #include "LoadAverageMeter.h" @@ -19,25 +32,13 @@ in the source distribution for its full text. #include "DateMeter.h" #include "DateTimeMeter.h" #include "HostnameMeter.h" +#include "SysArchMeter.h" #include "UptimeMeter.h" #include "zfs/ZfsArcMeter.h" #include "zfs/ZfsCompressedArcMeter.h" #include "SolarisProcess.h" #include "SolarisProcessList.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -double plat_loadavg[3] = {0}; const SignalItem Platform_signals[] = { { .name = " 0 Cancel", .number = 0 }, @@ -97,9 +98,11 @@ const MeterClass* const Platform_meterTypes[] = { &LoadMeter_class, &MemoryMeter_class, &SwapMeter_class, + &MemorySwapMeter_class, &TasksMeter_class, &BatteryMeter_class, &HostnameMeter_class, + &SysArchMeter_class, &UptimeMeter_class, &AllCPUsMeter_class, &AllCPUs2Meter_class, @@ -138,7 +141,7 @@ int Platform_getUptime() { struct utmpx* ent; while (( ent = getutxent() )) { - if ( !strcmp("system boot", ent->ut_line )) { + if ( String_eq("system boot", ent->ut_line )) { boot_time = ent->ut_tv.tv_sec; } } @@ -149,7 +152,13 @@ int Platform_getUptime() { } void Platform_getLoadAverage(double* one, double* five, double* fifteen) { - getloadavg( plat_loadavg, 3 ); + double plat_loadavg[3]; + if (getloadavg( plat_loadavg, 3 ) < 0) { + *one = NAN; + *five = NAN; + *fifteen = NAN; + return; + } *one = plat_loadavg[LOADAVG_1MIN]; *five = plat_loadavg[LOADAVG_5MIN]; *fifteen = plat_loadavg[LOADAVG_15MIN]; @@ -160,7 +169,7 @@ int Platform_getMaxPid() { kstat_ctl_t* kc = kstat_open(); if (kc != NULL) { - kstat_t* kshandle = kstat_lookup(kc, "unix", 0, "var"); + kstat_t* kshandle = kstat_lookup_wrapper(kc, "unix", 0, "var"); if (kshandle != NULL) { kstat_read(kc, kshandle, NULL); @@ -175,9 +184,9 @@ int Platform_getMaxPid() { return vproc; } -double Platform_setCPUValues(Meter* this, int cpu) { +double Platform_setCPUValues(Meter* this, unsigned int cpu) { const SolarisProcessList* spl = (const SolarisProcessList*) this->pl; - int cpus = this->pl->cpuCount; + unsigned int cpus = this->pl->existingCPUs; const CPUData* cpuData = NULL; if (cpus == 1) { @@ -187,6 +196,11 @@ double Platform_setCPUValues(Meter* this, int cpu) { cpuData = &(spl->cpus[cpu]); } + if (!cpuData->online) { + this->curItems = 0; + return NAN; + } + double percent; double* v = this->values; @@ -216,13 +230,16 @@ void Platform_setMemoryValues(Meter* this) { this->total = pl->totalMem; this->values[0] = pl->usedMem; this->values[1] = pl->buffersMem; - this->values[2] = pl->cachedMem; + // this->values[2] = "shared memory, like tmpfs and shm" + this->values[3] = pl->cachedMem; + // this->values[4] = "available memory" } void Platform_setSwapValues(Meter* this) { const ProcessList* pl = this->pl; this->total = pl->totalSwap; this->values[0] = pl->usedSwap; + this->values[1] = NAN; } void Platform_setZfsArcValues(Meter* this) { @@ -249,7 +266,7 @@ static int Platform_buildenv(void* accum, struct ps_prochandle* Phandle, uintptr return 1; } strlcpy( accump->env + accump->size, str, (accump->capacity - accump->size)); - strncpy( accump->env + accump->size + thissz + 1, "\n", 1); + strncpy( accump->env + accump->size + thissz + 1, "\n", 2); accump->size = accump->size + thissz + 1; return 0; } @@ -261,7 +278,7 @@ char* Platform_getProcessEnv(pid_t pid) { struct ps_prochandle* Phandle; if ((Phandle = Pgrab(realpid, PGRAB_RDONLY, &graberr)) == NULL) { - return "Unable to read process environment."; + return NULL; } envBuilder.capacity = 4096; @@ -277,14 +294,14 @@ char* Platform_getProcessEnv(pid_t pid) { } char* Platform_getInodeFilename(pid_t pid, ino_t inode) { - (void)pid; - (void)inode; - return NULL; + (void)pid; + (void)inode; + return NULL; } FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) { - (void)pid; - return NULL; + (void)pid; + return NULL; } bool Platform_getDiskIO(DiskIOData* data) { @@ -293,15 +310,9 @@ bool Platform_getDiskIO(DiskIOData* data) { return false; } -bool Platform_getNetworkIO(unsigned long int* bytesReceived, - unsigned long int* packetsReceived, - unsigned long int* bytesTransmitted, - unsigned long int* packetsTransmitted) { +bool Platform_getNetworkIO(NetworkIOData* data) { // TODO - *bytesReceived = 0; - *packetsReceived = 0; - *bytesTransmitted = 0; - *packetsTransmitted = 0; + (void)data; return false; } diff --git a/solaris/Platform.h b/solaris/Platform.h index de2b2c9..0a379a1 100644 --- a/solaris/Platform.h +++ b/solaris/Platform.h @@ -9,9 +9,21 @@ Released under the GNU GPLv2, see the COPYING file in the source distribution for its full text. */ +#include "config.h" // IWYU pragma: keep + +#include + +/* On OmniOS /usr/include/sys/regset.h redefines ERR to 13 - \r, breaking the Enter key. + * Since ncruses macros use the ERR macro, we can not use another name. + */ +#undef ERR #include +#undef ERR +#define ERR (-1) + #include #include + #include #include #include @@ -19,8 +31,13 @@ in the source distribution for its full text. #include "Action.h" #include "BatteryMeter.h" #include "DiskIOMeter.h" +#include "Hashtable.h" +#include "NetworkIOMeter.h" #include "ProcessLocksScreen.h" #include "SignalsPanel.h" +#include "generic/gettime.h" +#include "generic/hostname.h" +#include "generic/uname.h" #define kill(pid, signal) kill(pid / 1024, signal) @@ -34,8 +51,6 @@ typedef struct envAccum_ { char* env; } envAccum; -extern double plat_loadavg[3]; - extern const SignalItem Platform_signals[]; extern const unsigned int Platform_numberOfSignals; @@ -56,7 +71,7 @@ void Platform_getLoadAverage(double* one, double* five, double* fifteen); int Platform_getMaxPid(void); -double Platform_setCPUValues(Meter* this, int cpu); +double Platform_setCPUValues(Meter* this, unsigned int cpu); void Platform_setMemoryValues(Meter* this); @@ -74,11 +89,62 @@ FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid); bool Platform_getDiskIO(DiskIOData* data); -bool Platform_getNetworkIO(unsigned long int* bytesReceived, - unsigned long int* packetsReceived, - unsigned long int* bytesTransmitted, - unsigned long int* packetsTransmitted); +bool Platform_getNetworkIO(NetworkIOData* data); void Platform_getBattery(double* percent, ACPresence* isOnAC); +static inline void Platform_getHostname(char* buffer, size_t size) { + Generic_hostname(buffer, size); +} + +static inline void Platform_getRelease(char** string) { + *string = Generic_uname(); +} + +#define PLATFORM_LONG_OPTIONS + +static inline void Platform_longOptionsUsage(ATTR_UNUSED const char* name) { } + +static inline bool Platform_getLongOption(ATTR_UNUSED int opt, ATTR_UNUSED int argc, ATTR_UNUSED char** argv) { + return false; +} + +static inline void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec) { + Generic_gettime_realtime(tv, msec); +} + +static inline void Platform_gettime_monotonic(uint64_t* msec) { + Generic_gettime_monotonic(msec); +} + +static inline void* kstat_data_lookup_wrapper(kstat_t* ksp, const char* name) { +IGNORE_WCASTQUAL_BEGIN + return kstat_data_lookup(ksp, (char*)name); +IGNORE_WCASTQUAL_END +} + +static inline kstat_t* kstat_lookup_wrapper(kstat_ctl_t* kc, const char* ks_module, int ks_instance, const char* ks_name) { +IGNORE_WCASTQUAL_BEGIN + return kstat_lookup(kc, (char*)ks_module, ks_instance, (char*)ks_name); +IGNORE_WCASTQUAL_END +} + +static inline Hashtable* Platform_dynamicMeters(void) { return NULL; } + +static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { } + +static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { } + +static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { } + +static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { } + +static inline Hashtable* Platform_dynamicColumns(void) { return NULL; } + +static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { } + +static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; } + +static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; } + #endif diff --git a/solaris/ProcessField.h b/solaris/ProcessField.h index eb9f157..727c641 100644 --- a/solaris/ProcessField.h +++ b/solaris/ProcessField.h @@ -16,6 +16,8 @@ in the source distribution for its full text. POOLID = 104, \ CONTID = 105, \ LWPID = 106, \ + \ + DUMMY_BUMP_FIELD = CWD, \ // End of list diff --git a/solaris/SolarisProcess.c b/solaris/SolarisProcess.c index d905f7a..57071ab 100644 --- a/solaris/SolarisProcess.c +++ b/solaris/SolarisProcess.c @@ -6,17 +6,19 @@ Released under the GNU GPLv2, see the COPYING file in the source distribution for its full text. */ -#include "Process.h" -#include "ProcessList.h" -#include "SolarisProcess.h" -#include "Platform.h" -#include "CRT.h" +#include "solaris/SolarisProcess.h" #include #include #include #include +#include "Process.h" +#include "ProcessList.h" +#include "CRT.h" + +#include "solaris/Platform.h" + const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = { [0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, }, @@ -26,24 +28,28 @@ const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = { [PPID] = { .name = "PPID", .title = "PPID", .description = "Parent process ID", .flags = 0, .pidColumn = true, }, [PGRP] = { .name = "PGRP", .title = "PGRP", .description = "Process group ID", .flags = 0, .pidColumn = true, }, [SESSION] = { .name = "SESSION", .title = "SID", .description = "Process's session ID", .flags = 0, .pidColumn = true, }, - [TTY_NR] = { .name = "TTY_NR", .title = " TTY ", .description = "Controlling terminal", .flags = 0, }, - [TPGID] = { .name = "TPGID", .title = "TPGID", .description = "Process ID of the fg process group of the controlling terminal", .flags = 0, .pidColumn = true, }, - [MINFLT] = { .name = "MINFLT", .title = " MINFLT ", .description = "Number of minor faults which have not required loading a memory page from disk", .flags = 0, }, - [MAJFLT] = { .name = "MAJFLT", .title = " MAJFLT ", .description = "Number of major faults which have required loading a memory page from disk", .flags = 0, }, + [TTY] = { .name = "TTY", .title = "TTY ", .description = "Controlling terminal", .flags = 0, }, + //[TPGID] = { .name = "TPGID", .title = "TPGID", .description = "Process ID of the fg process group of the controlling terminal", .flags = 0, .pidColumn = true, }, + //[MINFLT] = { .name = "MINFLT", .title = " MINFLT ", .description = "Number of minor faults which have not required loading a memory page from disk", .flags = 0, .defaultSortDesc = true, }, + //[MAJFLT] = { .name = "MAJFLT", .title = " MAJFLT ", .description = "Number of major faults which have required loading a memory page from disk", .flags = 0, .defaultSortDesc = true, }, [PRIORITY] = { .name = "PRIORITY", .title = "PRI ", .description = "Kernel's internal priority for the process", .flags = 0, }, [NICE] = { .name = "NICE", .title = " NI ", .description = "Nice value (the higher the value, the more it lets other processes take priority)", .flags = 0, }, [STARTTIME] = { .name = "STARTTIME", .title = "START ", .description = "Time the process was started", .flags = 0, }, + [ELAPSED] = { .name = "ELAPSED", .title = "ELAPSED ", .description = "Time since the process was started", .flags = 0, }, [PROCESSOR] = { .name = "PROCESSOR", .title = "CPU ", .description = "Id of the CPU the process last executed on", .flags = 0, }, - [M_VIRT] = { .name = "M_VIRT", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, }, - [M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, }, + [M_VIRT] = { .name = "M_VIRT", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, .defaultSortDesc = true, }, + [M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, .defaultSortDesc = true, }, [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, }, - [PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, }, - [PERCENT_NORM_CPU] = { .name = "PERCENT_NORM_CPU", .title = "NCPU%", .description = "Normalized percentage of the CPU time the process used in the last sampling (normalized by cpu count)", .flags = 0, }, - [PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, }, + [PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, .defaultSortDesc = true, }, + [PERCENT_NORM_CPU] = { .name = "PERCENT_NORM_CPU", .title = "NCPU%", .description = "Normalized percentage of the CPU time the process used in the last sampling (normalized by cpu count)", .flags = 0, .defaultSortDesc = true, }, + [PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, .defaultSortDesc = true, }, [USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, }, - [TIME] = { .name = "TIME", .title = " TIME+ ", .description = "Total time the process has spent in user and system time", .flags = 0, }, + [TIME] = { .name = "TIME", .title = " TIME+ ", .description = "Total time the process has spent in user and system time", .flags = 0, .defaultSortDesc = true, }, [NLWP] = { .name = "NLWP", .title = "NLWP ", .description = "Number of threads in the process", .flags = 0, }, [TGID] = { .name = "TGID", .title = "TGID", .description = "Thread group ID (i.e. process ID)", .flags = 0, .pidColumn = true, }, + [PROC_COMM] = { .name = "COMM", .title = "COMM ", .description = "comm string of the process", .flags = 0, }, + [PROC_EXE] = { .name = "EXE", .title = "EXE ", .description = "Basename of exe of the process", .flags = 0, }, + [CWD] = { .name = "CWD", .title = "CWD ", .description = "The current working directory of the process", .flags = PROCESS_FLAG_CWD, }, [ZONEID] = { .name = "ZONEID", .title = "ZONEID", .description = "Zone ID", .flags = 0, .pidColumn = true, }, [ZONE] = { .name = "ZONE", .title = "ZONE ", .description = "Zone name", .flags = 0, }, [PROJID] = { .name = "PROJID", .title = "PRJID", .description = "Project ID", .flags = 0, .pidColumn = true, }, @@ -82,6 +88,7 @@ static void SolarisProcess_writeField(const Process* this, RichString* str, Proc case ZONE: Process_printLeftAlignedField(str, attr, sp->zname ? sp->zname : "global", ZONENAME_MAX/4); return; case PID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->realpid); break; case PPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->realppid); break; + case TGID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->realtgid); break; case LWPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->lwpid); break; default: Process_writeField(this, str, field); @@ -118,18 +125,6 @@ static int SolarisProcess_compareByKey(const Process* v1, const Process* v2, Pro } } -bool Process_isThread(const Process* this) { - const SolarisProcess* fp = (const SolarisProcess*) this; - - if (fp->kernel == 1 ) { - return 1; - } else if (fp->is_lwp) { - return 1; - } else { - return 0; - } -} - const ProcessClass SolarisProcess_class = { .super = { .extends = Class(Process), diff --git a/solaris/SolarisProcess.h b/solaris/SolarisProcess.h index 74cbb86..0fd458d 100644 --- a/solaris/SolarisProcess.h +++ b/solaris/SolarisProcess.h @@ -8,30 +8,36 @@ Released under the GNU GPLv2, see the COPYING file in the source distribution for its full text. */ -#include "Settings.h" +#include "config.h" // IWYU pragma: keep + #include #include + +/* On OmniOS /usr/include/sys/regset.h redefines ERR to 13 - \r, breaking the Enter key. + * Since ncruses macros use the ERR macro, we can not use another name. + */ +#undef ERR #include +#undef ERR +#define ERR (-1) + +#include "Settings.h" + typedef struct SolarisProcess_ { Process super; - int kernel; zoneid_t zoneid; char* zname; taskid_t taskid; projid_t projid; poolid_t poolid; ctid_t contid; - bool is_lwp; pid_t realpid; pid_t realppid; + pid_t realtgid; pid_t lwpid; } SolarisProcess; -#define Process_isKernelThread(_process) (_process->kernel == 1) - -#define Process_isUserlandThread(_process) (_process->pid != _process->tgid) - extern const ProcessClass SolarisProcess_class; extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD]; @@ -40,6 +46,4 @@ Process* SolarisProcess_new(const Settings* settings); void Process_delete(Object* cast); -bool Process_isThread(const Process* this); - #endif diff --git a/solaris/SolarisProcessList.c b/solaris/SolarisProcessList.c index 2ba23ac..45bc5ba 100644 --- a/solaris/SolarisProcessList.c +++ b/solaris/SolarisProcessList.c @@ -6,9 +6,8 @@ Released under the GNU GPLv2, see the COPYING file in the source distribution for its full text. */ -#include "ProcessList.h" -#include "SolarisProcess.h" -#include "SolarisProcessList.h" + +#include "solaris/SolarisProcessList.h" #include #include @@ -23,13 +22,17 @@ in the source distribution for its full text. #include #include "CRT.h" +#include "solaris/Platform.h" +#include "solaris/SolarisProcess.h" + -#define MAXCMDLINE 255 +#define GZONE "global " +#define UZONE "unknown " static int pageSize; static int pageSizeKB; -char* SolarisProcessList_readZoneName(kstat_ctl_t* kd, SolarisProcess* sproc) { +static char* SolarisProcessList_readZoneName(kstat_ctl_t* kd, SolarisProcess* sproc) { char* zname; if ( sproc->zoneid == 0 ) { @@ -37,39 +40,78 @@ char* SolarisProcessList_readZoneName(kstat_ctl_t* kd, SolarisProcess* sproc) { } else if ( kd == NULL ) { zname = xStrdup(UZONE); } else { - kstat_t* ks = kstat_lookup( kd, "zones", sproc->zoneid, NULL ); + kstat_t* ks = kstat_lookup_wrapper( kd, "zones", sproc->zoneid, NULL ); zname = xStrdup(ks == NULL ? UZONE : ks->ks_name); } return zname; } -ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) { +static void SolarisProcessList_updateCPUcount(ProcessList* super) { + SolarisProcessList* spl = (SolarisProcessList*) super; + long int s; + bool change = false; + + s = sysconf(_SC_NPROCESSORS_CONF); + if (s < 1) + CRT_fatalError("Cannot get existing CPU count by sysconf(_SC_NPROCESSORS_CONF)"); + + if (s != super->existingCPUs) { + if (s == 1) { + spl->cpus = xRealloc(spl->cpus, sizeof(CPUData)); + spl->cpus[0].online = true; + } else { + spl->cpus = xReallocArray(spl->cpus, s + 1, sizeof(CPUData)); + spl->cpus[0].online = true; /* average is always "online" */ + for (int i = 1; i < s + 1; i++) { + spl->cpus[i].online = false; + } + } + + change = true; + super->existingCPUs = s; + } + + s = sysconf(_SC_NPROCESSORS_ONLN); + if (s < 1) + CRT_fatalError("Cannot get active CPU count by sysconf(_SC_NPROCESSORS_ONLN)"); + + if (s != super->activeCPUs) { + change = true; + super->activeCPUs = s; + } + + if (change) { + kstat_close(spl->kd); + spl->kd = kstat_open(); + if (!spl->kd) + CRT_fatalError("Cannot open kstat handle"); + } +} + +ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* dynamicColumns, Hashtable* pidMatchList, uid_t userId) { SolarisProcessList* spl = xCalloc(1, sizeof(SolarisProcessList)); ProcessList* pl = (ProcessList*) spl; - ProcessList_init(pl, Class(SolarisProcess), usersTable, pidMatchList, userId); + ProcessList_init(pl, Class(SolarisProcess), usersTable, dynamicMeters, dynamicColumns, pidMatchList, userId); spl->kd = kstat_open(); + if (!spl->kd) + CRT_fatalError("Cannot open kstat handle"); pageSize = sysconf(_SC_PAGESIZE); if (pageSize == -1) CRT_fatalError("Cannot get pagesize by sysconf(_SC_PAGESIZE)"); pageSizeKB = pageSize / 1024; - pl->cpuCount = sysconf(_SC_NPROCESSORS_ONLN); - if (pl->cpuCount == -1) - CRT_fatalError("Cannot get CPU count by sysconf(_SC_NPROCESSORS_ONLN)"); - else if (pl->cpuCount == 1) - spl->cpus = xRealloc(spl->cpus, sizeof(CPUData)); - else - spl->cpus = xRealloc(spl->cpus, (pl->cpuCount + 1) * sizeof(CPUData)); + SolarisProcessList_updateCPUcount(pl); return pl; } static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) { const SolarisProcessList* spl = (SolarisProcessList*) pl; - int cpus = pl->cpuCount; + unsigned int activeCPUs = pl->activeCPUs; + unsigned int existingCPUs = pl->existingCPUs; kstat_t* cpuinfo = NULL; kstat_named_t* idletime = NULL; kstat_named_t* intrtime = NULL; @@ -82,44 +124,45 @@ static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) { double userbuf = 0; int arrskip = 0; - assert(cpus > 0); + assert(existingCPUs > 0); + assert(spl->kd); - if (cpus > 1) { + if (existingCPUs > 1) { // Store values for the stats loop one extra element up in the array // to leave room for the average to be calculated afterwards arrskip++; } // Calculate per-CPU statistics first - for (int i = 0; i < cpus; i++) { - if (spl->kd != NULL) { - if ((cpuinfo = kstat_lookup(spl->kd, "cpu", i, "sys")) != NULL) { - if (kstat_read(spl->kd, cpuinfo, NULL) != -1) { - idletime = kstat_data_lookup(cpuinfo, "cpu_nsec_idle"); - intrtime = kstat_data_lookup(cpuinfo, "cpu_nsec_intr"); - krnltime = kstat_data_lookup(cpuinfo, "cpu_nsec_kernel"); - usertime = kstat_data_lookup(cpuinfo, "cpu_nsec_user"); - } + for (unsigned int i = 0; i < existingCPUs; i++) { + CPUData* cpuData = &(spl->cpus[i + arrskip]); + + if ((cpuinfo = kstat_lookup_wrapper(spl->kd, "cpu", i, "sys")) != NULL) { + cpuData->online = true; + if (kstat_read(spl->kd, cpuinfo, NULL) != -1) { + idletime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_idle"); + intrtime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_intr"); + krnltime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_kernel"); + usertime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_user"); } + } else { + cpuData->online = false; + continue; } assert( (idletime != NULL) && (intrtime != NULL) && (krnltime != NULL) && (usertime != NULL) ); if (pl->settings->showCPUFrequency) { - if (spl->kd != NULL) { - if ((cpuinfo = kstat_lookup(spl->kd, "cpu_info", i, NULL)) != NULL) { - if (kstat_read(spl->kd, cpuinfo, NULL) != -1) { - cpu_freq = kstat_data_lookup(cpuinfo, "current_clock_Hz"); - } + if ((cpuinfo = kstat_lookup_wrapper(spl->kd, "cpu_info", i, NULL)) != NULL) { + if (kstat_read(spl->kd, cpuinfo, NULL) != -1) { + cpu_freq = kstat_data_lookup_wrapper(cpuinfo, "current_clock_Hz"); } } assert( cpu_freq != NULL ); } - CPUData* cpuData = &(spl->cpus[i + arrskip]); - uint64_t totaltime = (idletime->value.ui64 - cpuData->lidle) + (intrtime->value.ui64 - cpuData->lintr) + (krnltime->value.ui64 - cpuData->lkrnl) @@ -140,7 +183,7 @@ static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) { // Add frequency in MHz cpuData->frequency = pl->settings->showCPUFrequency ? (double)cpu_freq->value.ui64 / 1E6 : NAN; // Accumulate the current percentages into buffers for later average calculation - if (cpus > 1) { + if (existingCPUs > 1) { userbuf += cpuData->userPercent; krnlbuf += cpuData->systemPercent; intrbuf += cpuData->irqPercent; @@ -148,14 +191,14 @@ static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) { } } - if (cpus > 1) { + if (existingCPUs > 1) { CPUData* cpuData = &(spl->cpus[0]); - cpuData->userPercent = userbuf / cpus; + cpuData->userPercent = userbuf / activeCPUs; cpuData->nicePercent = (double)0.0; // Not implemented on Solaris - cpuData->systemPercent = krnlbuf / cpus; - cpuData->irqPercent = intrbuf / cpus; + cpuData->systemPercent = krnlbuf / activeCPUs; + cpuData->irqPercent = intrbuf / activeCPUs; cpuData->systemAllPercent = cpuData->systemPercent + cpuData->irqPercent; - cpuData->idlePercent = idlebuf / cpus; + cpuData->idlePercent = idlebuf / activeCPUs; } } @@ -177,15 +220,15 @@ static inline void SolarisProcessList_scanMemoryInfo(ProcessList* pl) { // Part 1 - physical memory if (spl->kd != NULL && meminfo == NULL) { // Look up the kstat chain just once, it never changes - meminfo = kstat_lookup(spl->kd, "unix", 0, "system_pages"); + meminfo = kstat_lookup_wrapper(spl->kd, "unix", 0, "system_pages"); } if (meminfo != NULL) { ksrphyserr = kstat_read(spl->kd, meminfo, NULL); } if (ksrphyserr != -1) { - totalmem_pgs = kstat_data_lookup(meminfo, "physmem"); - freemem_pgs = kstat_data_lookup(meminfo, "freemem"); - pages = kstat_data_lookup(meminfo, "pagestotal"); + totalmem_pgs = kstat_data_lookup_wrapper(meminfo, "physmem"); + freemem_pgs = kstat_data_lookup_wrapper(meminfo, "freemem"); + pages = kstat_data_lookup_wrapper(meminfo, "pagestotal"); pl->totalMem = totalmem_pgs->value.ui64 * pageSizeKB; if (pl->totalMem > freemem_pgs->value.ui64 * pageSizeKB) { @@ -244,39 +287,39 @@ static inline void SolarisProcessList_scanZfsArcstats(ProcessList* pl) { kstat_named_t *cur_kstat = NULL; if (spl->kd != NULL) { - arcstats = kstat_lookup(spl->kd, "zfs", 0, "arcstats"); + arcstats = kstat_lookup_wrapper(spl->kd, "zfs", 0, "arcstats"); } if (arcstats != NULL) { ksrphyserr = kstat_read(spl->kd, arcstats, NULL); } if (ksrphyserr != -1) { - cur_kstat = kstat_data_lookup( arcstats, "size" ); + cur_kstat = kstat_data_lookup_wrapper( arcstats, "size" ); spl->zfs.size = cur_kstat->value.ui64 / 1024; spl->zfs.enabled = spl->zfs.size > 0 ? 1 : 0; - cur_kstat = kstat_data_lookup( arcstats, "c_max" ); + cur_kstat = kstat_data_lookup_wrapper( arcstats, "c_max" ); spl->zfs.max = cur_kstat->value.ui64 / 1024; - cur_kstat = kstat_data_lookup( arcstats, "mfu_size" ); + cur_kstat = kstat_data_lookup_wrapper( arcstats, "mfu_size" ); spl->zfs.MFU = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0; - cur_kstat = kstat_data_lookup( arcstats, "mru_size" ); + cur_kstat = kstat_data_lookup_wrapper( arcstats, "mru_size" ); spl->zfs.MRU = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0; - cur_kstat = kstat_data_lookup( arcstats, "anon_size" ); + cur_kstat = kstat_data_lookup_wrapper( arcstats, "anon_size" ); spl->zfs.anon = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0; - cur_kstat = kstat_data_lookup( arcstats, "hdr_size" ); + cur_kstat = kstat_data_lookup_wrapper( arcstats, "hdr_size" ); spl->zfs.header = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0; - cur_kstat = kstat_data_lookup( arcstats, "other_size" ); + cur_kstat = kstat_data_lookup_wrapper( arcstats, "other_size" ); spl->zfs.other = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0; - if ((cur_kstat = kstat_data_lookup( arcstats, "compressed_size" )) != NULL) { + if ((cur_kstat = kstat_data_lookup_wrapper( arcstats, "compressed_size" )) != NULL) { spl->zfs.compressed = cur_kstat->value.ui64 / 1024; spl->zfs.isCompressed = 1; - cur_kstat = kstat_data_lookup( arcstats, "uncompressed_size" ); + cur_kstat = kstat_data_lookup_wrapper( arcstats, "uncompressed_size" ); spl->zfs.uncompressed = cur_kstat->value.ui64 / 1024; } else { spl->zfs.isCompressed = 0; @@ -294,13 +337,39 @@ void ProcessList_delete(ProcessList* pl) { free(spl); } +static void SolarisProcessList_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 SolarisProcessList_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); +} + /* 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. */ -int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo, void* listptr) { +static int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo, void* listptr) { bool preExisting; pid_t getpid; @@ -320,6 +389,7 @@ int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo, void* } else { getpid = lwpid; } + Process* proc = ProcessList_getProcess(pl, getpid, &preExisting, SolarisProcess_new); SolarisProcess* sproc = (SolarisProcess*) proc; @@ -337,21 +407,40 @@ int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo, void* // 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->st_uid = _psinfo->pr_euid; proc->pgrp = _psinfo->pr_pgid; proc->nlwp = _psinfo->pr_nlwp; + proc->session = _psinfo->pr_sid; + proc->tty_nr = _psinfo->pr_ttydev; - proc->m_resident = _psinfo->pr_rssize; // KB - proc->m_virt = _psinfo->pr_size; // KB + 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(pl->usersTable, proc->st_uid); + } if (!preExisting) { sproc->realpid = _psinfo->pr_pid; sproc->lwpid = lwpid_real; sproc->zoneid = _psinfo->pr_zoneid; sproc->zname = SolarisProcessList_readZoneName(spl->kd, sproc); - proc->user = UsersTable_getRef(pl->usersTable, proc->st_uid); - proc->comm = xStrdup(_psinfo->pr_fname); - proc->commLen = strnlen(_psinfo->pr_fname, PRFNSZ); + SolarisProcessList_updateExe(_psinfo->pr_pid, proc); + + Process_updateComm(proc, _psinfo->pr_fname); + Process_updateCmdline(proc, _psinfo->pr_psargs, 0, 0); + + if (proc->settings->flags & PROCESS_FLAG_CWD) { + SolarisProcessList_updateCwd(_psinfo->pr_pid, proc); + } } // End common code pass 1 @@ -360,22 +449,23 @@ int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo, void* proc->ppid = (_psinfo->pr_ppid * 1024); proc->tgid = (_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; proc->time = _psinfo->pr_time.tv_sec; if (!preExisting) { // Tasks done only for NEW processes - sproc->is_lwp = false; + proc->isUserlandThread = false; proc->starttime_ctime = _psinfo->pr_start.tv_sec; } // Update proc and thread counts based on settings - if (sproc->kernel && !pl->settings->hideKernelThreads) { + if (proc->isKernelThread && !pl->settings->hideKernelThreads) { pl->kernelThreads += proc->nlwp; pl->totalTasks += proc->nlwp + 1; if (proc->state == 'O') { pl->runningTasks++; } - } else if (!sproc->kernel) { + } else if (!proc->isKernelThread) { if (proc->state == 'O') { pl->runningTasks++; } @@ -386,24 +476,24 @@ int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo, void* pl->totalTasks += proc->nlwp + 1; } } - proc->show = !(pl->settings->hideKernelThreads && sproc->kernel); + proc->show = !(pl->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; proc->time = _lwpsinfo->pr_time.tv_sec; if (!preExisting) { // Tasks done only for NEW LWPs - sproc->is_lwp = true; - proc->basenameOffset = -1; + proc->isUserlandThread = true; proc->ppid = _psinfo->pr_pid * 1024; proc->tgid = _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 (sproc->kernel && !pl->settings->hideKernelThreads) { + if (proc->isKernelThread && !pl->settings->hideKernelThreads) { proc->show = true; } - if (!sproc->kernel && !pl->settings->hideUserlandThreads) { + if (!proc->isKernelThread && !pl->settings->hideUserlandThreads) { proc->show = true; } } // Top-level LWP or subordinate LWP @@ -412,13 +502,15 @@ int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo, void* if (!preExisting) { if ((sproc->realppid <= 0) && !(sproc->realpid <= 1)) { - sproc->kernel = true; + proc->isKernelThread = true; } else { - sproc->kernel = false; + proc->isKernelThread = false; } + Process_fillStarttimeBuffer(proc); ProcessList_add(pl, proc); } + proc->updated = true; // End common code pass 2 @@ -427,6 +519,7 @@ int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo, void* } void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { + SolarisProcessList_updateCPUcount(super); SolarisProcessList_scanCPUTime(super); SolarisProcessList_scanMemoryInfo(super); SolarisProcessList_scanZfsArcstats(super); @@ -439,3 +532,11 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { super->kernelThreads = 1; proc_walk(&SolarisProcessList_walkproc, super, PR_WALK_LWP); } + +bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id) { + assert(id < super->existingCPUs); + + const SolarisProcessList* spl = (const SolarisProcessList*) super; + + return (super->existingCPUs == 1) ? true : spl->cpus[id + 1].online; +} diff --git a/solaris/SolarisProcessList.h b/solaris/SolarisProcessList.h index 78362b6..f653b7c 100644 --- a/solaris/SolarisProcessList.h +++ b/solaris/SolarisProcessList.h @@ -8,14 +8,11 @@ Released under the GNU GPLv2, see the COPYING file in the source distribution for its full text. */ -#define MAXCMDLINE 255 - -#define GZONE "global " -#define UZONE "unknown " - -#include "zfs/ZfsArcStats.h" +#include "config.h" // IWYU pragma: keep #include +#include +#include #include #include #include @@ -23,6 +20,15 @@ in the source distribution for its full text. #include #include +#include "Hashtable.h" +#include "ProcessList.h" +#include "UsersTable.h" + +#include "solaris/SolarisProcess.h" + +#include "zfs/ZfsArcStats.h" + + #define ZONE_ERRMSGLEN 1024 extern char zone_errmsg[ZONE_ERRMSGLEN]; @@ -38,6 +44,7 @@ typedef struct CPUData_ { uint64_t lkrnl; uint64_t lintr; uint64_t lidle; + bool online; } CPUData; typedef struct SolarisProcessList_ { @@ -47,20 +54,12 @@ typedef struct SolarisProcessList_ { ZfsArcStats zfs; } SolarisProcessList; -char* SolarisProcessList_readZoneName(kstat_ctl_t* kd, SolarisProcess* sproc); - -ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId); +ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* dynamicColumns, Hashtable* pidMatchList, uid_t userId); void ProcessList_delete(ProcessList* pl); -/* 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. - */ - -int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo, void* listptr); - void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate); +bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id); + #endif -- cgit v1.2.3