From 69f439eff387a6ecb52734e400b297a3c85f2285 Mon Sep 17 00:00:00 2001 From: Daniel Lange Date: Tue, 21 Sep 2021 08:35:19 +0200 Subject: New upstream version 3.1.0 --- ProcessList.c | 153 +++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 104 insertions(+), 49 deletions(-) (limited to 'ProcessList.c') diff --git a/ProcessList.c b/ProcessList.c index 055ad1f..daf871a 100644 --- a/ProcessList.c +++ b/ProcessList.c @@ -11,15 +11,16 @@ in the source distribution for its full text. #include #include -#include "Compat.h" #include "CRT.h" +#include "DynamicColumn.h" #include "Hashtable.h" #include "Macros.h" +#include "Platform.h" #include "Vector.h" #include "XUtils.h" -ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) { +ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* dynamicColumns, Hashtable* pidMatchList, uid_t userId) { this->processes = Vector_new(klass, true, DEFAULT_SIZE); this->processes2 = Vector_new(klass, true, DEFAULT_SIZE); // tree-view auxiliary buffer @@ -29,13 +30,18 @@ ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, Users this->usersTable = usersTable; this->pidMatchList = pidMatchList; + this->dynamicMeters = dynamicMeters; + this->dynamicColumns = dynamicColumns; this->userId = userId; // set later by platform-specific code - this->cpuCount = 0; + this->activeCPUs = 0; + this->existingCPUs = 0; + this->monotonicMs = 0; - this->scanTs = 0; + // always maintain valid realtime timestamps + Platform_gettime_realtime(&this->realtime, &this->realtimeMs); #ifdef HAVE_LIBHWLOC this->topologyOk = false; @@ -79,7 +85,22 @@ void ProcessList_setPanel(ProcessList* this, Panel* panel) { this->panel = panel; } -static const char* alignedProcessFieldTitle(ProcessField field) { +static const char* alignedDynamicColumnTitle(const ProcessList* this, int key) { + const DynamicColumn* column = Hashtable_get(this->dynamicColumns, key); + if (column == NULL) + return "- "; + static char titleBuffer[DYNAMIC_MAX_COLUMN_WIDTH + /* space */ 1 + /* null terminator */ + 1]; + int width = column->width; + if (!width || abs(width) > DYNAMIC_MAX_COLUMN_WIDTH) + width = DYNAMIC_DEFAULT_COLUMN_WIDTH; + xSnprintf(titleBuffer, sizeof(titleBuffer), "%*s", width, column->heading); + return titleBuffer; +} + +static const char* alignedProcessFieldTitle(const ProcessList* this, ProcessField field) { + if (field >= LAST_PROCESSFIELD) + return alignedDynamicColumnTitle(this, field); + const char* title = Process_fields[field].title; if (!title) return "- "; @@ -93,8 +114,8 @@ static const char* alignedProcessFieldTitle(ProcessField field) { return titleBuffer; } -void ProcessList_printHeader(ProcessList* this, RichString* header) { - RichString_prune(header); +void ProcessList_printHeader(const ProcessList* this, RichString* header) { + RichString_rewind(header, RichString_size(header)); const Settings* settings = this->settings; const ProcessField* fields = settings->fields; @@ -111,12 +132,12 @@ void ProcessList_printHeader(ProcessList* this, RichString* header) { color = CRT_colors[PANEL_HEADER_FOCUS]; } - RichString_appendWide(header, color, alignedProcessFieldTitle(fields[i])); + RichString_appendWide(header, color, alignedProcessFieldTitle(this, fields[i])); if (key == fields[i] && RichString_getCharVal(*header, RichString_size(header) - 1) == ' ') { - header->chlen--; // rewind to override space + RichString_rewind(header, 1); // rewind to override space RichString_appendnWide(header, CRT_colors[PANEL_SELECTION_FOCUS], - CRT_treeStr[Settings_getActiveDirection(this->settings) == 1 ? TREE_STR_DESC : TREE_STR_ASC], + CRT_treeStr[Settings_getActiveDirection(this->settings) == 1 ? TREE_STR_ASC : TREE_STR_DESC], 1); } if (COMM == fields[i] && settings->showMergedCommand) { @@ -131,7 +152,7 @@ void ProcessList_add(ProcessList* this, Process* p) { p->processList = this; // highlighting processes found in first scan by first scan marked "far in the past" - p->seenTs = this->scanTs; + p->seenStampMs = this->monotonicMs; Vector_add(this->processes, p); Hashtable_put(this->processTable, p->pid, p); @@ -141,11 +162,11 @@ void ProcessList_add(ProcessList* this, Process* p) { assert(Hashtable_count(this->processTable) == Vector_count(this->processes)); } -void ProcessList_remove(ProcessList* this, Process* p) { +void ProcessList_remove(ProcessList* this, const Process* p) { assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1); assert(Hashtable_get(this->processTable, p->pid) != NULL); - Process* pp = Hashtable_remove(this->processTable, p->pid); + const Process* pp = Hashtable_remove(this->processTable, p->pid); assert(pp == p); (void)pp; pid_t pid = p->pid; @@ -165,14 +186,6 @@ void ProcessList_remove(ProcessList* this, Process* p) { assert(Hashtable_count(this->processTable) == Vector_count(this->processes)); } -Process* ProcessList_get(ProcessList* this, int idx) { - return (Process*)Vector_get(this->processes, idx); -} - -int ProcessList_size(ProcessList* this) { - return Vector_size(this->processes); -} - // ProcessList_updateTreeSetLayer sorts this->displayTreeSet, // relying only on itself. // @@ -202,7 +215,7 @@ static void ProcessList_updateTreeSetLayer(ProcessList* this, unsigned int leftB if (layerSize == 0) return; - Vector* layer = Vector_new(this->processes->type, false, layerSize); + Vector* layer = Vector_new(Vector_type(this->processes), false, layerSize); // Find all processes on the same layer (process with the same `deep` value // and included in a range from `leftBound` to `rightBound`). @@ -311,6 +324,11 @@ static void ProcessList_updateTreeSet(ProcessList* this) { } static void ProcessList_buildTreeBranch(ProcessList* this, pid_t pid, int level, int indent, int direction, bool show, int* node_counter, int* node_index) { + // On OpenBSD the kernel thread 'swapper' has pid 0. + // Do not treat it as root of any tree. + if (pid == 0) + return; + Vector* children = Vector_new(Class(Process), false, DEFAULT_SIZE); for (int i = Vector_size(this->processes) - 1; i >= 0; i--) { @@ -361,15 +379,15 @@ static void ProcessList_buildTreeBranch(ProcessList* this, pid_t pid, int level, } static int ProcessList_treeProcessCompare(const void* v1, const void* v2) { - const Process *p1 = (const Process*)v1; - const Process *p2 = (const Process*)v2; + const Process* p1 = (const Process*)v1; + const Process* p2 = (const Process*)v2; return SPACESHIP_NUMBER(p1->tree_left, p2->tree_left); } static int ProcessList_treeProcessCompareByPID(const void* v1, const void* v2) { - const Process *p1 = (const Process*)v1; - const Process *p2 = (const Process*)v2; + const Process* p1 = (const Process*)v1; + const Process* p2 = (const Process*)v2; return SPACESHIP_NUMBER(p1->pid, p2->pid); } @@ -477,7 +495,7 @@ ProcessField ProcessList_keyAt(const ProcessList* this, int at) { const ProcessField* fields = this->settings->fields; ProcessField field; for (int i = 0; (field = fields[i]); i++) { - int len = strlen(alignedProcessFieldTitle(field)); + int len = strlen(alignedProcessFieldTitle(this, field)); if (at >= x && at <= x + len) { return field; } @@ -494,17 +512,40 @@ void ProcessList_expandTree(ProcessList* this) { } } +void ProcessList_collapseAllBranches(ProcessList* this) { + int size = Vector_size(this->processes); + for (int i = 0; i < size; i++) { + Process* process = (Process*) Vector_get(this->processes, i); + // FreeBSD has pid 0 = kernel and pid 1 = init, so init has tree_depth = 1 + if (process->tree_depth > 0 && process->pid > 1) + process->showChildren = false; + } +} + void ProcessList_rebuildPanel(ProcessList* this) { const char* incFilter = this->incFilter; - int currPos = Panel_getSelectedIndex(this->panel); - int currScrollV = this->panel->scrollV; + const int currPos = Panel_getSelectedIndex(this->panel); + const int currScrollV = this->panel->scrollV; + const int currSize = Panel_size(this->panel); Panel_prune(this->panel); - int size = ProcessList_size(this); + + /* Follow main process if followed a userland thread and threads are now hidden */ + const Settings* settings = this->settings; + if (this->following != -1 && settings->hideUserlandThreads) { + const Process* followedProcess = (const Process*) Hashtable_get(this->processTable, this->following); + if (followedProcess && Process_isThread(followedProcess) && Hashtable_get(this->processTable, followedProcess->tgid) != NULL) { + this->following = followedProcess->tgid; + } + } + + const int processCount = Vector_size(this->processes); int idx = 0; - for (int i = 0; i < size; i++) { - Process* p = ProcessList_get(this, i); + bool foundFollowed = false; + + for (int i = 0; i < processCount; i++) { + Process* p = (Process*) Vector_get(this->processes, i); if ( (!p->show) || (this->userId != (uid_t) -1 && (p->st_uid != this->userId)) @@ -513,31 +554,47 @@ void ProcessList_rebuildPanel(ProcessList* this) { continue; Panel_set(this->panel, idx, (Object*)p); - if ((this->following == -1 && idx == currPos) || (this->following != -1 && p->pid == this->following)) { + + if (this->following != -1 && p->pid == this->following) { + foundFollowed = true; Panel_setSelected(this->panel, idx); this->panel->scrollV = currScrollV; } idx++; } + + if (this->following != -1 && !foundFollowed) { + /* Reset if current followed pid not found */ + this->following = -1; + Panel_setSelectionColor(this->panel, PANEL_SELECTION_FOCUS); + } + + if (this->following == -1) { + /* If the last item was selected, keep the new last item selected */ + if (currPos > 0 && currPos == currSize - 1) + Panel_setSelected(this->panel, Panel_size(this->panel) - 1); + else + Panel_setSelected(this->panel, currPos); + + this->panel->scrollV = currScrollV; + } } Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_New constructor) { Process* proc = (Process*) Hashtable_get(this->processTable, pid); - *preExisting = proc; + *preExisting = proc != NULL; if (proc) { assert(Vector_indexOf(this->processes, proc, Process_pidCompare) != -1); assert(proc->pid == pid); } else { proc = constructor(this->settings); - assert(proc->comm == NULL); + assert(proc->cmdline == NULL); proc->pid = pid; } return proc; } void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate) { - struct timespec now; - // in pause mode only gather global data for meters (CPU/memory/...) if (pauseProcessUpdate) { ProcessList_goThroughEntries(this, true); @@ -558,37 +615,35 @@ void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate) { this->runningTasks = 0; - // set scanTs + // set scan timestamp static bool firstScanDone = false; - if (!firstScanDone) { - this->scanTs = 0; + if (firstScanDone) { + Platform_gettime_monotonic(&this->monotonicMs); + } else { + this->monotonicMs = 0; firstScanDone = true; - } else if (Compat_clock_monotonic_gettime(&now) == 0) { - // save time in millisecond, so with a delay in deciseconds - // there are no irregularities - this->scanTs = 1000 * now.tv_sec + now.tv_nsec / 1000000; } ProcessList_goThroughEntries(this, false); for (int i = Vector_size(this->processes) - 1; i >= 0; i--) { Process* p = (Process*) Vector_get(this->processes, i); - if (p->tombTs > 0) { + Process_makeCommandStr(p); + + if (p->tombStampMs > 0) { // remove tombed process - if (this->scanTs >= p->tombTs) { + if (this->monotonicMs >= p->tombStampMs) { ProcessList_remove(this, p); } } else if (p->updated == false) { // process no longer exists if (this->settings->highlightChanges && p->wasShown) { // mark tombed - p->tombTs = this->scanTs + 1000 * this->settings->highlightDelaySecs; + p->tombStampMs = this->monotonicMs + 1000 * this->settings->highlightDelaySecs; } else { // immediately remove ProcessList_remove(this, p); } - } else { - p->updated = false; } } -- cgit v1.2.3