aboutsummaryrefslogtreecommitdiffstats
path: root/ProcessList.c
diff options
context:
space:
mode:
Diffstat (limited to 'ProcessList.c')
-rw-r--r--ProcessList.c153
1 files changed, 104 insertions, 49 deletions
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 <stdlib.h>
#include <string.h>
-#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;
}
}

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