From 7271b076b82785ffca73ee9e4ae84cabb77018ee Mon Sep 17 00:00:00 2001 From: Daniel Lange Date: Wed, 10 Jan 2024 12:40:37 +0100 Subject: New upstream version 3.3.0 --- Process.c | 690 ++++++++++++++++++++------------------------------------------ 1 file changed, 222 insertions(+), 468 deletions(-) (limited to 'Process.c') diff --git a/Process.c b/Process.c index fcaa3d5..a36ab6c 100644 --- a/Process.c +++ b/Process.c @@ -11,7 +11,6 @@ in the source distribution for its full text. #include "Process.h" #include -#include #include #include #include @@ -19,16 +18,18 @@ in the source distribution for its full text. #include #include #include -#include #include #include "CRT.h" +#include "Hashtable.h" +#include "Machine.h" #include "Macros.h" -#include "Platform.h" -#include "ProcessList.h" +#include "ProcessTable.h" #include "DynamicColumn.h" #include "RichString.h" +#include "Scheduling.h" #include "Settings.h" +#include "Table.h" #include "XUtils.h" #if defined(MAJOR_IN_MKDEV) @@ -39,242 +40,15 @@ in the source distribution for its full text. /* Used to identify kernel threads in Comm and Exe columns */ static const char* const kthreadID = "KTHREAD"; -static uid_t Process_getuid = (uid_t)-1; - -int Process_pidDigits = PROCESS_MIN_PID_DIGITS; -int Process_uidDigits = PROCESS_MIN_UID_DIGITS; - -void Process_setupColumnWidths(void) { - int maxPid = Platform_getMaxPid(); - if (maxPid == -1) - return; - - if (maxPid < (int)pow(10, PROCESS_MIN_PID_DIGITS)) { - Process_pidDigits = PROCESS_MIN_PID_DIGITS; - return; - } - - Process_pidDigits = (int)log10(maxPid) + 1; - assert(Process_pidDigits <= PROCESS_MAX_PID_DIGITS); -} - -void Process_setUidColumnWidth(uid_t maxUid) { - if (maxUid < (uid_t)pow(10, PROCESS_MIN_UID_DIGITS)) { - Process_uidDigits = PROCESS_MIN_UID_DIGITS; - return; - } - - Process_uidDigits = (int)log10(maxUid) + 1; - assert(Process_uidDigits <= PROCESS_MAX_UID_DIGITS); -} - -void Process_printBytes(RichString* str, unsigned long long number, bool coloring) { - char buffer[16]; - int len; - - int largeNumberColor = coloring ? CRT_colors[LARGE_NUMBER] : CRT_colors[PROCESS]; - int processMegabytesColor = coloring ? CRT_colors[PROCESS_MEGABYTES] : CRT_colors[PROCESS]; - int processGigabytesColor = coloring ? CRT_colors[PROCESS_GIGABYTES] : CRT_colors[PROCESS]; - int shadowColor = coloring ? CRT_colors[PROCESS_SHADOW] : CRT_colors[PROCESS]; - int processColor = CRT_colors[PROCESS]; - - if (number == ULLONG_MAX) { - //Invalid number - RichString_appendAscii(str, shadowColor, " N/A "); - return; - } - - number /= ONE_K; - - if (number < 1000) { - //Plain number, no markings - len = xSnprintf(buffer, sizeof(buffer), "%5llu ", number); - RichString_appendnAscii(str, processColor, buffer, len); - } else if (number < 100000) { - //2 digit MB, 3 digit KB - len = xSnprintf(buffer, sizeof(buffer), "%2llu", number / 1000); - RichString_appendnAscii(str, processMegabytesColor, buffer, len); - number %= 1000; - len = xSnprintf(buffer, sizeof(buffer), "%03llu ", number); - RichString_appendnAscii(str, processColor, buffer, len); - } else if (number < 1000 * ONE_K) { - //3 digit MB - number /= ONE_K; - len = xSnprintf(buffer, sizeof(buffer), "%4lluM ", number); - RichString_appendnAscii(str, processMegabytesColor, buffer, len); - } else if (number < 10000 * ONE_K) { - //1 digit GB, 3 digit MB - number /= ONE_K; - len = xSnprintf(buffer, sizeof(buffer), "%1llu", number / 1000); - RichString_appendnAscii(str, processGigabytesColor, buffer, len); - number %= 1000; - len = xSnprintf(buffer, sizeof(buffer), "%03lluM ", number); - RichString_appendnAscii(str, processMegabytesColor, buffer, len); - } else if (number < 100000 * ONE_K) { - //2 digit GB, 1 digit MB - number /= 100 * ONE_K; - len = xSnprintf(buffer, sizeof(buffer), "%2llu", number / 10); - RichString_appendnAscii(str, processGigabytesColor, buffer, len); - number %= 10; - len = xSnprintf(buffer, sizeof(buffer), ".%1llu", number); - RichString_appendnAscii(str, processMegabytesColor, buffer, len); - RichString_appendAscii(str, processGigabytesColor, "G "); - } else if (number < 1000 * ONE_M) { - //3 digit GB - number /= ONE_M; - len = xSnprintf(buffer, sizeof(buffer), "%4lluG ", number); - RichString_appendnAscii(str, processGigabytesColor, buffer, len); - } else if (number < 10000ULL * ONE_M) { - //1 digit TB, 3 digit GB - number /= ONE_M; - len = xSnprintf(buffer, sizeof(buffer), "%1llu", number / 1000); - RichString_appendnAscii(str, largeNumberColor, buffer, len); - number %= 1000; - len = xSnprintf(buffer, sizeof(buffer), "%03lluG ", number); - RichString_appendnAscii(str, processGigabytesColor, buffer, len); - } else if (number < 100000 * ONE_M) { - //2 digit TB, 1 digit GB - number /= 100 * ONE_M; - len = xSnprintf(buffer, sizeof(buffer), "%2llu", number / 10); - RichString_appendnAscii(str, largeNumberColor, buffer, len); - number %= 10; - len = xSnprintf(buffer, sizeof(buffer), ".%1llu", number); - RichString_appendnAscii(str, processGigabytesColor, buffer, len); - RichString_appendAscii(str, largeNumberColor, "T "); - } else if (number < 10000ULL * ONE_G) { - //3 digit TB or 1 digit PB, 3 digit TB - number /= ONE_G; - len = xSnprintf(buffer, sizeof(buffer), "%4lluT ", number); - RichString_appendnAscii(str, largeNumberColor, buffer, len); - } else { - //2 digit PB and above - len = xSnprintf(buffer, sizeof(buffer), "%4.1lfP ", (double)number / ONE_T); - RichString_appendnAscii(str, largeNumberColor, buffer, len); - } -} - -void Process_printKBytes(RichString* str, unsigned long long number, bool coloring) { - if (number == ULLONG_MAX) - Process_printBytes(str, ULLONG_MAX, coloring); - else - Process_printBytes(str, number * ONE_K, coloring); -} - -void Process_printCount(RichString* str, unsigned long long number, bool coloring) { - char buffer[13]; - - int largeNumberColor = coloring ? CRT_colors[LARGE_NUMBER] : CRT_colors[PROCESS]; - int processMegabytesColor = coloring ? CRT_colors[PROCESS_MEGABYTES] : CRT_colors[PROCESS]; - int processColor = CRT_colors[PROCESS]; - int processShadowColor = coloring ? CRT_colors[PROCESS_SHADOW] : CRT_colors[PROCESS]; - - if (number == ULLONG_MAX) { - RichString_appendAscii(str, CRT_colors[PROCESS_SHADOW], " N/A "); - } else if (number >= 100000LL * ONE_DECIMAL_T) { - xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_G); - RichString_appendnAscii(str, largeNumberColor, buffer, 12); - } else if (number >= 100LL * ONE_DECIMAL_T) { - xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_M); - RichString_appendnAscii(str, largeNumberColor, buffer, 8); - RichString_appendnAscii(str, processMegabytesColor, buffer + 8, 4); - } else if (number >= 10LL * ONE_DECIMAL_G) { - xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_K); - RichString_appendnAscii(str, largeNumberColor, buffer, 5); - RichString_appendnAscii(str, processMegabytesColor, buffer + 5, 3); - RichString_appendnAscii(str, processColor, buffer + 8, 4); - } else { - xSnprintf(buffer, sizeof(buffer), "%11llu ", number); - RichString_appendnAscii(str, largeNumberColor, buffer, 2); - RichString_appendnAscii(str, processMegabytesColor, buffer + 2, 3); - RichString_appendnAscii(str, processColor, buffer + 5, 3); - RichString_appendnAscii(str, processShadowColor, buffer + 8, 4); - } -} - -void Process_printTime(RichString* str, unsigned long long totalHundredths, bool coloring) { - char buffer[10]; - int len; - - unsigned long long totalSeconds = totalHundredths / 100; - unsigned long long hours = totalSeconds / 3600; - unsigned long long days = totalSeconds / 86400; - int minutes = (totalSeconds / 60) % 60; - int seconds = totalSeconds % 60; - int hundredths = totalHundredths - (totalSeconds * 100); - - int yearColor = coloring ? CRT_colors[LARGE_NUMBER] : CRT_colors[PROCESS]; - int dayColor = coloring ? CRT_colors[PROCESS_GIGABYTES] : CRT_colors[PROCESS]; - int hourColor = coloring ? CRT_colors[PROCESS_MEGABYTES] : CRT_colors[PROCESS]; - int defColor = CRT_colors[PROCESS]; - - if (days >= /* Ignore leapyears */365) { - int years = days / 365; - int daysLeft = days - 365 * years; - - if (years >= 10000000) { - RichString_appendnAscii(str, yearColor, "eternity ", 9); - } else if (years >= 1000) { - len = xSnprintf(buffer, sizeof(buffer), "%7dy ", years); - RichString_appendnAscii(str, yearColor, buffer, len); - } else if (daysLeft >= 100) { - len = xSnprintf(buffer, sizeof(buffer), "%3dy", years); - RichString_appendnAscii(str, yearColor, buffer, len); - len = xSnprintf(buffer, sizeof(buffer), "%3dd ", daysLeft); - RichString_appendnAscii(str, dayColor, buffer, len); - } else if (daysLeft >= 10) { - len = xSnprintf(buffer, sizeof(buffer), "%4dy", years); - RichString_appendnAscii(str, yearColor, buffer, len); - len = xSnprintf(buffer, sizeof(buffer), "%2dd ", daysLeft); - RichString_appendnAscii(str, dayColor, buffer, len); - } else { - len = xSnprintf(buffer, sizeof(buffer), "%5dy", years); - RichString_appendnAscii(str, yearColor, buffer, len); - len = xSnprintf(buffer, sizeof(buffer), "%1dd ", daysLeft); - RichString_appendnAscii(str, dayColor, buffer, len); - } - } else if (days >= 100) { - int hoursLeft = hours - days * 24; - - if (hoursLeft >= 10) { - len = xSnprintf(buffer, sizeof(buffer), "%4llud", days); - RichString_appendnAscii(str, dayColor, buffer, len); - len = xSnprintf(buffer, sizeof(buffer), "%2dh ", hoursLeft); - RichString_appendnAscii(str, hourColor, buffer, len); - } else { - len = xSnprintf(buffer, sizeof(buffer), "%5llud", days); - RichString_appendnAscii(str, dayColor, buffer, len); - len = xSnprintf(buffer, sizeof(buffer), "%1dh ", hoursLeft); - RichString_appendnAscii(str, hourColor, buffer, len); - } - } else if (hours >= 100) { - int minutesLeft = totalSeconds / 60 - hours * 60; - - if (minutesLeft >= 10) { - len = xSnprintf(buffer, sizeof(buffer), "%4lluh", hours); - RichString_appendnAscii(str, hourColor, buffer, len); - len = xSnprintf(buffer, sizeof(buffer), "%2dm ", minutesLeft); - RichString_appendnAscii(str, defColor, buffer, len); - } else { - len = xSnprintf(buffer, sizeof(buffer), "%5lluh", hours); - RichString_appendnAscii(str, hourColor, buffer, len); - len = xSnprintf(buffer, sizeof(buffer), "%1dm ", minutesLeft); - RichString_appendnAscii(str, defColor, buffer, len); - } - } else if (hours > 0) { - len = xSnprintf(buffer, sizeof(buffer), "%2lluh", hours); - RichString_appendnAscii(str, hourColor, buffer, len); - len = xSnprintf(buffer, sizeof(buffer), "%02d:%02d ", minutes, seconds); - RichString_appendnAscii(str, defColor, buffer, len); - } else { - len = xSnprintf(buffer, sizeof(buffer), "%2d:%02d.%02d ", minutes, seconds, hundredths); - RichString_appendnAscii(str, defColor, buffer, len); - } -} - void Process_fillStarttimeBuffer(Process* this) { struct tm date; + time_t now = this->super.host->realtime.tv_sec; (void) localtime_r(&this->starttime_ctime, &date); - strftime(this->starttime_show, sizeof(this->starttime_show) - 1, (this->starttime_ctime > (time(NULL) - 86400)) ? "%R " : "%b%d ", &date); + + strftime(this->starttime_show, + sizeof(this->starttime_show) - 1, + (this->starttime_ctime > now - 86400) ? "%R " : (this->starttime_ctime > now - 364 * 86400) ? "%b%d " : " %Y ", + &date); } /* @@ -286,7 +60,7 @@ void Process_fillStarttimeBuffer(Process* this) { * * 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 upto (TASK_COMM_LEN - 1) could be comm. + * implicit that only up to (TASK_COMM_LEN - 1) could be comm. */ #define TASK_COMM_LEN 16 @@ -404,9 +178,8 @@ static inline char* stpcpyWithNewlineConversion(char* dstStr, const char* srcStr * Process_writeCommand() for coloring. The merged Command string is also * returned by Process_getCommand() for searching, sorting and filtering. */ -void Process_makeCommandStr(Process* this) { +void Process_makeCommandStr(Process* this, const Settings* settings) { ProcessMergedCommand* mc = &this->mergedCommand; - const Settings* settings = this->settings; bool showMergedCommand = settings->showMergedCommand; bool showProgramPath = settings->showProgramPath; @@ -433,7 +206,7 @@ void Process_makeCommandStr(Process* this) { mc->lastUpdate = settingsStamp; - /* The field separtor "│" has been chosen such that it will not match any + /* The field separator "│" 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); @@ -674,15 +447,16 @@ void Process_writeCommand(const Process* this, int attr, int baseAttr, RichStrin int strStart = RichString_size(str); - const bool highlightBaseName = this->settings->highlightBaseName; + const Settings* settings = this->super.host->settings; + const bool highlightBaseName = settings->highlightBaseName; const bool highlightSeparator = true; - const bool highlightDeleted = this->settings->highlightDeletedExe; + const bool highlightDeleted = settings->highlightDeletedExe; if (!mergedCommand) { int len = 0; const char* cmdline = this->cmdline; - if (highlightBaseName || !this->settings->showProgramPath) { + if (highlightBaseName || !settings->showProgramPath) { int basename = 0; for (int i = 0; i < this->cmdlineBasenameEnd; i++) { if (cmdline[i] == '/') { @@ -693,7 +467,7 @@ void Process_writeCommand(const Process* this, int attr, int baseAttr, RichStrin } } if (len == 0) { - if (this->settings->showProgramPath) { + if (settings->showProgramPath) { strStart += basename; } else { cmdline += basename; @@ -704,7 +478,7 @@ void Process_writeCommand(const Process* this, int attr, int baseAttr, RichStrin RichString_appendWide(str, attr, cmdline); - if (this->settings->highlightBaseName) { + if (settings->highlightBaseName) { RichString_setAttrn(str, baseAttr, strStart, len); } @@ -739,73 +513,6 @@ void Process_writeCommand(const Process* this, int attr, int baseAttr, RichStrin } } -void Process_printRate(RichString* str, double rate, bool coloring) { - char buffer[16]; - - int largeNumberColor = CRT_colors[LARGE_NUMBER]; - int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES]; - int processColor = CRT_colors[PROCESS]; - int shadowColor = CRT_colors[PROCESS_SHADOW]; - - if (!coloring) { - largeNumberColor = CRT_colors[PROCESS]; - processMegabytesColor = CRT_colors[PROCESS]; - } - - if (isnan(rate)) { - RichString_appendAscii(str, shadowColor, " N/A "); - } else if (rate < 0.005) { - int len = snprintf(buffer, sizeof(buffer), "%7.2f B/s ", rate); - RichString_appendnAscii(str, shadowColor, buffer, len); - } else if (rate < ONE_K) { - int len = snprintf(buffer, sizeof(buffer), "%7.2f B/s ", rate); - RichString_appendnAscii(str, processColor, buffer, len); - } else if (rate < ONE_M) { - int len = snprintf(buffer, sizeof(buffer), "%7.2f K/s ", rate / ONE_K); - RichString_appendnAscii(str, processColor, buffer, len); - } else if (rate < ONE_G) { - int len = snprintf(buffer, sizeof(buffer), "%7.2f M/s ", rate / ONE_M); - RichString_appendnAscii(str, processMegabytesColor, buffer, len); - } else if (rate < ONE_T) { - int len = snprintf(buffer, sizeof(buffer), "%7.2f G/s ", rate / ONE_G); - RichString_appendnAscii(str, largeNumberColor, buffer, len); - } else if (rate < ONE_P) { - int len = snprintf(buffer, sizeof(buffer), "%7.2f T/s ", rate / ONE_T); - RichString_appendnAscii(str, largeNumberColor, buffer, len); - } else { - int len = snprintf(buffer, sizeof(buffer), "%7.2f P/s ", rate / ONE_P); - RichString_appendnAscii(str, largeNumberColor, buffer, len); - } -} - -void Process_printLeftAlignedField(RichString* str, int attr, const char* content, unsigned int width) { - int columns = width; - RichString_appendnWideColumns(str, attr, content, strlen(content), &columns); - RichString_appendChr(str, attr, ' ', width + 1 - columns); -} - -void Process_printPercentage(float val, char* buffer, int n, uint8_t width, int* attr) { - if (val >= 0) { - if (val < 0.05F) - *attr = CRT_colors[PROCESS_SHADOW]; - else if (val >= 99.9F) - *attr = CRT_colors[PROCESS_MEGABYTES]; - - int precision = 1; - - // Display "val" as "100" for columns like "MEM%". - if (width == 4 && val > 99.9F) { - precision = 0; - val = 100.0F; - } - - xSnprintf(buffer, n, "%*.*f ", width, precision, val); - } else { - *attr = CRT_colors[PROCESS_SHADOW]; - xSnprintf(buffer, n, "%*.*s ", width, width, "N/A"); - } -} - static inline char processStateChar(ProcessState state) { switch (state) { case UNKNOWN: return '?'; @@ -828,29 +535,39 @@ static inline char processStateChar(ProcessState state) { } } -void Process_writeField(const Process* this, RichString* str, ProcessField field) { - char buffer[256]; - size_t n = sizeof(buffer); +static void Process_rowWriteField(const Row* super, RichString* str, RowField field) { + const Process* this = (const Process*) super; + assert(Object_isA((const Object*) this, (const ObjectClass*) &Process_class)); + Process_writeField(this, str, field); +} + +void Process_writeField(const Process* this, RichString* str, RowField field) { + const Row* super = (const Row*) &this->super; + const Machine* host = super->host; + const Settings* settings = host->settings; + + bool coloring = settings->highlightMegabytes; + char buffer[256]; buffer[255] = '\0'; int attr = CRT_colors[DEFAULT_COLOR]; - bool coloring = this->settings->highlightMegabytes; + size_t n = sizeof(buffer) - 1; switch (field) { case COMM: { int baseattr = CRT_colors[PROCESS_BASENAME]; - if (this->settings->highlightThreads && Process_isThread(this)) { + if (settings->highlightThreads && Process_isThread(this)) { attr = CRT_colors[PROCESS_THREAD]; baseattr = CRT_colors[PROCESS_THREAD_BASENAME]; } - const ScreenSettings* ss = this->settings->ss; - if (!ss->treeView || this->indent == 0) { + const ScreenSettings* ss = settings->ss; + if (!ss->treeView || super->indent == 0) { Process_writeCommand(this, attr, baseattr, str); return; } char* buf = buffer; - const bool lastItem = (this->indent < 0); + const bool lastItem = (super->indent < 0); - for (uint32_t indent = (this->indent < 0 ? -this->indent : this->indent); indent > 1; indent >>= 1) { + for (uint32_t indent = (super->indent < 0 ? -super->indent : super->indent); indent > 1; indent >>= 1) { int written, ret; if (indent & 1U) { ret = xSnprintf(buf, n, "%s ", CRT_treeStr[TREE_STR_VERT]); @@ -867,7 +584,7 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field } 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] ); + xSnprintf(buf, n, "%s%s ", draw, super->showChildren ? CRT_treeStr[TREE_STR_SHUT] : CRT_treeStr[TREE_STR_OPEN] ); RichString_appendWide(str, CRT_colors[PROCESS_TREE], buffer); Process_writeCommand(this, attr, baseattr, str); return; @@ -882,14 +599,14 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field procComm = Process_isKernelThread(this) ? kthreadID : "N/A"; } - Process_printLeftAlignedField(str, attr, procComm, TASK_COMM_LEN - 1); + Row_printLeftAlignedField(str, attr, procComm, TASK_COMM_LEN - 1); return; } case PROC_EXE: { const char* procExe; if (this->procExe) { attr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_BASENAME : PROCESS_BASENAME]; - if (this->settings->highlightDeletedExe) { + if (settings->highlightDeletedExe) { if (this->procExeDeleted) attr = CRT_colors[FAILED_READ]; else if (this->usesDeletedLib) @@ -901,7 +618,7 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field procExe = Process_isKernelThread(this) ? kthreadID : "N/A"; } - Process_printLeftAlignedField(str, attr, procExe, TASK_COMM_LEN - 1); + Row_printLeftAlignedField(str, attr, procExe, TASK_COMM_LEN - 1); return; } case CWD: { @@ -915,27 +632,27 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field } else { cwd = this->procCwd; } - Process_printLeftAlignedField(str, attr, cwd, 25); + Row_printLeftAlignedField(str, attr, cwd, 25); return; } case ELAPSED: { - const uint64_t rt = this->processList->realtimeMs; + const uint64_t rt = host->realtimeMs; const uint64_t st = this->starttime_ctime * 1000; const uint64_t dt = rt < st ? 0 : rt - st; - Process_printTime(str, /* convert to hundreds of a second */ dt / 10, coloring); + Row_printTime(str, /* convert to hundreds of a second */ dt / 10, coloring); return; } - case MAJFLT: Process_printCount(str, this->majflt, coloring); return; - case MINFLT: Process_printCount(str, this->minflt, coloring); return; - case M_RESIDENT: Process_printKBytes(str, this->m_resident, coloring); return; - case M_VIRT: Process_printKBytes(str, this->m_virt, coloring); return; + case MAJFLT: Row_printCount(str, this->majflt, coloring); return; + case MINFLT: Row_printCount(str, this->minflt, coloring); return; + case M_RESIDENT: Row_printKBytes(str, this->m_resident, coloring); return; + case M_VIRT: Row_printKBytes(str, this->m_virt, coloring); return; case NICE: xSnprintf(buffer, n, "%3ld ", this->nice); attr = this->nice < 0 ? CRT_colors[PROCESS_HIGH_PRIORITY] - : this->nice > 0 ? CRT_colors[PROCESS_LOW_PRIORITY] - : CRT_colors[PROCESS_SHADOW]; + : this->nice > 0 ? CRT_colors[PROCESS_LOW_PRIORITY] + : CRT_colors[PROCESS_SHADOW]; break; case NLWP: if (this->nlwp == 1) @@ -943,61 +660,70 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field xSnprintf(buffer, n, "%4ld ", this->nlwp); break; - case PERCENT_CPU: Process_printPercentage(this->percent_cpu, buffer, n, Process_fieldWidths[PERCENT_CPU], &attr); break; + case PERCENT_CPU: Row_printPercentage(this->percent_cpu, buffer, n, Row_fieldWidths[PERCENT_CPU], &attr); break; case PERCENT_NORM_CPU: { - float cpuPercentage = this->percent_cpu / this->processList->activeCPUs; - Process_printPercentage(cpuPercentage, buffer, n, Process_fieldWidths[PERCENT_CPU], &attr); + float cpuPercentage = this->percent_cpu / host->activeCPUs; + Row_printPercentage(cpuPercentage, buffer, n, Row_fieldWidths[PERCENT_CPU], &attr); break; } - case PERCENT_MEM: Process_printPercentage(this->percent_mem, buffer, n, 4, &attr); break; + case PERCENT_MEM: Row_printPercentage(this->percent_mem, buffer, n, 4, &attr); break; case PGRP: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->pgrp); break; - case PID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->pid); break; - case PPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->ppid); break; + case PID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, Process_getPid(this)); break; + case PPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, Process_getParent(this)); break; case PRIORITY: if (this->priority <= -100) xSnprintf(buffer, n, " RT "); else xSnprintf(buffer, n, "%3ld ", this->priority); break; - case PROCESSOR: xSnprintf(buffer, n, "%3d ", Settings_cpuId(this->settings, this->processor)); break; + case PROCESSOR: xSnprintf(buffer, n, "%3d ", Settings_cpuId(settings, this->processor)); break; + case SCHEDULERPOLICY: { + const char* schedPolStr = "N/A"; +#ifdef SCHEDULER_SUPPORT + if (this->scheduling_policy >= 0) + schedPolStr = Scheduling_formatPolicy(this->scheduling_policy); +#endif + xSnprintf(buffer, n, "%-5s ", schedPolStr); + break; + } case SESSION: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->session); break; case STARTTIME: xSnprintf(buffer, n, "%s", this->starttime_show); break; case STATE: xSnprintf(buffer, n, "%c ", processStateChar(this->state)); switch (this->state) { - case RUNNABLE: - case RUNNING: - case TRACED: - attr = CRT_colors[PROCESS_RUN_STATE]; - break; - - case BLOCKED: - case DEFUNCT: - case STOPPED: - case UNINTERRUPTIBLE_WAIT: - case ZOMBIE: - attr = CRT_colors[PROCESS_D_STATE]; - break; - - case QUEUED: - case WAITING: - case IDLE: - case SLEEPING: - attr = CRT_colors[PROCESS_SHADOW]; - break; - - case UNKNOWN: - case PAGING: - break; + case RUNNABLE: + case RUNNING: + case TRACED: + attr = CRT_colors[PROCESS_RUN_STATE]; + break; + + case BLOCKED: + case DEFUNCT: + case STOPPED: + case UNINTERRUPTIBLE_WAIT: + case ZOMBIE: + attr = CRT_colors[PROCESS_D_STATE]; + break; + + case QUEUED: + case WAITING: + case IDLE: + case SLEEPING: + attr = CRT_colors[PROCESS_SHADOW]; + break; + + case UNKNOWN: + case PAGING: + break; } break; case ST_UID: xSnprintf(buffer, n, "%*d ", Process_uidDigits, this->st_uid); break; - case TIME: Process_printTime(str, this->time, coloring); return; + case TIME: Row_printTime(str, this->time, coloring); return; case TGID: - if (this->tgid == this->pid) + if (Process_getThreadGroup(this) == Process_getPid(this)) attr = CRT_colors[PROCESS_SHADOW]; - xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->tgid); + xSnprintf(buffer, n, "%*d ", Process_pidDigits, Process_getThreadGroup(this)); break; case TPGID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->tpgid); break; case TTY: @@ -1010,11 +736,13 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field } break; case USER: - if (Process_getuid != this->st_uid) + if (this->elevated_priv) + attr = CRT_colors[PROCESS_PRIV]; + else if (host->htopUserId != this->st_uid) attr = CRT_colors[PROCESS_SHADOW]; if (this->user) { - Process_printLeftAlignedField(str, attr, this->user, 10); + Row_printLeftAlignedField(str, attr, this->user, 10); return; } @@ -1027,36 +755,12 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field xSnprintf(buffer, n, "- "); break; } - RichString_appendAscii(str, attr, buffer); -} - -void Process_display(const Object* cast, RichString* out) { - const Process* this = (const Process*) cast; - const ProcessField* fields = this->settings->ss->fields; - for (int i = 0; fields[i]; i++) - As_Process(this)->writeField(this, out, fields[i]); - - if (this->settings->shadowOtherUsers && this->st_uid != Process_getuid) { - RichString_setAttr(out, CRT_colors[PROCESS_SHADOW]); - } - - if (this->tag == true) { - RichString_setAttr(out, CRT_colors[PROCESS_TAG]); - } - - if (this->settings->highlightChanges) { - if (Process_isTomb(this)) { - out->highlightAttr = CRT_colors[PROCESS_TOMB]; - } else if (Process_isNew(this)) { - out->highlightAttr = CRT_colors[PROCESS_NEW]; - } - } - assert(RichString_size(out) > 0); + RichString_appendAscii(str, attr, buffer); } void Process_done(Process* this) { - assert (this != NULL); + assert(this != NULL); free(this->cmdline); free(this->procComm); free(this->procExe); @@ -1069,80 +773,122 @@ void Process_done(Process* this) { * happens on what is displayed - whether comm, full path, basename, etc.. So * this follows Process_writeField(COMM) and Process_writeCommand */ const char* Process_getCommand(const Process* this) { - if ((Process_isUserlandThread(this) && this->settings->showThreadNames) || !this->mergedCommand.str) { + const Settings* settings = this->super.host->settings; + + if ((Process_isUserlandThread(this) && settings->showThreadNames) || !this->mergedCommand.str) { return this->cmdline; } return this->mergedCommand.str; } -const ProcessClass Process_class = { - .super = { - .extends = Class(Object), - .display = Process_display, - .delete = Process_delete, - .compare = Process_compare - }, - .writeField = Process_writeField, -}; +static const char* Process_getSortKey(const Process* this) { + return Process_getCommand(this); +} -void Process_init(Process* this, const Settings* settings) { - this->settings = settings; - this->tag = false; - this->showChildren = true; - this->show = true; - this->updated = false; - this->cmdlineBasenameEnd = -1; - this->st_uid = (uid_t)-1; +const char* Process_rowGetSortKey(Row* super) { + const Process* this = (const Process*) super; + assert(Object_isA((const Object*) this, (const ObjectClass*) &Process_class)); + return Process_getSortKey(this); +} - if (Process_getuid == (uid_t)-1) { - Process_getuid = getuid(); - } +/* Test whether display must highlight this row (if the htop UID matches) */ +static bool Process_isHighlighted(const Process* this) { + const Machine* host = this->super.host; + const Settings* settings = host->settings; + return settings->shadowOtherUsers && this->st_uid != host->htopUserId; } -void Process_toggleTag(Process* this) { - this->tag = !this->tag; +bool Process_rowIsHighlighted(const Row* super) { + const Process* this = (const Process*) super; + assert(Object_isA((const Object*) this, (const ObjectClass*) &Process_class)); + return Process_isHighlighted(this); } -bool Process_isNew(const Process* this) { - assert(this->processList); - if (this->processList->monotonicMs >= this->seenStampMs) { - return this->processList->monotonicMs - this->seenStampMs <= 1000 * (uint64_t)this->processList->settings->highlightDelaySecs; - } +/* Test whether display must follow parent process (if this thread is hidden) */ +static bool Process_isVisible(const Process* p, const Settings* settings) { + if (settings->hideUserlandThreads) + return !Process_isThread(p); + return true; +} + +bool Process_rowIsVisible(const Row* super, const Table* table) { + const Process* this = (const Process*) super; + assert(Object_isA((const Object*) this, (const ObjectClass*) &Process_class)); + return Process_isVisible(this, table->host->settings); +} + +/* Test whether display must filter out this process (various mechanisms) */ +static bool Process_matchesFilter(const Process* this, const Table* table) { + const Machine* host = table->host; + if (host->userId != (uid_t) -1 && this->st_uid != host->userId) + return true; + + const char* incFilter = table->incFilter; + if (incFilter && !String_contains_i(Process_getCommand(this), incFilter, true)) + return true; + + const ProcessTable* pt = (const ProcessTable*) host->activeTable; + assert(Object_isA((const Object*) pt, (const ObjectClass*) &ProcessTable_class)); + if (pt->pidMatchList && !Hashtable_get(pt->pidMatchList, Process_getThreadGroup(this))) + return true; + return false; } -bool Process_isTomb(const Process* this) { - return this->tombStampMs > 0; +bool Process_rowMatchesFilter(const Row* super, const Table* table) { + const Process* this = (const Process*) super; + assert(Object_isA((const Object*) this, (const ObjectClass*) &Process_class)); + return Process_matchesFilter(this, table); } -bool Process_setPriority(Process* this, int priority) { +void Process_init(Process* this, const Machine* host) { + Row_init(&this->super, host); + + this->cmdlineBasenameEnd = -1; + this->st_uid = (uid_t)-1; +} + +static bool Process_setPriority(Process* this, int priority) { if (Settings_isReadonly()) return false; - int old_prio = getpriority(PRIO_PROCESS, this->pid); - int err = setpriority(PRIO_PROCESS, this->pid, priority); + int old_prio = getpriority(PRIO_PROCESS, Process_getPid(this)); + int err = setpriority(PRIO_PROCESS, Process_getPid(this), priority); - if (err == 0 && old_prio != getpriority(PRIO_PROCESS, this->pid)) { + if (err == 0 && old_prio != getpriority(PRIO_PROCESS, Process_getPid(this))) { this->nice = priority; } return (err == 0); } -bool Process_changePriorityBy(Process* this, Arg delta) { +bool Process_rowSetPriority(Row* super, int priority) { + Process* this = (Process*) super; + assert(Object_isA((const Object*) this, (const ObjectClass*) &Process_class)); + return Process_setPriority(this, priority); +} + +bool Process_rowChangePriorityBy(Row* super, Arg delta) { + Process* this = (Process*) super; + assert(Object_isA((const Object*) this, (const ObjectClass*) &Process_class)); return Process_setPriority(this, this->nice + delta.i); } -bool Process_sendSignal(Process* this, Arg sgn) { - return kill(this->pid, sgn.i) == 0; +static bool Process_sendSignal(Process* this, Arg sgn) { + return kill(Process_getPid(this), sgn.i) == 0; +} + +bool Process_rowSendSignal(Row* super, Arg sgn) { + Process* this = (Process*) super; + assert(Object_isA((const Object*) this, (const ObjectClass*) &Process_class)); + return Process_sendSignal(this, sgn); } int Process_compare(const void* v1, const void* v2) { const Process* p1 = (const Process*)v1; const Process* p2 = (const Process*)v2; - const Settings* settings = p1->settings; - const ScreenSettings* ss = settings->ss; + const ScreenSettings* ss = p1->super.host->settings->ss; ProcessField key = ScreenSettings_getActiveSortKey(ss); @@ -1150,18 +896,27 @@ int Process_compare(const void* v1, const void* v2) { // Implement tie-breaker (needed to make tree mode more stable) if (!result) - return SPACESHIP_NUMBER(p1->pid, p2->pid); + return SPACESHIP_NUMBER(Process_getPid(p1), Process_getPid(p2)); return (ScreenSettings_getActiveDirection(ss) == 1) ? result : -result; } +int Process_compareByParent(const Row* r1, const Row* r2) { + int result = Row_compareByParent_Base(r1, r2); + + if (result != 0) + return result; + + return Process_compare(r1, r2); +} + int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField key) { int r; switch (key) { case PERCENT_CPU: case PERCENT_NORM_CPU: - return SPACESHIP_NUMBER(p1->percent_cpu, p2->percent_cpu); + return compareRealNumbers(p1->percent_cpu, p2->percent_cpu); case PERCENT_MEM: return SPACESHIP_NUMBER(p1->m_resident, p2->m_resident); case COMM: @@ -1180,7 +935,7 @@ int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField return SPACESHIP_NULLSTR(p1->procCwd, p2->procCwd); case ELAPSED: r = -SPACESHIP_NUMBER(p1->starttime_ctime, p2->starttime_ctime); - return r != 0 ? r : SPACESHIP_NUMBER(p1->pid, p2->pid); + return r != 0 ? r : SPACESHIP_NUMBER(Process_getPid(p1), Process_getPid(p2)); case MAJFLT: return SPACESHIP_NUMBER(p1->majflt, p2->majflt); case MINFLT: @@ -1196,18 +951,20 @@ int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField case PGRP: return SPACESHIP_NUMBER(p1->pgrp, p2->pgrp); case PID: - return SPACESHIP_NUMBER(p1->pid, p2->pid); + return SPACESHIP_NUMBER(Process_getPid(p1), Process_getPid(p2)); case PPID: - return SPACESHIP_NUMBER(p1->ppid, p2->ppid); + return SPACESHIP_NUMBER(Process_getParent(p1), Process_getParent(p2)); case PRIORITY: return SPACESHIP_NUMBER(p1->priority, p2->priority); case PROCESSOR: return SPACESHIP_NUMBER(p1->processor, p2->processor); + case SCHEDULERPOLICY: + return SPACESHIP_NUMBER(p1->scheduling_policy, p2->scheduling_policy); case SESSION: return SPACESHIP_NUMBER(p1->session, p2->session); case STARTTIME: r = SPACESHIP_NUMBER(p1->starttime_ctime, p2->starttime_ctime); - return r != 0 ? r : SPACESHIP_NUMBER(p1->pid, p2->pid); + return r != 0 ? r : SPACESHIP_NUMBER(Process_getPid(p1), Process_getPid(p2)); case STATE: return SPACESHIP_NUMBER(p1->state, p2->state); case ST_UID: @@ -1215,7 +972,7 @@ int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField case TIME: return SPACESHIP_NUMBER(p1->time, p2->time); case TGID: - return SPACESHIP_NUMBER(p1->tgid, p2->tgid); + return SPACESHIP_NUMBER(Process_getThreadGroup(p1), Process_getThreadGroup(p2)); case TPGID: return SPACESHIP_NUMBER(p1->tpgid, p2->tpgid); case TTY: @@ -1226,7 +983,7 @@ int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField default: CRT_debug("Process_compareByKey_Base() called with key %d", key); assert(0 && "Process_compareByKey_Base: default key reached"); /* should never be reached */ - return SPACESHIP_NUMBER(p1->pid, p2->pid); + return SPACESHIP_NUMBER(Process_getPid(p1), Process_getPid(p2)); } } @@ -1304,36 +1061,33 @@ void Process_updateExe(Process* this, const char* exe) { this->mergedCommand.lastUpdate = 0; } -uint8_t Process_fieldWidths[LAST_PROCESSFIELD] = { 0 }; - -void Process_resetFieldWidths(void) { - for (size_t i = 0; i < LAST_PROCESSFIELD; i++) { - if (!Process_fields[i].autoWidth) - continue; - - size_t len = strlen(Process_fields[i].title); - assert(len <= UINT8_MAX); - Process_fieldWidths[i] = (uint8_t)len; - } -} - -void Process_updateFieldWidth(ProcessField key, size_t width) { - if (width > UINT8_MAX) - Process_fieldWidths[key] = UINT8_MAX; - else if (width > Process_fieldWidths[key]) - Process_fieldWidths[key] = (uint8_t)width; -} - void Process_updateCPUFieldWidths(float percentage) { if (percentage < 99.9F) { - Process_updateFieldWidth(PERCENT_CPU, 4); - Process_updateFieldWidth(PERCENT_NORM_CPU, 4); + Row_updateFieldWidth(PERCENT_CPU, 4); + Row_updateFieldWidth(PERCENT_NORM_CPU, 4); return; } // Add additional two characters, one for "." and another for precision. uint8_t width = ceil(log10(percentage + 0.1)) + 2; - Process_updateFieldWidth(PERCENT_CPU, width); - Process_updateFieldWidth(PERCENT_NORM_CPU, width); + Row_updateFieldWidth(PERCENT_CPU, width); + Row_updateFieldWidth(PERCENT_NORM_CPU, width); } + +const ProcessClass Process_class = { + .super = { + .super = { + .extends = Class(Row), + .display = Row_display, + .delete = Process_delete, + .compare = Process_compare + }, + .isHighlighted = Process_rowIsHighlighted, + .isVisible = Process_rowIsVisible, + .matchesFilter = Process_rowMatchesFilter, + .sortKeyString = Process_rowGetSortKey, + .compareByParent = Process_compareByParent, + .writeField = Process_rowWriteField + }, +}; -- cgit v1.2.3