aboutsummaryrefslogtreecommitdiffstats
path: root/Process.c
diff options
context:
space:
mode:
Diffstat (limited to 'Process.c')
-rw-r--r--Process.c690
1 files changed, 222 insertions, 468 deletions
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 <assert.h>
-#include <limits.h>
#include <math.h>
#include <signal.h>
#include <stdbool.h>
@@ -19,16 +18,18 @@ in the source distribution for its full text.
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#include <unistd.h>
#include <sys/resource.h>
#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
+ },
+};

© 2014-2024 Faster IT GmbH | imprint | privacy policy