From 4bcb5d116bd371fb72e8c43335316184fb8febd9 Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Thu, 27 May 2021 16:05:48 +1000 Subject: [PATCH] Update the PCP platform to use common Process fields and code Remove code now that we have common platform-independent command line wrangling (thanks BenBE!). Add PCP platform support for a handful of other recently arriving odds and ends - ELAPSED time, CWD, and so on. --- pcp/PCPProcess.c | 304 ++++--------------------------------------- pcp/PCPProcess.h | 43 ------ pcp/PCPProcessList.c | 81 ++++-------- pcp/Platform.c | 2 + pcp/Platform.h | 2 + pcp/ProcessField.h | 3 +- 6 files changed, 59 insertions(+), 376 deletions(-) diff --git a/pcp/PCPProcess.c b/pcp/PCPProcess.c index 4a5cdb32..3b66a301 100644 --- a/pcp/PCPProcess.c +++ b/pcp/PCPProcess.c @@ -21,9 +21,6 @@ in the source distribution for its full text. #include "ProvideCurses.h" #include "XUtils.h" -/* Used to identify kernel threads in Comm column */ -static const char *const kthreadID = "KTHREAD"; - const ProcessFieldData Process_fields[] = { [0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, }, [PID] = { .name = "PID", .title = "PID", .description = "Process/thread ID", .flags = 0, .pidColumn = true, }, @@ -45,6 +42,7 @@ const ProcessFieldData Process_fields[] = { [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 = "If 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, .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, }, @@ -81,20 +79,11 @@ const ProcessFieldData Process_fields[] = { [M_PSSWP] = { .name = "M_PSSWP", .title = " PSSWP ", .description = "shows proportional swap share of this mapping, Unlike \"Swap\", this does not take into account swapped out page of underlying shmem objects.", .flags = PROCESS_FLAG_LINUX_SMAPS, .defaultSortDesc = true, }, [CTXT] = { .name = "CTXT", .title = " CTXT ", .description = "Context switches (incremental sum of voluntary_ctxt_switches and nonvoluntary_ctxt_switches)", .flags = PROCESS_FLAG_LINUX_CTXT, .defaultSortDesc = true, }, [SECATTR] = { .name = "SECATTR", .title = " Security Attribute ", .description = "Security attribute of the process (e.g. SELinux or AppArmor)", .flags = PROCESS_FLAG_LINUX_SECATTR, }, - [PROC_COMM] = { .name = "COMM", .title = "COMM ", .description = "comm string of the process from /proc/[pid]/comm", .flags = 0, }, + [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, }, }; -/* This function returns the string displayed in Command column, so that sorting - * happens on what is displayed - whether comm, full path, basename, etc.. So - * this follows PCPProcess_writeField(COMM) and PCPProcess_writeCommand */ -static const char* PCPProcess_getCommandStr(const Process *this) { - const PCPProcess *pp = (const PCPProcess *)this; - if ((Process_isUserlandThread(this) && this->settings->showThreadNames) || !pp->mergedCommand.str) { - return this->comm; - } - return pp->mergedCommand.str; -} - Process* PCPProcess_new(const Settings* settings) { PCPProcess* this = xCalloc(1, sizeof(PCPProcess)); Object_setClass(this, Class(PCPProcess)); @@ -107,8 +96,6 @@ void Process_delete(Object* cast) { Process_done((Process*)cast); free(this->cgroup); free(this->secattr); - free(this->procComm); - free(this->mergedCommand.str); free(this); } @@ -120,210 +107,6 @@ static void PCPProcess_printDelay(float delay_percent, char* buffer, int n) { } } -/* -TASK_COMM_LEN is defined to be 16 for /proc/[pid]/comm in man proc(5), but is -not available in an userspace header - so define it. Note: when colorizing a -basename with the comm prefix, the entire basename (not just the comm prefix) -is colorized for better readability, and it is implicit that only up to -(TASK_COMM_LEN - 1) could be comm. -*/ -#define TASK_COMM_LEN 16 - -/* -This function makes the merged Command string. It also stores the offsets of -the basename, comm w.r.t the merged Command string - these offsets will be used -by PCPProcess_writeCommand() for coloring. The merged Command string is also -returned by PCPProcess_getCommandStr() for searching, sorting and filtering. -*/ -void PCPProcess_makeCommandStr(Process* this) { - PCPProcess *pp = (PCPProcess *)this; - PCPProcessMergedCommand *mc = &pp->mergedCommand; - - bool showMergedCommand = this->settings->showMergedCommand; - bool showProgramPath = this->settings->showProgramPath; - bool searchCommInCmdline = this->settings->findCommInCmdline; - - /* pp->mergedCommand.str needs updating only if its state or contents - * changed. Its content is based on the fields cmdline and comm. */ - if ( - mc->prevMergeSet == showMergedCommand && - mc->prevPathSet == showProgramPath && - mc->prevCommSet == searchCommInCmdline && - !mc->cmdlineChanged && - !mc->commChanged - ) { - return; - } - - /* The field separtor "│" has been chosen such that it will not match any - * valid string used for searching or filtering */ - const char *SEPARATOR = CRT_treeStr[TREE_STR_VERT]; - const int SEPARATOR_LEN = strlen(SEPARATOR); - - /* Check for any changed fields since we last built this string */ - if (mc->cmdlineChanged || mc->commChanged) { - free(mc->str); - /* Accommodate the column text, two field separators and terminating NUL */ - mc->str = xCalloc(1, mc->maxLen + 2*SEPARATOR_LEN + 1); - } - - /* Preserve the settings used in this run */ - mc->prevMergeSet = showMergedCommand; - mc->prevPathSet = showProgramPath; - mc->prevCommSet = searchCommInCmdline; - - /* Mark everything as unchanged */ - mc->cmdlineChanged = false; - mc->commChanged = false; - - /* Clear any separators */ - mc->sep1 = 0; - mc->sep2 = 0; - /* Clear any highlighting locations */ - mc->baseStart = 0; - mc->baseEnd = 0; - mc->commStart = 0; - mc->commEnd = 0; - - const char *cmdline = this->comm; - const char *procComm = pp->procComm; - - char *strStart = mc->str; - char *str = strStart; - - int cmdlineBasenameOffset = pp->procCmdlineBasenameOffset; - int cmdlineBasenameEnd = pp->procCmdlineBasenameEnd; - - if (!cmdline) { - cmdlineBasenameOffset = 0; - cmdlineBasenameEnd = 0; - cmdline = "(zombie)"; - } - - assert(cmdlineBasenameOffset >= 0); - assert(cmdlineBasenameOffset <= (int)strlen(cmdline)); - - if (showMergedCommand && procComm && strlen(procComm)) { /* Prefix column with comm */ - if (strncmp(cmdline + cmdlineBasenameOffset, procComm, MINIMUM(TASK_COMM_LEN - 1, strlen(procComm))) != 0) { - mc->commStart = 0; - mc->commEnd = strlen(procComm); - - str = stpcpy(str, procComm); - - mc->sep1 = str - strStart; - str = stpcpy(str, SEPARATOR); - } - } - - if (showProgramPath) { - (void) stpcpy(str, cmdline); - mc->baseStart = cmdlineBasenameOffset; - mc->baseEnd = cmdlineBasenameEnd; - } else { - (void) stpcpy(str, cmdline + cmdlineBasenameOffset); - mc->baseStart = 0; - mc->baseEnd = cmdlineBasenameEnd - cmdlineBasenameOffset; - } - - if (mc->sep1) { - mc->baseStart += str - strStart - SEPARATOR_LEN + 1; - mc->baseEnd += str - strStart - SEPARATOR_LEN + 1; - } -} - -static void PCPProcess_writeCommand(const Process* this, int attr, int baseAttr, RichString* str) { - const PCPProcess *pp = (const PCPProcess *)this; - const PCPProcessMergedCommand *mc = &pp->mergedCommand; - - int strStart = RichString_size(str); - - int baseStart = strStart + pp->mergedCommand.baseStart; - int baseEnd = strStart + pp->mergedCommand.baseEnd; - int commStart = strStart + pp->mergedCommand.commStart; - int commEnd = strStart + pp->mergedCommand.commEnd; - - int commAttr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_COMM : PROCESS_COMM]; - - bool highlightBaseName = this->settings->highlightBaseName; - - RichString_appendWide(str, attr, pp->mergedCommand.str); - - if (pp->mergedCommand.commEnd) { - if (!pp->mergedCommand.separateComm && commStart == baseStart && highlightBaseName) { - /* If it was matched with binaries basename, make it bold if needed */ - if (commEnd > baseEnd) { - RichString_setAttrn(str, A_BOLD | baseAttr, baseStart, baseEnd - baseStart); - RichString_setAttrn(str, A_BOLD | commAttr, baseEnd, commEnd - baseEnd); - } else if (commEnd < baseEnd) { - RichString_setAttrn(str, A_BOLD | commAttr, commStart, commEnd - commStart); - RichString_setAttrn(str, A_BOLD | baseAttr, commEnd, baseEnd - commEnd); - } else { - // Actually should be highlighted commAttr, but marked baseAttr to reduce visual noise - RichString_setAttrn(str, A_BOLD | baseAttr, commStart, commEnd - commStart); - } - - baseStart = baseEnd; - } else { - RichString_setAttrn(str, commAttr, commStart, commEnd - commStart); - } - } - - if (baseStart < baseEnd && highlightBaseName) { - RichString_setAttrn(str, baseAttr, baseStart, baseEnd - baseStart); - } - - if (mc->sep1) - RichString_setAttrn(str, CRT_colors[FAILED_READ], strStart + mc->sep1, 1); - if (mc->sep2) - RichString_setAttrn(str, CRT_colors[FAILED_READ], strStart + mc->sep2, 1); -} - -static void PCPProcess_writeCommandField(const Process *this, RichString *str, char *buffer, int n, int attr) { - /* This code is from Process_writeField for COMM, but we invoke - * PCPProcess_writeCommand to display the full binary path - * (or its basename)│/proc/pid/comm│/proc/pid/cmdline */ - int baseattr = CRT_colors[PROCESS_BASENAME]; - if (this->settings->highlightThreads && Process_isThread(this)) { - attr = CRT_colors[PROCESS_THREAD]; - baseattr = CRT_colors[PROCESS_THREAD_BASENAME]; - } - if (!this->settings->treeView || this->indent == 0) { - PCPProcess_writeCommand(this, attr, baseattr, str); - } else { - char* buf = buffer; - int maxIndent = 0; - bool lastItem = (this->indent < 0); - int indent = (this->indent < 0 ? -this->indent : this->indent); - int vertLen = strlen(CRT_treeStr[TREE_STR_VERT]); - - for (int i = 0; i < 32; i++) { - if (indent & (1U << i)) { - maxIndent = i+1; - } - } - for (int i = 0; i < maxIndent - 1; i++) { - if (indent & (1 << i)) { - if (buf - buffer + (vertLen + 3) > n) { - break; - } - buf = stpcpy(buf, CRT_treeStr[TREE_STR_VERT]); - buf = stpcpy(buf, " "); - } else { - if (buf - buffer + 4 > n) { - break; - } - buf = stpcpy(buf, " "); - } - } - - n -= (buf - buffer); - const char* draw = CRT_treeStr[lastItem ? TREE_STR_BEND : TREE_STR_RTEE]; - xSnprintf(buf, n, "%s%s ", draw, this->showChildren ? CRT_treeStr[TREE_STR_SHUT] : CRT_treeStr[TREE_STR_OPEN] ); - RichString_appendWide(str, CRT_colors[PROCESS_TREE], buffer); - PCPProcess_writeCommand(this, attr, baseattr, str); - } -} - static void PCPProcess_writeField(const Process* this, RichString* str, ProcessField field) { const PCPProcess* pp = (const PCPProcess*) this; bool coloring = this->settings->highlightMegabytes; @@ -331,29 +114,29 @@ static void PCPProcess_writeField(const Process* this, RichString* str, ProcessF int attr = CRT_colors[DEFAULT_COLOR]; int n = sizeof(buffer) - 1; switch ((int)field) { - case CMINFLT: Process_colorNumber(str, pp->cminflt, coloring); return; - case CMAJFLT: Process_colorNumber(str, pp->cmajflt, coloring); return; - case M_DRS: Process_humanNumber(str, pp->m_drs, coloring); return; - case M_DT: Process_humanNumber(str, pp->m_dt, coloring); return; - case M_LRS: Process_humanNumber(str, pp->m_lrs, coloring); return; - case M_TRS: Process_humanNumber(str, pp->m_trs, coloring); return; - case M_SHARE: Process_humanNumber(str, pp->m_share, coloring); return; - case M_PSS: Process_humanNumber(str, pp->m_pss, coloring); return; - case M_SWAP: Process_humanNumber(str, pp->m_swap, coloring); return; - case M_PSSWP: Process_humanNumber(str, pp->m_psswp, coloring); return; - case UTIME: Process_printTime(str, pp->utime); return; - case STIME: Process_printTime(str, pp->stime); return; - case CUTIME: Process_printTime(str, pp->cutime); return; - case CSTIME: Process_printTime(str, pp->cstime); return; - case RCHAR: Process_humanNumber(str, pp->io_rchar, coloring); return; - case WCHAR: Process_humanNumber(str, pp->io_wchar, coloring); return; - case SYSCR: Process_colorNumber(str, pp->io_syscr, coloring); return; - case SYSCW: Process_colorNumber(str, pp->io_syscw, coloring); return; - case RBYTES: Process_humanNumber(str, pp->io_read_bytes, coloring); return; - case WBYTES: Process_humanNumber(str, pp->io_write_bytes, coloring); return; - case CNCLWB: Process_humanNumber(str, pp->io_cancelled_write_bytes, coloring); return; - case IO_READ_RATE: Process_outputRate(str, buffer, n, pp->io_rate_read_bps, coloring); return; - case IO_WRITE_RATE: Process_outputRate(str, buffer, n, pp->io_rate_write_bps, coloring); return; + case CMINFLT: Process_printCount(str, pp->cminflt, coloring); return; + case CMAJFLT: Process_printCount(str, pp->cmajflt, coloring); return; + case M_DRS: Process_printBytes(str, pp->m_drs, coloring); return; + case M_DT: Process_printBytes(str, pp->m_dt, coloring); return; + case M_LRS: Process_printBytes(str, pp->m_lrs, coloring); return; + case M_TRS: Process_printBytes(str, pp->m_trs, coloring); return; + case M_SHARE: Process_printBytes(str, pp->m_share, coloring); return; + case M_PSS: Process_printKBytes(str, pp->m_pss, coloring); return; + case M_SWAP: Process_printKBytes(str, pp->m_swap, coloring); return; + case M_PSSWP: Process_printKBytes(str, pp->m_psswp, coloring); return; + case UTIME: Process_printTime(str, pp->utime, coloring); return; + case STIME: Process_printTime(str, pp->stime, coloring); return; + case CUTIME: Process_printTime(str, pp->cutime, coloring); return; + case CSTIME: Process_printTime(str, pp->cstime, coloring); return; + case RCHAR: Process_printBytes(str, pp->io_rchar, coloring); return; + case WCHAR: Process_printBytes(str, pp->io_wchar, coloring); return; + case SYSCR: Process_printCount(str, pp->io_syscr, coloring); return; + case SYSCW: Process_printCount(str, pp->io_syscw, coloring); return; + case RBYTES: Process_printBytes(str, pp->io_read_bytes, coloring); return; + case WBYTES: Process_printBytes(str, pp->io_write_bytes, coloring); return; + case CNCLWB: Process_printBytes(str, pp->io_cancelled_write_bytes, coloring); return; + case IO_READ_RATE: Process_printRate(str, pp->io_rate_read_bps, coloring); return; + case IO_WRITE_RATE: Process_printRate(str, pp->io_rate_write_bps, coloring); return; case IO_RATE: { double totalRate = NAN; if (!isnan(pp->io_rate_read_bps) && !isnan(pp->io_rate_write_bps)) @@ -364,7 +147,7 @@ static void PCPProcess_writeField(const Process* this, RichString* str, ProcessF totalRate = pp->io_rate_write_bps; else totalRate = NAN; - Process_outputRate(str, buffer, n, totalRate, coloring); return; + Process_printRate(str, totalRate, coloring); return; } case CGROUP: xSnprintf(buffer, n, "%-10s ", pp->cgroup ? pp->cgroup : ""); break; case OOM: xSnprintf(buffer, n, "%4u ", pp->oom); break; @@ -384,27 +167,6 @@ static void PCPProcess_writeField(const Process* this, RichString* str, ProcessF xSnprintf(buffer, n, "%5lu ", pp->ctxt_diff); break; case SECATTR: snprintf(buffer, n, "%-30s ", pp->secattr ? pp->secattr : "?"); break; - case COMM: { - if ((Process_isUserlandThread(this) && this->settings->showThreadNames) || !pp->mergedCommand.str) { - Process_writeField(this, str, field); - } else { - PCPProcess_writeCommandField(this, str, buffer, n, attr); - } - return; - } - case PROC_COMM: { - const char* procComm; - if (pp->procComm) { - attr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_COMM : PROCESS_COMM]; - procComm = pp->procComm; - } else { - attr = CRT_colors[PROCESS_SHADOW]; - procComm = Process_isKernelThread(this) ? kthreadID : "N/A"; - } - /* 15 being (TASK_COMM_LEN - 1) */ - Process_printLeftAlignedField(str, attr, procComm, 15); - return; - } default: Process_writeField(this, str, field); return; @@ -482,20 +244,11 @@ static int PCPProcess_compareByKey(const Process* v1, const Process* v2, Process return SPACESHIP_NUMBER(p1->ctxt_diff, p1->ctxt_diff); case SECATTR: return SPACESHIP_NULLSTR(p1->secattr, p2->secattr); - case PROC_COMM: { - const char *comm1 = p1->procComm ? p1->procComm : (Process_isKernelThread(v1) ? kthreadID : ""); - const char *comm2 = p2->procComm ? p2->procComm : (Process_isKernelThread(v2) ? kthreadID : ""); - return strcmp(comm1, comm2); - } default: return Process_compareByKey_Base(v1, v2, key); } } -bool Process_isThread(const Process* this) { - return (Process_isUserlandThread(this) || Process_isKernelThread(this)); -} - const ProcessClass PCPProcess_class = { .super = { .extends = Class(Process), @@ -504,6 +257,5 @@ const ProcessClass PCPProcess_class = { .compare = Process_compare }, .writeField = PCPProcess_writeField, - .getCommandStr = PCPProcess_getCommandStr, .compareByKey = PCPProcess_compareByKey }; diff --git a/pcp/PCPProcess.h b/pcp/PCPProcess.h index 946d3831..25707f2b 100644 --- a/pcp/PCPProcess.h +++ b/pcp/PCPProcess.h @@ -26,35 +26,8 @@ in the source distribution for its full text. #define PROCESS_FLAG_LINUX_CTXT 0x4000 #define PROCESS_FLAG_LINUX_SECATTR 0x8000 -/* PCPProcessMergedCommand is populated by PCPProcess_makeCommandStr: It - * contains the merged Command string, and the information needed by - * PCPProcess_writeCommand to color the string. str will be NULL for kernel - * threads and zombies */ -typedef struct PCPProcessMergedCommand_ { - char *str; /* merged Command string */ - int maxLen; /* maximum expected length of Command string */ - int baseStart; /* basename's start offset */ - int baseEnd; /* basename's end offset */ - int commStart; /* comm's start offset */ - int commEnd; /* comm's end offset */ - int sep1; /* first field separator, used if non-zero */ - int sep2; /* second field separator, used if non-zero */ - bool separateComm; /* whether comm is a separate field */ - bool cmdlineChanged; /* whether cmdline changed */ - bool commChanged; /* whether comm changed */ - bool prevMergeSet; /* whether showMergedCommand was set */ - bool prevPathSet; /* whether showProgramPath was set */ - bool prevCommSet; /* whether findCommInCmdline was set */ - bool prevCmdlineSet; /* whether findCommInCmdline was set */ -} PCPProcessMergedCommand; - typedef struct PCPProcess_ { Process super; - char *procComm; - int procCmdlineBasenameOffset; - int procCmdlineBasenameEnd; - PCPProcessMergedCommand mergedCommand; - bool isKernelThread; unsigned long int cminflt; unsigned long int cmajflt; unsigned long long int utime; @@ -111,18 +84,6 @@ typedef struct PCPProcess_ { unsigned long long int last_mlrs_calctime; } PCPProcess; -static inline void Process_setKernelThread(Process* this, bool truth) { - ((PCPProcess*)this)->isKernelThread = truth; -} - -static inline bool Process_isKernelThread(const Process* this) { - return ((const PCPProcess*)this)->isKernelThread; -} - -static inline bool Process_isUserlandThread(const Process* this) { - return this->pid != this->tgid; -} - extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD]; extern const ProcessClass PCPProcess_class; @@ -131,10 +92,6 @@ Process* PCPProcess_new(const Settings* settings); void Process_delete(Object* cast); -/* This function constructs the string that is displayed by - * PCPProcess_writeCommand and also returned by PCPProcess_getCommandStr */ -void PCPProcess_makeCommandStr(Process *this); - bool Process_isThread(const Process* this); #endif diff --git a/pcp/PCPProcessList.c b/pcp/PCPProcessList.c index 3755c9bc..0985ad2c 100644 --- a/pcp/PCPProcessList.c +++ b/pcp/PCPProcessList.c @@ -364,6 +364,10 @@ static void PCPProcessList_readSecattrData(PCPProcess* process, int pid, int off process->secattr = setString(PCP_PROC_LABELS, pid, offset, process->secattr); } +static void PCPProcessList_readCwd(PCPProcess* process, int pid, int offset) { + process->super.procCwd = setString(PCP_PROC_CWD, pid, offset, process->super.procCwd); +} + static void PCPProcessList_updateUsername(Process* process, int pid, int offset, UsersTable* users) { unsigned int uid = 0; pmAtomValue value; @@ -377,61 +381,42 @@ static void PCPProcessList_updateCmdline(Process* process, int pid, int offset, pmAtomValue value; if (!Metric_instance(PCP_PROC_PSARGS, pid, offset, &value, PM_TYPE_STRING)) { if (process->state != 'Z') - Process_setKernelThread(process, true); - else - process->basenameOffset = 0; + process->isKernelThread = true; + Process_updateCmdline(process, NULL, 0, 0); return; } char *command = value.cp; int length = strlen(command); if (command[0] != '(') { - Process_setKernelThread(process, false); + process->isKernelThread = false; } else { ++command; --length; if (command[length-1] == ')') command[length-1] = '\0'; - Process_setKernelThread(process, true); + process->isKernelThread = true; } - int tokenEnd = 0; int tokenStart = 0; - int lastChar = 0; for (int i = 0; i < length; i++) { /* htop considers the next character after the last / that is before * basenameOffset, as the start of the basename in cmdline - see * Process_writeCommand */ if (command[i] == '/') tokenStart = i + 1; - lastChar = i; - } - tokenEnd = length; - - PCPProcess *pp = (PCPProcess *)process; - pp->mergedCommand.maxLen = lastChar + 1; /* accommodate cmdline */ - if (!process->comm || !String_eq(command, process->comm)) { - process->basenameOffset = tokenEnd; - free_and_xStrdup(&process->comm, command); - pp->procCmdlineBasenameOffset = tokenStart; - pp->procCmdlineBasenameEnd = tokenEnd; - pp->mergedCommand.cmdlineChanged = true; - } - - /* comm could change, so should be updated */ - if ((length = strlen(comm)) > 0) { - pp->mergedCommand.maxLen += length; - if (!pp->procComm || !String_eq(command, pp->procComm)) { - free_and_xStrdup(&pp->procComm, command); - pp->mergedCommand.commChanged = true; - } - } else if (pp->procComm) { - free(pp->procComm); - pp->procComm = NULL; - pp->mergedCommand.commChanged = true; } + int tokenEnd = length; + Process_updateCmdline(process, command, tokenStart, tokenEnd); free(value.cp); + + Process_updateComm(process, comm); + + if (Metric_instance(PCP_PROC_EXE, pid, offset, &value, PM_TYPE_STRING)) { + Process_updateExe(process, value.cp); + free(value.cp); + } } static bool PCPProcessList_updateProcesses(PCPProcessList* this, double period, struct timeval* tv) { @@ -511,16 +496,6 @@ static bool PCPProcessList_updateProcesses(PCPProcessList* this, double period, PCPProcessList_updateCmdline(proc, pid, offset, command); } - /* (Re)Generate the Command string, but only if the process is: - * - not a kernel thread, and - * - not a zombie or it became zombie under htop's watch, and - * - not a user thread or if showThreadNames is not set */ - if (!Process_isKernelThread(proc) && - (proc->state != 'Z' || pp->mergedCommand.str) && - (!Process_isUserlandThread(proc) || !settings->showThreadNames)) { - PCPProcess_makeCommandStr(proc); - } - if (settings->flags & PROCESS_FLAG_LINUX_CGROUP) PCPProcessList_readCGroups(pp, pid, offset); @@ -533,20 +508,16 @@ static bool PCPProcessList_updateProcesses(PCPProcessList* this, double period, if (settings->flags & PROCESS_FLAG_LINUX_SECATTR) PCPProcessList_readSecattrData(pp, pid, offset); - if (proc->state == 'Z' && proc->basenameOffset == 0) { - proc->basenameOffset = -1; - free_and_xStrdup(&proc->comm, command); - pp->procCmdlineBasenameOffset = 0; - pp->procCmdlineBasenameEnd = 0; - pp->mergedCommand.commChanged = true; + if (settings->flags & PROCESS_FLAG_CWD) + PCPProcessList_readCwd(pp, pid, offset); + + if (proc->state == 'Z' && !proc->cmdline && command[0]) { + Process_updateCmdline(proc, command, 0, strlen(command)); } else if (Process_isThread(proc)) { - if (settings->showThreadNames || Process_isKernelThread(proc)) { - proc->basenameOffset = -1; - free_and_xStrdup(&proc->comm, command); - pp->procCmdlineBasenameOffset = 0; - pp->procCmdlineBasenameEnd = 0; - pp->mergedCommand.commChanged = true; + if ((settings->showThreadNames || Process_isKernelThread(proc)) && command[0]) { + Process_updateCmdline(proc, command, 0, strlen(command)); } + if (Process_isKernelThread(proc)) { pl->kernelThreads++; } else { @@ -557,14 +528,12 @@ static bool PCPProcessList_updateProcesses(PCPProcessList* this, double period, /* Set at the end when we know if a new entry is a thread */ proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc))); -//fprintf(stderr, "Updated PID %d [%s] show=%d user=%d[%d] kern=%d[%d]\n", pid, command, proc->show, Process_isUserlandThread(proc), hideUserlandThreads, Process_isKernelThread(proc), hideKernelThreads); pl->totalTasks++; if (proc->state == 'R') pl->runningTasks++; proc->updated = true; } -//fprintf(stderr, "Total tasks %d, running=%d\n", pl->totalTasks, pl->runningTasks); return true; } diff --git a/pcp/Platform.c b/pcp/Platform.c index 1caa3e09..f4d538df 100644 --- a/pcp/Platform.c +++ b/pcp/Platform.c @@ -219,6 +219,8 @@ static const char *Platform_metricNames[] = { [PCP_PROC_LABELS] = "proc.psinfo.labels", [PCP_PROC_ENVIRON] = "proc.psinfo.environ", [PCP_PROC_TTYNAME] = "proc.psinfo.ttyname", + [PCP_PROC_EXE] = "proc.psinfo.exe", + [PCP_PROC_CWD] = "proc.psinfo.cwd", [PCP_PROC_ID_UID] = "proc.id.uid", [PCP_PROC_ID_USER] = "proc.id.uid_nm", [PCP_PROC_IO_RCHAR] = "proc.io.rchar", diff --git a/pcp/Platform.h b/pcp/Platform.h index 2a1bd3b4..cd90bc00 100644 --- a/pcp/Platform.h +++ b/pcp/Platform.h @@ -206,6 +206,8 @@ typedef enum Metric_ { PCP_PROC_LABELS, /* proc.psinfo.labels */ PCP_PROC_ENVIRON, /* proc.psinfo.environ */ PCP_PROC_TTYNAME, /* proc.psinfo.ttyname */ + PCP_PROC_EXE, /* proc.psinfo.exe */ + PCP_PROC_CWD, /* proc.psinfo.cwd */ PCP_PROC_ID_UID, /* proc.id.uid */ PCP_PROC_ID_USER, /* proc.id.uid_nm */ diff --git a/pcp/ProcessField.h b/pcp/ProcessField.h index ee03cbaf..3d5cb743 100644 --- a/pcp/ProcessField.h +++ b/pcp/ProcessField.h @@ -43,7 +43,8 @@ in the source distribution for its full text. M_PSSWP = 121, \ CTXT = 122, \ SECATTR = 123, \ - PROC_COMM = 124, \ + \ + DUMMY_BUMP_FIELD = CWD, \ // End of list