aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Lange <DLange@git.local>2021-01-11 20:43:28 +0100
committerDaniel Lange <DLange@git.local>2021-01-11 20:43:28 +0100
commit94123a215ba971baf4ad7e12cc479258ddb8600e (patch)
tree6f053d8e1ce754ab7104b7364be9754231ab84de
parent50cb99f0acecb15992f3d5610c02676a6c94f2a4 (diff)
parentc55320e9e2a8916e911bcd39ab37b79e3a7d03b2 (diff)
downloaddebian_htop-94123a215ba971baf4ad7e12cc479258ddb8600e.tar.gz
debian_htop-94123a215ba971baf4ad7e12cc479258ddb8600e.tar.bz2
debian_htop-94123a215ba971baf4ad7e12cc479258ddb8600e.zip
Update upstream source from tag 'upstream/3.0.5'
Update to upstream version '3.0.5' with Debian dir 10922042e094a59dc72f9c39ddd4bfd59c7a302c
-rw-r--r--.github/workflows/ci.yml26
-rw-r--r--.travis.yml11
-rw-r--r--Action.c152
-rw-r--r--Action.h4
-rw-r--r--AffinityPanel.c33
-rw-r--r--AvailableColumnsPanel.c2
-rw-r--r--AvailableMetersPanel.c1
-rw-r--r--BatteryMeter.c29
-rw-r--r--CPUMeter.c52
-rw-r--r--CRT.c138
-rw-r--r--CRT.h23
-rw-r--r--ChangeLog56
-rw-r--r--ColorsPanel.c19
-rw-r--r--ColumnsPanel.c2
-rw-r--r--CommandScreen.c6
-rw-r--r--Compat.c34
-rw-r--r--Compat.h2
-rw-r--r--DiskIOMeter.c12
-rw-r--r--DisplayOptionsPanel.c2
-rw-r--r--EnvScreen.c24
-rw-r--r--EnvScreen.h4
-rw-r--r--FunctionBar.c7
-rw-r--r--Hashtable.c90
-rw-r--r--Hashtable.h30
-rw-r--r--IncSet.c43
-rw-r--r--IncSet.h4
-rw-r--r--InfoScreen.c21
-rw-r--r--InfoScreen.h1
-rw-r--r--ListItem.c6
-rw-r--r--LoadAverageMeter.c50
-rw-r--r--MainPanel.c57
-rw-r--r--MainPanel.h2
-rw-r--r--Makefile.am26
-rw-r--r--MemoryMeter.c24
-rw-r--r--Meter.c66
-rw-r--r--Meter.h1
-rw-r--r--MetersPanel.c13
-rw-r--r--NetworkIOMeter.c16
-rw-r--r--Object.h2
-rw-r--r--OpenFilesScreen.c2
-rw-r--r--OptionItem.c20
-rw-r--r--Panel.c90
-rw-r--r--Panel.h35
-rw-r--r--Process.c170
-rw-r--r--Process.h39
-rw-r--r--ProcessList.c94
-rw-r--r--ProcessLocksScreen.c2
-rw-r--r--RichString.c73
-rw-r--r--RichString.h14
-rw-r--r--ScreenManager.c36
-rw-r--r--Settings.c38
-rw-r--r--Settings.h16
-rw-r--r--SignalsPanel.c2
-rw-r--r--SwapMeter.c12
-rw-r--r--TasksMeter.c20
-rw-r--r--TraceScreen.c34
-rw-r--r--TraceScreen.h6
-rw-r--r--Vector.h2
-rw-r--r--XUtils.c22
-rw-r--r--XUtils.h4
-rw-r--r--configure.ac68
-rw-r--r--darwin/DarwinProcess.c106
-rw-r--r--darwin/DarwinProcess.h5
-rw-r--r--darwin/DarwinProcessList.c21
-rw-r--r--darwin/Platform.c99
-rw-r--r--darwin/Platform.h9
-rw-r--r--darwin/ProcessField.h16
-rw-r--r--dragonflybsd/DragonFlyBSDProcess.c88
-rw-r--r--dragonflybsd/DragonFlyBSDProcess.h15
-rw-r--r--dragonflybsd/DragonFlyBSDProcessList.c37
-rw-r--r--dragonflybsd/DragonFlyBSDProcessList.h8
-rw-r--r--dragonflybsd/Platform.c4
-rw-r--r--dragonflybsd/Platform.h5
-rw-r--r--dragonflybsd/ProcessField.h17
-rw-r--r--freebsd/FreeBSDProcess.c66
-rw-r--r--freebsd/FreeBSDProcess.h11
-rw-r--r--freebsd/FreeBSDProcessList.c21
-rw-r--r--freebsd/Platform.c4
-rw-r--r--freebsd/Platform.h6
-rw-r--r--freebsd/ProcessField.h17
-rw-r--r--htop.1.in68
-rw-r--r--htop.c22
-rw-r--r--iwyu/htop.imp2
-rw-r--r--linux/IOPriorityPanel.c2
-rw-r--r--linux/LibSensors.c81
-rw-r--r--linux/LibSensors.h2
-rw-r--r--linux/LinuxProcess.c177
-rw-r--r--linux/LinuxProcess.h97
-rw-r--r--linux/LinuxProcessList.c164
-rw-r--r--linux/Platform.c4
-rw-r--r--linux/Platform.h4
-rw-r--r--linux/PressureStallMeter.c18
-rw-r--r--linux/ProcessField.h53
-rw-r--r--linux/SELinuxMeter.c2
-rw-r--r--linux/SystemdMeter.c20
-rw-r--r--linux/ZramMeter.c14
-rw-r--r--openbsd/OpenBSDProcess.c59
-rw-r--r--openbsd/OpenBSDProcess.h9
-rw-r--r--openbsd/OpenBSDProcessList.c27
-rw-r--r--openbsd/Platform.c4
-rw-r--r--openbsd/Platform.h6
-rw-r--r--openbsd/ProcessField.h15
-rw-r--r--solaris/Platform.c8
-rw-r--r--solaris/Platform.h7
-rw-r--r--solaris/ProcessField.h22
-rw-r--r--solaris/SolarisProcess.c106
-rw-r--r--solaris/SolarisProcess.h20
-rw-r--r--solaris/SolarisProcessList.c76
-rw-r--r--solaris/SolarisProcessList.h1
-rw-r--r--unsupported/Platform.c37
-rw-r--r--unsupported/Platform.h10
-rw-r--r--unsupported/ProcessField.h15
-rw-r--r--unsupported/UnsupportedProcess.c27
-rw-r--r--unsupported/UnsupportedProcess.h2
-rw-r--r--zfs/ZfsArcMeter.c44
-rw-r--r--zfs/ZfsCompressedArcMeter.c22
116 files changed, 2033 insertions, 1659 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e416c67..5de7c19 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,6 +2,11 @@ name: CI
on: [ push, pull_request ]
+env:
+ # Enable format attributes in ncurses headers
+ # Enable fortified memory/string handling
+ CPPFLAGS: -DGCC_PRINTF -DGCC_SCANF -D_FORTIFY_SOURCE=2
+
jobs:
build-ubuntu-latest-minimal-gcc:
runs-on: ubuntu-latest
@@ -47,6 +52,10 @@ jobs:
build-ubuntu-latest-full-featured-gcc:
runs-on: ubuntu-latest
+ # Enable LTO, might trigger additional warnings on advanced inlining
+ env:
+ CFLAGS: -O3 -g -flto
+ LDFLAGS: -O3 -g -flto
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
@@ -102,6 +111,23 @@ jobs:
- name: Build
run: scan-build-11 -analyze-headers --status-bugs make -j"$(nproc)"
+ build-macos-latest-clang:
+ runs-on: macOS-latest
+ env:
+ CC: clang
+ steps:
+ - uses: actions/checkout@v2
+ - name: Install Dependencies
+ run: brew install automake
+ - name: Bootstrap
+ run: ./autogen.sh
+ - name: Configure
+ run: ./configure --enable-werror
+ - name: Build
+ run: make -k
+ - name: Distcheck
+ run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror"
+
whitespace_check:
runs-on: ubuntu-latest
steps:
diff --git a/.travis.yml b/.travis.yml
index bb79560..2c79fa8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,17 +6,6 @@ compiler:
os:
- freebsd
- - linux
- - osx
-
-arch:
- - amd64
- - s390x
-
-before_script:
- if [[ ${TRAVIS_CPU_ARCH} == 's390x' ]]; then
- sudo apt-get update && sudo apt-get install -y libncursesw5-dev ;
- fi
script:
- ./autogen.sh
diff --git a/Action.c b/Action.c
index 66934be..88ccf6d 100644
--- a/Action.c
+++ b/Action.c
@@ -104,7 +104,7 @@ static bool changePriority(MainPanel* panel, int delta) {
return anyTagged;
}
-static void addUserToVector(hkey_t key, void* userCast, void* panelCast) {
+static void addUserToVector(ht_key_t key, void* userCast, void* panelCast) {
const char* user = userCast;
Panel* panel = panelCast;
Panel_add(panel, (Object*) ListItem_new(user, key));
@@ -158,20 +158,21 @@ static bool collapseIntoParent(Panel* panel) {
}
Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey) {
- settings->sortKey = sortKey;
- settings->direction = 1;
+ Settings_setSortKey(settings, sortKey);
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_UPDATE_PANELHDR | HTOP_KEEP_FOLLOWING;
}
-static Htop_Reaction sortBy(State* st) {
+// ----------------------------------------
+
+static Htop_Reaction actionSetSortColumn(State* st) {
Htop_Reaction reaction = HTOP_OK;
- Panel* sortPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem), FunctionBar_newEnterEsc("Sort ", "Cancel "));
+ Panel* sortPanel = Panel_new(0, 0, 0, 0, Class(ListItem), true, FunctionBar_newEnterEsc("Sort ", "Cancel "));
Panel_setHeader(sortPanel, "Sort by");
ProcessField* fields = st->settings->fields;
for (int i = 0; fields[i]; i++) {
char* name = String_trim(Process_fields[fields[i]].name);
Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i]));
- if (fields[i] == st->settings->sortKey)
+ if (fields[i] == Settings_getActiveSortKey(st->settings))
Panel_setSelected(sortPanel, i);
free(name);
@@ -188,12 +189,8 @@ static Htop_Reaction sortBy(State* st) {
return reaction | HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}
-// ----------------------------------------
-
-static Htop_Reaction actionResize(State* st) {
- clear();
- Panel_resize(st->panel, COLS, LINES - (st->panel->y) - 1);
- return HTOP_REDRAW_BAR;
+static Htop_Reaction actionSortByPID(State* st) {
+ return Action_setSortKey(st->settings, PID);
}
static Htop_Reaction actionSortByMemory(State* st) {
@@ -231,7 +228,7 @@ static Htop_Reaction actionToggleMergedCommand(State* st) {
static Htop_Reaction actionToggleTreeView(State* st) {
st->settings->treeView = !st->settings->treeView;
if (st->settings->treeView) {
- st->settings->direction = 1;
+ st->settings->treeDirection = 1;
}
ProcessList_expandTree(st->pl);
@@ -251,16 +248,6 @@ static Htop_Reaction actionIncSearch(State* st) {
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
}
-static Htop_Reaction actionIncNext(State* st) {
- IncSet_next(((MainPanel*)st->panel)->inc, INC_SEARCH, st->panel, (IncMode_GetPanelValue) MainPanel_getValue);
- return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
-}
-
-static Htop_Reaction actionIncPrev(State* st) {
- IncSet_prev(((MainPanel*)st->panel)->inc, INC_SEARCH, st->panel, (IncMode_GetPanelValue) MainPanel_getValue);
- return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
-}
-
static Htop_Reaction actionHigherPriority(State* st) {
bool changed = changePriority((MainPanel*)st->panel, -1);
return changed ? HTOP_REFRESH : HTOP_OK;
@@ -273,13 +260,11 @@ static Htop_Reaction actionLowerPriority(State* st) {
static Htop_Reaction actionInvertSortOrder(State* st) {
Settings_invertSortOrder(st->settings);
+ if (st->pauseProcessUpdate)
+ ProcessList_sort(st->pl);
return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
}
-static Htop_Reaction actionSetSortColumn(State* st) {
- return sortBy(st);
-}
-
static Htop_Reaction actionExpandOrCollapse(State* st) {
bool changed = expandCollapse(st->panel);
return changed ? HTOP_RECALCULATE : HTOP_OK;
@@ -340,7 +325,7 @@ static Htop_Reaction actionKill(State* st) {
if (sgn) {
if (sgn->key != 0) {
Panel_setHeader(st->panel, "Sending...");
- Panel_draw(st->panel, true, true);
+ Panel_draw(st->panel, false, true, true, State_hideFunctionBar(st));
refresh();
MainPanel_foreachProcess((MainPanel*)st->panel, Process_sendSignal, (Arg) { .i = sgn->key }, NULL);
napms(500);
@@ -351,7 +336,7 @@ static Htop_Reaction actionKill(State* st) {
}
static Htop_Reaction actionFilterByUser(State* st) {
- Panel* usersPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem), FunctionBar_newEnterEsc("Show ", "Cancel "));
+ Panel* usersPanel = Panel_new(0, 0, 0, 0, Class(ListItem), true, FunctionBar_newEnterEsc("Show ", "Cancel "));
Panel_setHeader(usersPanel, "Show processes of:");
UsersTable_foreach(st->ut, addUserToVector, usersPanel);
Vector_insertionSort(usersPanel->items);
@@ -371,7 +356,7 @@ static Htop_Reaction actionFilterByUser(State* st) {
Htop_Reaction Action_follow(State* st) {
st->pl->following = MainPanel_selectedPid((MainPanel*)st->panel);
- Panel_setSelectionColor(st->panel, CRT_colors[PANEL_SELECTION_FOLLOW]);
+ Panel_setSelectionColor(st->panel, PANEL_SELECTION_FOLLOW);
return HTOP_KEEP_FOLLOWING;
}
@@ -460,8 +445,8 @@ static const struct {
{ .key = " H: ", .info = "hide/show user process threads" },
{ .key = " K: ", .info = "hide/show kernel threads" },
{ .key = " F: ", .info = "cursor follows process" },
- { .key = " F6 + -: ", .info = "expand/collapse tree" },
- { .key = " P M T: ", .info = "sort by CPU%, MEM% or TIME" },
+ { .key = " + -: ", .info = "expand/collapse tree" },
+ { .key = "N P M T: ", .info = "sort by PID, CPU%, MEM% or TIME" },
{ .key = " I: ", .info = "invert sort order" },
{ .key = " F6 > .: ", .info = "select sort column" },
{ .key = NULL, .info = NULL }
@@ -562,24 +547,24 @@ static Htop_Reaction actionHelp(State* st) {
int item;
for (item = 0; helpLeft[item].key; item++) {
attrset(CRT_colors[DEFAULT_COLOR]);
- mvaddstr(line + item, 9, helpLeft[item].info);
+ mvaddstr(line + item, 10, helpLeft[item].info);
attrset(CRT_colors[HELP_BOLD]);
- mvaddstr(line + item, 0, helpLeft[item].key);
+ mvaddstr(line + item, 1, helpLeft[item].key);
if (String_eq(helpLeft[item].key, " H: ")) {
attrset(CRT_colors[PROCESS_THREAD]);
- mvaddstr(line + item, 32, "threads");
+ mvaddstr(line + item, 33, "threads");
} else if (String_eq(helpLeft[item].key, " K: ")) {
attrset(CRT_colors[PROCESS_THREAD]);
- mvaddstr(line + item, 26, "threads");
+ mvaddstr(line + item, 27, "threads");
}
}
int leftHelpItems = item;
for (item = 0; helpRight[item].key; item++) {
attrset(CRT_colors[HELP_BOLD]);
- mvaddstr(line + item, 40, helpRight[item].key);
+ mvaddstr(line + item, 41, helpRight[item].key);
attrset(CRT_colors[DEFAULT_COLOR]);
- mvaddstr(line + item, 49, helpRight[item].info);
+ mvaddstr(line + item, 50, helpRight[item].info);
}
line += MAXIMUM(leftHelpItems, item);
line++;
@@ -638,60 +623,57 @@ static Htop_Reaction actionShowCommandScreen(State* st) {
}
void Action_setBindings(Htop_Action* keys) {
- keys[KEY_RESIZE] = actionResize;
- keys['M'] = actionSortByMemory;
- keys['T'] = actionSortByTime;
- keys['P'] = actionSortByCPU;
- keys['H'] = actionToggleUserlandThreads;
- keys['K'] = actionToggleKernelThreads;
- keys['p'] = actionToggleProgramPath;
- keys['m'] = actionToggleMergedCommand;
- keys['t'] = actionToggleTreeView;
- keys[KEY_F(5)] = actionToggleTreeView;
- keys[KEY_F(4)] = actionIncFilter;
- keys['\\'] = actionIncFilter;
- keys[KEY_F(3)] = actionIncSearch;
- keys['/'] = actionIncSearch;
- keys['n'] = actionIncNext;
- keys['N'] = actionIncPrev;
-
- keys[']'] = actionHigherPriority;
- keys[KEY_F(7)] = actionHigherPriority;
- keys['['] = actionLowerPriority;
- keys[KEY_F(8)] = actionLowerPriority;
- keys['I'] = actionInvertSortOrder;
- keys[KEY_F(6)] = actionSetSortColumn;
- keys[KEY_F(18)] = actionExpandCollapseOrSortColumn;
- keys['<'] = actionSetSortColumn;
+ keys[' '] = actionTag;
+ keys['+'] = actionExpandOrCollapse;
keys[','] = actionSetSortColumn;
- keys['>'] = actionSetSortColumn;
+ keys['-'] = actionExpandOrCollapse;
keys['.'] = actionSetSortColumn;
- keys[KEY_F(10)] = actionQuit;
- keys['q'] = actionQuit;
- keys['a'] = actionSetAffinity;
- keys[KEY_F(9)] = actionKill;
- keys['k'] = actionKill;
- keys[KEY_RECLICK] = actionExpandOrCollapse;
- keys['+'] = actionExpandOrCollapse;
+ keys['/'] = actionIncSearch;
+ keys['<'] = actionSetSortColumn;
keys['='] = actionExpandOrCollapse;
- keys['-'] = actionExpandOrCollapse;
- keys['\177'] = actionCollapseIntoParent;
- keys['u'] = actionFilterByUser;
+ keys['>'] = actionSetSortColumn;
+ keys['?'] = actionHelp;
+ keys['C'] = actionSetup;
keys['F'] = Action_follow;
+ keys['H'] = actionToggleUserlandThreads;
+ keys['I'] = actionInvertSortOrder;
+ keys['K'] = actionToggleKernelThreads;
+ keys['M'] = actionSortByMemory;
+ keys['N'] = actionSortByPID;
+ keys['P'] = actionSortByCPU;
keys['S'] = actionSetup;
- keys['C'] = actionSetup;
- keys[KEY_F(2)] = actionSetup;
- keys['x'] = actionShowLocks;
- keys['l'] = actionLsof;
- keys['s'] = actionStrace;
- keys[' '] = actionTag;
- keys['\014'] = actionRedraw; // Ctrl+L
- keys[KEY_F(1)] = actionHelp;
- keys['h'] = actionHelp;
- keys['?'] = actionHelp;
+ keys['T'] = actionSortByTime;
keys['U'] = actionUntagAll;
+ keys['Z'] = actionTogglePauseProcessUpdate;
+ keys['['] = actionLowerPriority;
+ keys['\014'] = actionRedraw; // Ctrl+L
+ keys['\177'] = actionCollapseIntoParent;
+ keys['\\'] = actionIncFilter;
+ keys[']'] = actionHigherPriority;
+ keys['a'] = actionSetAffinity;
keys['c'] = actionTagAllChildren;
keys['e'] = actionShowEnvScreen;
+ keys['h'] = actionHelp;
+ keys['k'] = actionKill;
+ keys['l'] = actionLsof;
+ keys['m'] = actionToggleMergedCommand;
+ keys['p'] = actionToggleProgramPath;
+ keys['q'] = actionQuit;
+ keys['s'] = actionStrace;
+ keys['t'] = actionToggleTreeView;
+ keys['u'] = actionFilterByUser;
keys['w'] = actionShowCommandScreen;
- keys['Z'] = actionTogglePauseProcessUpdate;
+ keys['x'] = actionShowLocks;
+ keys[KEY_F(1)] = actionHelp;
+ keys[KEY_F(2)] = actionSetup;
+ keys[KEY_F(3)] = actionIncSearch;
+ keys[KEY_F(4)] = actionIncFilter;
+ keys[KEY_F(5)] = actionToggleTreeView;
+ keys[KEY_F(6)] = actionSetSortColumn;
+ keys[KEY_F(7)] = actionHigherPriority;
+ keys[KEY_F(8)] = actionLowerPriority;
+ keys[KEY_F(9)] = actionKill;
+ keys[KEY_F(10)] = actionQuit;
+ keys[KEY_F(18)] = actionExpandCollapseOrSortColumn;
+ keys[KEY_RECLICK] = actionExpandOrCollapse;
}
diff --git a/Action.h b/Action.h
index 1251911..02d9030 100644
--- a/Action.h
+++ b/Action.h
@@ -41,6 +41,10 @@ typedef struct State_ {
bool hideProcessSelection;
} State;
+static inline bool State_hideFunctionBar(const State* st) {
+ return st->settings->hideFunctionBar == 2 || (st->settings->hideFunctionBar == 1 && st->hideProcessSelection);
+}
+
typedef Htop_Reaction (*Htop_Action)(State* st);
Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess);
diff --git a/AffinityPanel.c b/AffinityPanel.c
index e491b52..a4d6361 100644
--- a/AffinityPanel.c
+++ b/AffinityPanel.c
@@ -59,25 +59,25 @@ static void MaskItem_delete(Object* cast) {
static void MaskItem_display(const Object* cast, RichString* out) {
const MaskItem* this = (const MaskItem*)cast;
assert (this != NULL);
- RichString_append(out, CRT_colors[CHECK_BOX], "[");
+ RichString_appendAscii(out, CRT_colors[CHECK_BOX], "[");
if (this->value == 2) {
- RichString_append(out, CRT_colors[CHECK_MARK], "x");
+ RichString_appendAscii(out, CRT_colors[CHECK_MARK], "x");
} else if (this->value == 1) {
- RichString_append(out, CRT_colors[CHECK_MARK], "o");
+ RichString_appendAscii(out, CRT_colors[CHECK_MARK], "o");
} else {
- RichString_append(out, CRT_colors[CHECK_MARK], " ");
+ RichString_appendAscii(out, CRT_colors[CHECK_MARK], " ");
}
- RichString_append(out, CRT_colors[CHECK_BOX], "]");
- RichString_append(out, CRT_colors[CHECK_TEXT], " ");
+ RichString_appendAscii(out, CRT_colors[CHECK_BOX], "]");
+ RichString_appendAscii(out, CRT_colors[CHECK_TEXT], " ");
if (this->indent) {
- RichString_append(out, CRT_colors[PROCESS_TREE], this->indent);
- RichString_append(out, CRT_colors[PROCESS_TREE],
- this->sub_tree == 2
- ? CRT_treeStr[TREE_STR_OPEN]
- : CRT_treeStr[TREE_STR_SHUT]);
- RichString_append(out, CRT_colors[CHECK_TEXT], " ");
+ RichString_appendWide(out, CRT_colors[PROCESS_TREE], this->indent);
+ RichString_appendWide(out, CRT_colors[PROCESS_TREE],
+ this->sub_tree == 2
+ ? CRT_treeStr[TREE_STR_OPEN]
+ : CRT_treeStr[TREE_STR_SHUT]);
+ RichString_appendAscii(out, CRT_colors[CHECK_TEXT], " ");
}
- RichString_append(out, CRT_colors[CHECK_TEXT], this->text);
+ RichString_appendWide(out, CRT_colors[CHECK_TEXT], this->text);
}
static const ObjectClass MaskItem_class = {
@@ -173,7 +173,6 @@ static void AffinityPanel_update(AffinityPanel* this, bool keepSelected) {
Panel* super = (Panel*) this;
FunctionBar_setLabel(super->currentBar, KEY_F(3), this->topoView ? "Collapse/Expand" : "");
- FunctionBar_draw(super->currentBar);
int oldSelected = Panel_getSelectedIndex(super);
Panel_prune(super);
@@ -281,7 +280,7 @@ static MaskItem* AffinityPanel_addObject(AffinityPanel* this, hwloc_obj_t obj, u
indent_buf[0] = '\0';
if (depth > 0) {
for (unsigned i = 1; i < depth; i++) {
- xSnprintf(&indent_buf[off], left, "%s ", (indent & (1u << i)) ? CRT_treeStr[TREE_STR_VERT] : " ");
+ xSnprintf(&indent_buf[off], left, "%s ", (indent & (1U << i)) ? CRT_treeStr[TREE_STR_VERT] : " ");
size_t len = strlen(&indent_buf[off]);
off += len;
left -= len;
@@ -323,9 +322,9 @@ static MaskItem* AffinityPanel_addObject(AffinityPanel* this, hwloc_obj_t obj, u
static MaskItem* AffinityPanel_buildTopology(AffinityPanel* this, hwloc_obj_t obj, unsigned indent, MaskItem* parent) {
MaskItem* item = AffinityPanel_addObject(this, obj, indent, parent);
if (obj->next_sibling) {
- indent |= (1u << obj->depth);
+ indent |= (1U << obj->depth);
} else {
- indent &= ~(1u << obj->depth);
+ indent &= ~(1U << obj->depth);
}
for (unsigned i = 0; i < obj->arity; i++) {
diff --git a/AvailableColumnsPanel.c b/AvailableColumnsPanel.c
index 8945bd2..fb0357c 100644
--- a/AvailableColumnsPanel.c
+++ b/AvailableColumnsPanel.c
@@ -77,7 +77,7 @@ AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns) {
Panel_setHeader(super, "Available Columns");
- for (int i = 1; i < Platform_numberOfFields; i++) {
+ for (int i = 1; i < LAST_PROCESSFIELD; i++) {
if (i != COMM && Process_fields[i].description) {
char description[256];
xSnprintf(description, sizeof(description), "%s - %s", Process_fields[i].name, Process_fields[i].description);
diff --git a/AvailableMetersPanel.c b/AvailableMetersPanel.c
index ce01255..7c82229 100644
--- a/AvailableMetersPanel.c
+++ b/AvailableMetersPanel.c
@@ -35,7 +35,6 @@ static inline void AvailableMetersPanel_addMeter(Header* header, Panel* panel, c
Panel_add(panel, (Object*) Meter_toListItem(meter, false));
Panel_setSelected(panel, Panel_size(panel) - 1);
MetersPanel_setMoving((MetersPanel*)panel, true);
- FunctionBar_draw(panel->currentBar);
}
static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
diff --git a/BatteryMeter.c b/BatteryMeter.c
index 4836809..2c808c7 100644
--- a/BatteryMeter.c
+++ b/BatteryMeter.c
@@ -35,24 +35,21 @@ static void BatteryMeter_updateValues(Meter* this, char* buffer, size_t len) {
this->values[0] = percent;
- const char *onAcText, *onBatteryText, *unknownText;
-
- unknownText = "%.1f%%";
- if (this->mode == TEXT_METERMODE) {
- onAcText = "%.1f%% (Running on A/C)";
- onBatteryText = "%.1f%% (Running on battery)";
- } else {
- onAcText = "%.1f%%(A/C)";
- onBatteryText = "%.1f%%(bat)";
+ const char* text;
+ switch (isOnAC) {
+ case AC_PRESENT:
+ text = this->mode == TEXT_METERMODE ? " (Running on A/C)" : "(A/C)";
+ break;
+ case AC_ABSENT:
+ text = this->mode == TEXT_METERMODE ? " (Running on battery)" : "(bat)";
+ break;
+ case AC_ERROR:
+ default:
+ text = "";
+ break;
}
- if (isOnAC == AC_PRESENT) {
- xSnprintf(buffer, len, onAcText, percent);
- } else if (isOnAC == AC_ABSENT) {
- xSnprintf(buffer, len, onBatteryText, percent);
- } else {
- xSnprintf(buffer, len, unknownText, percent);
- }
+ xSnprintf(buffer, len, "%.1f%%%s", percent, text);
}
const MeterClass BatteryMeter_class = {
diff --git a/CPUMeter.c b/CPUMeter.c
index 97fc3f0..d84e4db 100644
--- a/CPUMeter.c
+++ b/CPUMeter.c
@@ -67,7 +67,7 @@ static void CPUMeter_updateValues(Meter* this, char* buffer, size_t size) {
double percent = Platform_setCPUValues(this, cpu);
if (this->pl->settings->showCPUUsage) {
- xSnprintf(cpuUsageBuffer, sizeof(cpuUsageBuffer), "%5.1f%%", percent);
+ xSnprintf(cpuUsageBuffer, sizeof(cpuUsageBuffer), "%.1f%%", percent);
}
if (this->pl->settings->showCPUFrequency) {
@@ -104,49 +104,49 @@ static void CPUMeter_display(const Object* cast, RichString* out) {
const Meter* this = (const Meter*)cast;
RichString_prune(out);
if (this->param > this->pl->cpuCount) {
- RichString_append(out, CRT_colors[METER_TEXT], "absent");
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], "absent");
return;
}
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NORMAL]);
- RichString_append(out, CRT_colors[METER_TEXT], ":");
- RichString_append(out, CRT_colors[CPU_NORMAL], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], ":");
+ RichString_appendAscii(out, CRT_colors[CPU_NORMAL], buffer);
if (this->pl->settings->detailedCPUTime) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
- RichString_append(out, CRT_colors[METER_TEXT], "sy:");
- RichString_append(out, CRT_colors[CPU_SYSTEM], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], "sy:");
+ RichString_appendAscii(out, CRT_colors[CPU_SYSTEM], buffer);
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
- RichString_append(out, CRT_colors[METER_TEXT], "ni:");
- RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], "ni:");
+ RichString_appendAscii(out, CRT_colors[CPU_NICE_TEXT], buffer);
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]);
- RichString_append(out, CRT_colors[METER_TEXT], "hi:");
- RichString_append(out, CRT_colors[CPU_IRQ], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], "hi:");
+ RichString_appendAscii(out, CRT_colors[CPU_IRQ], buffer);
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_SOFTIRQ]);
- RichString_append(out, CRT_colors[METER_TEXT], "si:");
- RichString_append(out, CRT_colors[CPU_SOFTIRQ], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], "si:");
+ RichString_appendAscii(out, CRT_colors[CPU_SOFTIRQ], buffer);
if (!isnan(this->values[CPU_METER_STEAL])) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_STEAL]);
- RichString_append(out, CRT_colors[METER_TEXT], "st:");
- RichString_append(out, CRT_colors[CPU_STEAL], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], "st:");
+ RichString_appendAscii(out, CRT_colors[CPU_STEAL], buffer);
}
if (!isnan(this->values[CPU_METER_GUEST])) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_GUEST]);
- RichString_append(out, CRT_colors[METER_TEXT], "gu:");
- RichString_append(out, CRT_colors[CPU_GUEST], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], "gu:");
+ RichString_appendAscii(out, CRT_colors[CPU_GUEST], buffer);
}
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IOWAIT]);
- RichString_append(out, CRT_colors[METER_TEXT], "wa:");
- RichString_append(out, CRT_colors[CPU_IOWAIT], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], "wa:");
+ RichString_appendAscii(out, CRT_colors[CPU_IOWAIT], buffer);
} else {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
- RichString_append(out, CRT_colors[METER_TEXT], "sys:");
- RichString_append(out, CRT_colors[CPU_SYSTEM], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], "sys:");
+ RichString_appendAscii(out, CRT_colors[CPU_SYSTEM], buffer);
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
- RichString_append(out, CRT_colors[METER_TEXT], "low:");
- RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], "low:");
+ RichString_appendAscii(out, CRT_colors[CPU_NICE_TEXT], buffer);
if (!isnan(this->values[CPU_METER_IRQ])) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]);
- RichString_append(out, CRT_colors[METER_TEXT], "vir:");
- RichString_append(out, CRT_colors[CPU_GUEST], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], "vir:");
+ RichString_appendAscii(out, CRT_colors[CPU_GUEST], buffer);
}
}
@@ -161,8 +161,8 @@ static void CPUMeter_display(const Object* cast, RichString* out) {
} else {
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sC", cpuTemperature, CRT_degreeSign);
}
- RichString_append(out, CRT_colors[METER_TEXT], "temp:");
- RichString_append(out, CRT_colors[METER_VALUE], cpuTemperatureBuffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], "temp:");
+ RichString_appendWide(out, CRT_colors[METER_VALUE], cpuTemperatureBuffer);
}
#endif
}
diff --git a/CRT.c b/CRT.c
index 68f6405..85f2962 100644
--- a/CRT.c
+++ b/CRT.c
@@ -41,28 +41,33 @@ in the source distribution for its full text.
#define ColorPairGrayBlack ColorPair(Magenta,Magenta)
#define ColorIndexGrayBlack ColorIndex(Magenta,Magenta)
-static const char* const CRT_treeStrAscii[TREE_STR_COUNT] = {
- "-", // TREE_STR_HORZ
- "|", // TREE_STR_VERT
- "`", // TREE_STR_RTEE
- "`", // TREE_STR_BEND
- ",", // TREE_STR_TEND
- "+", // TREE_STR_OPEN
- "-", // TREE_STR_SHUT
+#define ColorPairWhiteDefault ColorPair(Red, Red)
+#define ColorIndexWhiteDefault ColorIndex(Red, Red)
+
+static const char* const CRT_treeStrAscii[LAST_TREE_STR] = {
+ [TREE_STR_VERT] = "|",
+ [TREE_STR_RTEE] = "`",
+ [TREE_STR_BEND] = "`",
+ [TREE_STR_TEND] = ",",
+ [TREE_STR_OPEN] = "+",
+ [TREE_STR_SHUT] = "-",
+ [TREE_STR_ASC] = "+",
+ [TREE_STR_DESC] = "-",
};
#ifdef HAVE_LIBNCURSESW
-static const char* const CRT_treeStrUtf8[TREE_STR_COUNT] = {
- "\xe2\x94\x80", // TREE_STR_HORZ ─
- "\xe2\x94\x82", // TREE_STR_VERT │
- "\xe2\x94\x9c", // TREE_STR_RTEE ├
- "\xe2\x94\x94", // TREE_STR_BEND └
- "\xe2\x94\x8c", // TREE_STR_TEND ┌
- "+", // TREE_STR_OPEN +, TODO use 🮯 'BOX DRAWINGS LIGHT HORIZONTAL
- // WITH VERTICAL STROKE' (U+1FBAF, "\xf0\x9f\xae\xaf") when
- // Unicode 13 is common
- "\xe2\x94\x80", // TREE_STR_SHUT ─
+static const char* const CRT_treeStrUtf8[LAST_TREE_STR] = {
+ [TREE_STR_VERT] = "\xe2\x94\x82", // │
+ [TREE_STR_RTEE] = "\xe2\x94\x9c", // ├
+ [TREE_STR_BEND] = "\xe2\x94\x94", // └
+ [TREE_STR_TEND] = "\xe2\x94\x8c", // ┌
+ [TREE_STR_OPEN] = "+", // +, TODO use 🮯 'BOX DRAWINGS LIGHT HORIZONTAL
+ // WITH VERTICAL STROKE' (U+1FBAF, "\xf0\x9f\xae\xaf") when
+ // Unicode 13 is common
+ [TREE_STR_SHUT] = "\xe2\x94\x80", // ─
+ [TREE_STR_ASC] = "\xe2\x96\xb3", // △
+ [TREE_STR_DESC] = "\xe2\x96\xbd", // ▽
};
bool CRT_utf8 = false;
@@ -92,7 +97,7 @@ static const char* initDegreeSign(void) {
const int* CRT_colors;
-int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
+static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[COLORSCHEME_DEFAULT] = {
[RESET_COLOR] = ColorPair(White, Black),
[DEFAULT_COLOR] = ColorPair(White, Black),
@@ -116,6 +121,7 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[METER_VALUE_IOWRITE] = ColorPair(Blue, Black),
[METER_VALUE_NOTICE] = A_BOLD | ColorPair(White, Black),
[METER_VALUE_OK] = ColorPair(Green, Black),
+ [METER_VALUE_WARN] = A_BOLD | ColorPair(Yellow, Black),
[LED_COLOR] = ColorPair(Green, Black),
[TASKS_RUNNING] = A_BOLD | ColorPair(Green, Black),
[PROCESS] = A_NORMAL,
@@ -200,6 +206,7 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[METER_VALUE_IOWRITE] = A_NORMAL,
[METER_VALUE_NOTICE] = A_BOLD,
[METER_VALUE_OK] = A_NORMAL,
+ [METER_VALUE_WARN] = A_BOLD,
[LED_COLOR] = A_NORMAL,
[TASKS_RUNNING] = A_BOLD,
[PROCESS] = A_NORMAL,
@@ -284,6 +291,7 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[METER_VALUE_IOWRITE] = ColorPair(Yellow, White),
[METER_VALUE_NOTICE] = A_BOLD | ColorPair(Yellow, White),
[METER_VALUE_OK] = ColorPair(Green, White),
+ [METER_VALUE_WARN] = A_BOLD | ColorPair(Yellow, White),
[LED_COLOR] = ColorPair(Green, White),
[TASKS_RUNNING] = ColorPair(Green, White),
[PROCESS] = ColorPair(Black, White),
@@ -346,10 +354,10 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[ZRAM] = ColorPair(Yellow, White)
},
[COLORSCHEME_LIGHTTERMINAL] = {
- [RESET_COLOR] = ColorPair(Blue, Black),
- [DEFAULT_COLOR] = ColorPair(Blue, Black),
+ [RESET_COLOR] = ColorPair(Black, Black),
+ [DEFAULT_COLOR] = ColorPair(Black, Black),
[FUNCTION_BAR] = ColorPair(Black, Cyan),
- [FUNCTION_KEY] = ColorPair(Blue, Black),
+ [FUNCTION_KEY] = ColorPair(Black, Black),
[PANEL_HEADER_FOCUS] = ColorPair(Black, Green),
[PANEL_HEADER_UNFOCUS] = ColorPair(Black, Green),
[PANEL_SELECTION_FOCUS] = ColorPair(Black, Cyan),
@@ -362,17 +370,18 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[BATTERY] = ColorPair(Yellow, Black),
[LARGE_NUMBER] = ColorPair(Red, Black),
[METER_TEXT] = ColorPair(Blue, Black),
- [METER_VALUE] = ColorPair(Blue, Black),
+ [METER_VALUE] = ColorPair(Black, Black),
[METER_VALUE_ERROR] = A_BOLD | ColorPair(Red, Black),
[METER_VALUE_IOREAD] = ColorPair(Green, Black),
[METER_VALUE_IOWRITE] = ColorPair(Yellow, Black),
- [METER_VALUE_NOTICE] = A_BOLD | ColorPair(Yellow, Black),
+ [METER_VALUE_NOTICE] = A_BOLD | ColorPairWhiteDefault,
[METER_VALUE_OK] = ColorPair(Green, Black),
+ [METER_VALUE_WARN] = A_BOLD | ColorPair(Yellow, Black),
[LED_COLOR] = ColorPair(Green, Black),
[TASKS_RUNNING] = ColorPair(Green, Black),
- [PROCESS] = ColorPair(Blue, Black),
+ [PROCESS] = ColorPair(Black, Black),
[PROCESS_SHADOW] = A_BOLD | ColorPairGrayBlack,
- [PROCESS_TAG] = ColorPair(Yellow, Blue),
+ [PROCESS_TAG] = ColorPair(White, Blue),
[PROCESS_MEGABYTES] = ColorPair(Blue, Black),
[PROCESS_GIGABYTES] = ColorPair(Green, Black),
[PROCESS_BASENAME] = ColorPair(Green, Black),
@@ -396,34 +405,34 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[MEMORY_BUFFERS] = ColorPair(Cyan, Black),
[MEMORY_BUFFERS_TEXT] = ColorPair(Cyan, Black),
[MEMORY_CACHE] = ColorPair(Yellow, Black),
- [LOAD_AVERAGE_FIFTEEN] = ColorPair(Blue, Black),
- [LOAD_AVERAGE_FIVE] = ColorPair(Blue, Black),
- [LOAD_AVERAGE_ONE] = ColorPair(Yellow, Black),
- [LOAD] = ColorPair(Yellow, Black),
+ [LOAD_AVERAGE_FIFTEEN] = ColorPair(Black, Black),
+ [LOAD_AVERAGE_FIVE] = ColorPair(Black, Black),
+ [LOAD_AVERAGE_ONE] = ColorPair(Black, Black),
+ [LOAD] = ColorPairWhiteDefault,
[HELP_BOLD] = ColorPair(Blue, Black),
- [CLOCK] = ColorPair(Yellow, Black),
- [DATE] = ColorPair(White, Black),
- [DATETIME] = ColorPair(White, Black),
+ [CLOCK] = ColorPairWhiteDefault,
+ [DATE] = ColorPairWhiteDefault,
+ [DATETIME] = ColorPairWhiteDefault,
[CHECK_BOX] = ColorPair(Blue, Black),
- [CHECK_MARK] = ColorPair(Blue, Black),
- [CHECK_TEXT] = ColorPair(Blue, Black),
- [HOSTNAME] = ColorPair(Yellow, Black),
+ [CHECK_MARK] = ColorPair(Black, Black),
+ [CHECK_TEXT] = ColorPair(Black, Black),
+ [HOSTNAME] = ColorPairWhiteDefault,
[CPU_NICE] = ColorPair(Cyan, Black),
[CPU_NICE_TEXT] = ColorPair(Cyan, Black),
[CPU_NORMAL] = ColorPair(Green, Black),
[CPU_SYSTEM] = ColorPair(Red, Black),
- [CPU_IOWAIT] = A_BOLD | ColorPair(Blue, Black),
+ [CPU_IOWAIT] = A_BOLD | ColorPair(Black, Black),
[CPU_IRQ] = A_BOLD | ColorPair(Blue, Black),
[CPU_SOFTIRQ] = ColorPair(Blue, Black),
- [CPU_STEAL] = ColorPair(Blue, Black),
- [CPU_GUEST] = ColorPair(Blue, Black),
- [PRESSURE_STALL_THREEHUNDRED] = ColorPair(Blue, Black),
- [PRESSURE_STALL_SIXTY] = ColorPair(Blue, Black),
- [PRESSURE_STALL_TEN] = ColorPair(Blue, Black),
+ [CPU_STEAL] = ColorPair(Black, Black),
+ [CPU_GUEST] = ColorPair(Black, Black),
+ [PRESSURE_STALL_THREEHUNDRED] = ColorPair(Black, Black),
+ [PRESSURE_STALL_SIXTY] = ColorPair(Black, Black),
+ [PRESSURE_STALL_TEN] = ColorPair(Black, Black),
[ZFS_MFU] = ColorPair(Cyan, Black),
[ZFS_MRU] = ColorPair(Yellow, Black),
[ZFS_ANON] = A_BOLD | ColorPair(Magenta, Black),
- [ZFS_HEADER] = ColorPair(Blue, Black),
+ [ZFS_HEADER] = ColorPair(Black, Black),
[ZFS_OTHER] = A_BOLD | ColorPair(Magenta, Black),
[ZFS_COMPRESSED] = ColorPair(Cyan, Black),
[ZFS_RATIO] = A_BOLD | ColorPair(Magenta, Black),
@@ -452,6 +461,7 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[METER_VALUE_IOWRITE] = ColorPair(Black, Blue),
[METER_VALUE_NOTICE] = A_BOLD | ColorPair(White, Blue),
[METER_VALUE_OK] = ColorPair(Green, Blue),
+ [METER_VALUE_WARN] = A_BOLD | ColorPair(Yellow, Black),
[LED_COLOR] = ColorPair(Green, Blue),
[TASKS_RUNNING] = A_BOLD | ColorPair(Green, Blue),
[PROCESS] = ColorPair(White, Blue),
@@ -534,8 +544,9 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[METER_VALUE_ERROR] = A_BOLD | ColorPair(Red, Black),
[METER_VALUE_IOREAD] = ColorPair(Green, Black),
[METER_VALUE_IOWRITE] = ColorPair(Blue, Black),
- [METER_VALUE_NOTICE] = A_BOLD | ColorPair(Yellow, Black),
+ [METER_VALUE_NOTICE] = A_BOLD | ColorPair(White, Black),
[METER_VALUE_OK] = ColorPair(Green, Black),
+ [METER_VALUE_WARN] = A_BOLD | ColorPair(Yellow, Black),
[LED_COLOR] = ColorPair(Green, Black),
[TASKS_RUNNING] = A_BOLD | ColorPair(Green, Black),
[PROCESS] = ColorPair(Cyan, Black),
@@ -604,12 +615,7 @@ int CRT_scrollHAmount = 5;
int CRT_scrollWheelVAmount = 10;
-const char* CRT_termType;
-
-int CRT_colorScheme = 0;
-
-long CRT_pageSize = -1;
-long CRT_pageSizeKB = -1;
+ColorScheme CRT_colorScheme = COLORSCHEME_DEFAULT;
ATTR_NORETURN
static void CRT_handleSIGTERM(int sgn) {
@@ -676,14 +682,14 @@ void CRT_init(const int* delay, int colorScheme, bool allowUnicode) {
start_color();
}
- CRT_termType = getenv("TERM");
- if (String_eq(CRT_termType, "linux")) {
+ const char* termType = getenv("TERM");
+ if (termType && String_eq(termType, "linux")) {
CRT_scrollHAmount = 20;
} else {
CRT_scrollHAmount = 5;
}
- if (String_startsWith(CRT_termType, "xterm") || String_eq(CRT_termType, "vt220")) {
+ if (termType && (String_startsWith(termType, "xterm") || String_eq(termType, "vt220"))) {
define_key("\033[H", KEY_HOME);
define_key("\033[F", KEY_END);
define_key("\033[7~", KEY_HOME);
@@ -696,6 +702,7 @@ void CRT_init(const int* delay, int colorScheme, bool allowUnicode) {
define_key("\033[12~", KEY_F(2));
define_key("\033[13~", KEY_F(3));
define_key("\033[14~", KEY_F(4));
+ define_key("\033[14;2~", KEY_F(15));
define_key("\033[17;2~", KEY_F(18));
char sequence[3] = "\033a";
for (char c = 'a'; c <= 'z'; c++) {
@@ -746,11 +753,6 @@ void CRT_init(const int* delay, int colorScheme, bool allowUnicode) {
mousemask(BUTTON1_RELEASED, NULL);
#endif
- CRT_pageSize = sysconf(_SC_PAGESIZE);
- if (CRT_pageSize == -1)
- CRT_fatalError("Fatal error: Can not get PAGE_SIZE by sysconf(_SC_PAGESIZE)");
- CRT_pageSizeKB = CRT_pageSize / 1024;
-
CRT_degreeSign = initDegreeSign();
}
@@ -760,7 +762,7 @@ void CRT_done() {
}
void CRT_fatalError(const char* note) {
- char* sysMsg = strerror(errno);
+ const char* sysMsg = strerror(errno);
CRT_done();
fprintf(stderr, "%s: %s\n", note, sysMsg);
exit(2);
@@ -790,7 +792,7 @@ void CRT_setColors(int colorScheme) {
for (short int i = 0; i < 8; i++) {
for (short int j = 0; j < 8; j++) {
- if (ColorIndex(i, j) != ColorIndexGrayBlack) {
+ if (ColorIndex(i, j) != ColorIndexGrayBlack && ColorIndex(i, j) != ColorIndexWhiteDefault) {
short int bg = (colorScheme != COLORSCHEME_BLACKNIGHT)
? (j == 0 ? -1 : j)
: j;
@@ -803,6 +805,8 @@ void CRT_setColors(int colorScheme) {
short int grayBlackBg = (colorScheme != COLORSCHEME_BLACKNIGHT) ? -1 : 0;
init_pair(ColorIndexGrayBlack, grayBlackFg, grayBlackBg);
+ init_pair(ColorIndexWhiteDefault, White, -1);
+
CRT_colors = CRT_colorSchemes[colorScheme];
}
@@ -819,9 +823,13 @@ void CRT_handleSIGSEGV(int signal) {
"- Your OS and kernel version (uname -a)\n"
"- Your distribution and release (lsb_release -a)\n"
"- Likely steps to reproduce (How did it happened?)\n"
+ );
+
#ifdef HAVE_EXECINFO_H
- "- Backtrace of the issue (see below)\n"
+ fprintf(stderr, "- Backtrace of the issue (see below)\n");
#endif
+
+ fprintf(stderr,
"\n"
);
@@ -856,11 +864,15 @@ void CRT_handleSIGSEGV(int signal) {
"you should provide a disassembly of your binary.\n"
"This can usually be done by running the following command:\n"
"\n"
+ );
+
#ifdef HTOP_DARWIN
- " otool -tvV `which htop` > ~/htop.otool\n"
+ fprintf(stderr, " otool -tvV `which htop` > ~/htop.otool\n");
#else
- " objdump -d -S -w `which htop` > ~/htop.objdump\n"
+ fprintf(stderr, " objdump -d -S -w `which htop` > ~/htop.objdump\n");
#endif
+
+ fprintf(stderr,
"\n"
"Please include the generated file in your report.\n"
"\n"
diff --git a/CRT.h b/CRT.h
index ec3fdaf..4806994 100644
--- a/CRT.h
+++ b/CRT.h
@@ -16,26 +16,27 @@ in the source distribution for its full text.
typedef enum TreeStr_ {
- TREE_STR_HORZ,
TREE_STR_VERT,
TREE_STR_RTEE,
TREE_STR_BEND,
TREE_STR_TEND,
TREE_STR_OPEN,
TREE_STR_SHUT,
- TREE_STR_COUNT
+ TREE_STR_ASC,
+ TREE_STR_DESC,
+ LAST_TREE_STR
} TreeStr;
-typedef enum ColorSchemes_ {
- COLORSCHEME_DEFAULT = 0,
+typedef enum ColorScheme_ {
+ COLORSCHEME_DEFAULT,
COLORSCHEME_MONOCHROME,
COLORSCHEME_BLACKONWHITE,
COLORSCHEME_LIGHTTERMINAL,
COLORSCHEME_MIDNIGHT,
COLORSCHEME_BLACKNIGHT,
COLORSCHEME_BROKENGRAY,
- LAST_COLORSCHEME,
-} ColorSchemes;
+ LAST_COLORSCHEME
+} ColorScheme;
typedef enum ColorElements_ {
RESET_COLOR,
@@ -58,6 +59,7 @@ typedef enum ColorElements_ {
METER_VALUE_IOWRITE,
METER_VALUE_NOTICE,
METER_VALUE_OK,
+ METER_VALUE_WARN,
LED_COLOR,
UPTIME,
BATTERY,
@@ -144,20 +146,13 @@ extern const char* const* CRT_treeStr;
extern const int* CRT_colors;
-extern int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT];
-
extern int CRT_cursorX;
extern int CRT_scrollHAmount;
extern int CRT_scrollWheelVAmount;
-extern const char* CRT_termType;
-
-extern int CRT_colorScheme;
-
-extern long CRT_pageSize;
-extern long CRT_pageSizeKB;
+extern ColorScheme CRT_colorScheme;
#ifdef HAVE_SETUID_ENABLED
diff --git a/ChangeLog b/ChangeLog
index 0b70458..126f11b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,59 @@
+What's new in version 3.0.5
+
+* BUGFIX / SECURITY: InfoScreen: fix uncontrolled format string
+* BUGFIX: Improve white text in the Light Terminal colour scheme
+ (both of the above thanks to V)
+* Enable the function bar on the main screen to be hidden (see Setup -> Display options)
+* BUGFIX: Reduce layout issues esp. around printing wide characters (not complete yet)
+* BUGFIX: Make the follow function exit cleanly after followed process died
+* Solaris: make Process callbacks static
+* Update help and man page for improved -t / -s options
+* Drop usage of formatted error messages from <err.h>
+* Show arrow indicating order of sorted process column
+* Lots of plumbing around the internal Hashtable, hardening and code cleanups
+* LibSensors: add support for Ryzen CPUs (vor 5 Tagen)
+ (thanks to Matej Dian)
+* BUGFIX: Fix CPU percentage on M1 silicon Macs
+ (thanks to Luke Groeninger)
+* LoadMeter: dynamically adjust color and total of bar
+* Find libsensors.so.4 for Fedora and friends
+* Add support to display CPU frequencies on Solarish platforms
+ (thanks to Dominik Hassler)
+* Enable going back to previous search matches (Shift-F3)
+* Added keybind 'N' for sorting by PID (drops 'n'/'N' as not used before much)
+ (thanks to Jake Mannens)
+
+What's new in version 3.0.4
+
+* Separate tree and list sort orders
+* Invert Process_compare so that superclass matches run first
+ (thanks to Hisham Muhammad)
+* Unhardcode Mac OS tick-to-milliseconds conversion
+ (thanks to Alexander Momchilov)
+* Check if clock_gettime needs linking of librt
+* Define O_PATH if not already defined
+ (thanks to Chris Burr)
+* Add column on Mac for processes running under translation
+ (thanks to Dániel Bakai)
+* Configure check for additional linker flags for keypad(3)
+* PSI Meter: constant width and only print ten-duration as bar
+* Sort in paused mode after inverting sort order
+* Handle absence of package CPU temperature
+* Meter: restore non-wide-character build
+* LibSensors: restore temperature for Raspberry Pi
+* MainPanel: do not reset hideProcessSelection on KEY_SHUFFLE
+* BarMeter: rework text padding
+* Panel: rework drawing of FunctionBar
+* Meter: fix artifacts with very tiny width
+* DragonFlyBSD updates
+* BUGFIX: Fix dlopen issue for libsensors5 for some platforms
+* BUGFIX: Fix broken tree display on inverted sort order
+* BUGFIX: Fix pause mode ("Z") in tree view
+* BUGFIX: Correct timebase for non-x86 CPUs on Darwin
+* BUGFIX: Avoid NULL dereference on zombie processes
+* Document dynamic bindings and assumed external configuration
+* Update key mapping documentation for sorting
+
What's new in version 3.0.3
* Process sorting in 'tree' mode
diff --git a/ColorsPanel.c b/ColorsPanel.c
index 2fb1c92..c076adc 100644
--- a/ColorsPanel.c
+++ b/ColorsPanel.c
@@ -60,26 +60,21 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
case KEY_MOUSE:
case KEY_RECLICK:
case ' ':
+ assert(mark >= 0);
+ assert(mark < LAST_COLORSCHEME);
for (int i = 0; ColorSchemeNames[i] != NULL; i++)
CheckItem_set((CheckItem*)Panel_get(super, i), false);
CheckItem_set((CheckItem*)Panel_get(super, mark), true);
this->settings->colorScheme = mark;
- result = HANDLED;
- }
-
- if (result == HANDLED) {
this->settings->changed = true;
- const Header* header = this->scr->header;
+
CRT_setColors(mark);
clear();
- Panel* menu = (Panel*) Vector_get(this->scr->panels, 0);
- Header_draw(header);
- FunctionBar_draw(super->currentBar);
- RichString_setAttr(&(super->header), CRT_colors[PANEL_HEADER_FOCUS]);
- RichString_setAttr(&(menu->header), CRT_colors[PANEL_HEADER_UNFOCUS]);
- ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
+
+ result = HANDLED | REDRAW;
}
+
return result;
}
@@ -100,6 +95,8 @@ ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr) {
this->settings = settings;
this->scr = scr;
+ assert(ARRAYSIZE(ColorSchemeNames) == LAST_COLORSCHEME + 1);
+
Panel_setHeader(super, "Colors");
for (int i = 0; ColorSchemeNames[i] != NULL; i++) {
Panel_add(super, (Object*) CheckItem_newByVal(ColorSchemeNames[i], false));
diff --git a/ColumnsPanel.c b/ColumnsPanel.c
index b2a8246..ea56166 100644
--- a/ColumnsPanel.c
+++ b/ColumnsPanel.c
@@ -44,7 +44,7 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
{
if (selected < size - 1) {
this->moving = !(this->moving);
- Panel_setSelectionColor(super, this->moving ? CRT_colors[PANEL_SELECTION_FOLLOW] : CRT_colors[PANEL_SELECTION_FOCUS]);
+ Panel_setSelectionColor(super, this->moving ? PANEL_SELECTION_FOLLOW : PANEL_SELECTION_FOCUS);
ListItem* selectedItem = (ListItem*) Panel_getSelected(super);
if (selectedItem)
selectedItem->moving = this->moving;
diff --git a/CommandScreen.c b/CommandScreen.c
index d342829..12b1987 100644
--- a/CommandScreen.c
+++ b/CommandScreen.c
@@ -17,9 +17,10 @@ static void CommandScreen_scan(InfoScreen* this) {
Panel_prune(panel);
const char* p = Process_getCommand(this->process);
- char* line = xMalloc(COLS + 1);
+ char line[COLS + 1];
int line_offset = 0, last_spc = -1, len;
for (; *p != '\0'; p++, line_offset++) {
+ assert(line_offset >= 0 && (size_t)line_offset < sizeof(line));
line[line_offset] = *p;
if (*p == ' ') {
last_spc = line_offset;
@@ -41,7 +42,6 @@ static void CommandScreen_scan(InfoScreen* this) {
InfoScreen_addLine(this, line);
}
- free(line);
Panel_setSelected(panel, idx);
}
@@ -60,7 +60,7 @@ const InfoScreenClass CommandScreen_class = {
CommandScreen* CommandScreen_new(Process* process) {
CommandScreen* this = AllocThis(CommandScreen);
- return (CommandScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 3, " ");
+ return (CommandScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " ");
}
void CommandScreen_delete(Object* this) {
diff --git a/Compat.c b/Compat.c
index 43d02ec..55be1b1 100644
--- a/Compat.c
+++ b/Compat.c
@@ -11,12 +11,18 @@ in the source distribution for its full text.
#include <errno.h>
#include <fcntl.h> // IWYU pragma: keep
+#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h> // IWYU pragma: keep
#include "XUtils.h" // IWYU pragma: keep
+#ifdef HAVE_HOST_GET_CLOCK_SERVICE
+#include <mach/clock.h>
+#include <mach/mach.h>
+#endif
+
int Compat_faccessat(int dirfd,
const char* pathname,
@@ -117,3 +123,31 @@ ssize_t Compat_readlinkat(int dirfd,
#endif
}
+
+int Compat_clock_monotonic_gettime(struct timespec *tp) {
+
+#if defined(HAVE_CLOCK_GETTIME)
+
+ return clock_gettime(CLOCK_MONOTONIC, tp);
+
+#elif defined(HAVE_HOST_GET_CLOCK_SERVICE)
+
+ clock_serv_t cclock;
+ mach_timespec_t mts;
+
+ host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
+ clock_get_time(cclock, &mts);
+ mach_port_deallocate(mach_task_self(), cclock);
+
+ tp->tv_sec = mts.tv_sec;
+ tp->tv_nsec = mts.tv_nsec;
+
+ return 0;
+
+#else
+
+#error No Compat_clock_monotonic_gettime() implementation!
+
+#endif
+
+}
diff --git a/Compat.h b/Compat.h
index 94c2ee2..9594735 100644
--- a/Compat.h
+++ b/Compat.h
@@ -56,4 +56,6 @@ ssize_t Compat_readlinkat(int dirfd,
char* buf,
size_t bufsize);
+int Compat_clock_monotonic_gettime(struct timespec *tp);
+
#endif /* HEADER_Compat */
diff --git a/DiskIOMeter.c b/DiskIOMeter.c
index 0105ce3..04ca5a7 100644
--- a/DiskIOMeter.c
+++ b/DiskIOMeter.c
@@ -88,7 +88,7 @@ static void DiskIOMeter_updateValues(Meter* this, char* buffer, size_t len) {
static void DIskIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
if (!hasData) {
- RichString_write(out, CRT_colors[METER_VALUE_ERROR], "no data");
+ RichString_writeAscii(out, CRT_colors[METER_VALUE_ERROR], "no data");
return;
}
@@ -96,15 +96,15 @@ static void DIskIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out)
int color = cached_utilisation_diff > 40.0 ? METER_VALUE_NOTICE : METER_VALUE;
xSnprintf(buffer, sizeof(buffer), "%.1f%%", cached_utilisation_diff);
- RichString_write(out, CRT_colors[color], buffer);
+ RichString_writeAscii(out, CRT_colors[color], buffer);
- RichString_append(out, CRT_colors[METER_TEXT], " read: ");
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " read: ");
Meter_humanUnit(buffer, cached_read_diff, sizeof(buffer));
- RichString_append(out, CRT_colors[METER_VALUE_IOREAD], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], buffer);
- RichString_append(out, CRT_colors[METER_TEXT], " write: ");
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " write: ");
Meter_humanUnit(buffer, cached_write_diff, sizeof(buffer));
- RichString_append(out, CRT_colors[METER_VALUE_IOWRITE], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], buffer);
}
const MeterClass DiskIOMeter_class = {
diff --git a/DisplayOptionsPanel.c b/DisplayOptionsPanel.c
index ed37319..7e02b23 100644
--- a/DisplayOptionsPanel.c
+++ b/DisplayOptionsPanel.c
@@ -97,6 +97,7 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
Panel_setHeader(super, "Display options");
Panel_add(super, (Object*) CheckItem_newByRef("Tree view", &(settings->treeView)));
+ Panel_add(super, (Object*) CheckItem_newByRef("- Tree view is always sorted by PID (htop 2 behavior)", &(settings->treeViewAlwaysByPID)));
Panel_add(super, (Object*) CheckItem_newByRef("Shadow other users' processes", &(settings->shadowOtherUsers)));
Panel_add(super, (Object*) CheckItem_newByRef("Hide kernel threads", &(settings->hideKernelThreads)));
Panel_add(super, (Object*) CheckItem_newByRef("Hide userland process threads", &(settings->hideUserlandThreads)));
@@ -123,6 +124,7 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
Panel_add(super, (Object*) NumberItem_newByRef("Update interval (in seconds)", &(settings->delay), -1, 1, 255));
Panel_add(super, (Object*) CheckItem_newByRef("Highlight new and old processes", &(settings->highlightChanges)));
Panel_add(super, (Object*) NumberItem_newByRef("- Highlight time (in seconds)", &(settings->highlightDelaySecs), 0, 1, 24*60*60));
+ Panel_add(super, (Object*) NumberItem_newByRef("Hide main function bar (0 - off, 1 - on ESC until next input, 2 - permanently)", &(settings->hideFunctionBar), 0, 0, 2));
#ifdef HAVE_LIBHWLOC
Panel_add(super, (Object*) CheckItem_newByRef("Show topology when selecting affinity by default", &(settings->topologyAffinity)));
#endif
diff --git a/EnvScreen.c b/EnvScreen.c
index ae63d3e..acd1f33 100644
--- a/EnvScreen.c
+++ b/EnvScreen.c
@@ -14,30 +14,21 @@
#include "XUtils.h"
-const InfoScreenClass EnvScreen_class = {
- .super = {
- .extends = Class(Object),
- .delete = EnvScreen_delete
- },
- .scan = EnvScreen_scan,
- .draw = EnvScreen_draw
-};
-
EnvScreen* EnvScreen_new(Process* process) {
EnvScreen* this = xMalloc(sizeof(EnvScreen));
Object_setClass(this, Class(EnvScreen));
- return (EnvScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 3, " ");
+ return (EnvScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " ");
}
void EnvScreen_delete(Object* this) {
free(InfoScreen_done((InfoScreen*)this));
}
-void EnvScreen_draw(InfoScreen* this) {
+static void EnvScreen_draw(InfoScreen* this) {
InfoScreen_drawTitled(this, "Environment of process %d - %s", this->process->pid, Process_getCommand(this->process));
}
-void EnvScreen_scan(InfoScreen* this) {
+static void EnvScreen_scan(InfoScreen* this) {
Panel* panel = this->display;
int idx = MAXIMUM(Panel_getSelectedIndex(panel), 0);
@@ -59,3 +50,12 @@ void EnvScreen_scan(InfoScreen* this) {
Vector_insertionSort(panel->items);
Panel_setSelected(panel, idx);
}
+
+const InfoScreenClass EnvScreen_class = {
+ .super = {
+ .extends = Class(Object),
+ .delete = EnvScreen_delete
+ },
+ .scan = EnvScreen_scan,
+ .draw = EnvScreen_draw
+};
diff --git a/EnvScreen.h b/EnvScreen.h
index bf38580..66d263f 100644
--- a/EnvScreen.h
+++ b/EnvScreen.h
@@ -15,8 +15,4 @@ EnvScreen* EnvScreen_new(Process* process);
void EnvScreen_delete(Object* this);
-void EnvScreen_draw(InfoScreen* this);
-
-void EnvScreen_scan(InfoScreen* this);
-
#endif
diff --git a/FunctionBar.c b/FunctionBar.c
index 627bc77..1c260ab 100644
--- a/FunctionBar.c
+++ b/FunctionBar.c
@@ -112,10 +112,11 @@ void FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr
attrset(attr);
}
mvaddstr(LINES - 1, x, buffer);
- attrset(CRT_colors[RESET_COLOR]);
x += strlen(buffer);
}
+ attrset(CRT_colors[RESET_COLOR]);
+
if (setCursor) {
CRT_cursorX = x;
curs_set(1);
@@ -132,10 +133,10 @@ void FunctionBar_append(const char* buffer, int attr) {
} else {
attrset(attr);
}
- mvaddstr(LINES - 1, currentLen, buffer);
+ mvaddstr(LINES - 1, currentLen + 1, buffer);
attrset(CRT_colors[RESET_COLOR]);
- currentLen += strlen(buffer);
+ currentLen += strlen(buffer) + 1;
}
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos) {
diff --git a/Hashtable.c b/Hashtable.c
index 1beb2bb..9b0882a 100644
--- a/Hashtable.c
+++ b/Hashtable.c
@@ -15,22 +15,37 @@ in the source distribution for its full text.
#include <stdlib.h>
#include <string.h>
+#include "CRT.h"
#include "Macros.h"
#include "XUtils.h"
+typedef struct HashtableItem_ {
+ ht_key_t key;
+ size_t probe;
+ void* value;
+} HashtableItem;
+
+struct Hashtable_ {
+ size_t size;
+ HashtableItem* buckets;
+ size_t items;
+ bool owner;
+};
+
+
#ifndef NDEBUG
static void Hashtable_dump(const Hashtable* this) {
- fprintf(stderr, "Hashtable %p: size=%u items=%u owner=%s\n",
+ fprintf(stderr, "Hashtable %p: size=%zu items=%zu owner=%s\n",
(const void*)this,
this->size,
this->items,
this->owner ? "yes" : "no");
- unsigned int items = 0;
- for (unsigned int i = 0; i < this->size; i++) {
- fprintf(stderr, " item %5u: key = %5u probe = %2u value = %p\n",
+ size_t items = 0;
+ for (size_t i = 0; i < this->size; i++) {
+ fprintf(stderr, " item %5zu: key = %5u probe = %2zu value = %p\n",
i,
this->buckets[i].key,
this->buckets[i].probe,
@@ -40,15 +55,15 @@ static void Hashtable_dump(const Hashtable* this) {
items++;
}
- fprintf(stderr, "Hashtable %p: items=%u counted=%u\n",
+ fprintf(stderr, "Hashtable %p: items=%zu counted=%zu\n",
(const void*)this,
this->items,
items);
}
static bool Hashtable_isConsistent(const Hashtable* this) {
- unsigned int items = 0;
- for (unsigned int i = 0; i < this->size; i++) {
+ size_t items = 0;
+ for (size_t i = 0; i < this->size; i++) {
if (this->buckets[i].value)
items++;
}
@@ -58,9 +73,9 @@ static bool Hashtable_isConsistent(const Hashtable* this) {
return res;
}
-unsigned int Hashtable_count(const Hashtable* this) {
- unsigned int items = 0;
- for (unsigned int i = 0; i < this->size; i++) {
+size_t Hashtable_count(const Hashtable* this) {
+ size_t items = 0;
+ for (size_t i = 0; i < this->size; i++) {
if (this->buckets[i].value)
items++;
}
@@ -80,18 +95,17 @@ static const uint64_t OEISprimes[] = {
34359738337, 68719476731, 137438953447
};
-static uint64_t nextPrime(unsigned int n) {
- assert(n <= OEISprimes[ARRAYSIZE(OEISprimes) - 1]);
-
- for (unsigned int i = 0; i < ARRAYSIZE(OEISprimes); i++) {
+static uint64_t nextPrime(size_t n) {
+ /* on 32-bit make sure we do not return primes not fitting in size_t */
+ for (size_t i = 0; i < ARRAYSIZE(OEISprimes) && OEISprimes[i] < SIZE_MAX; i++) {
if (n <= OEISprimes[i])
return OEISprimes[i];
}
- return OEISprimes[ARRAYSIZE(OEISprimes) - 1];
+ CRT_fatalError("Hashtable: no prime found");
}
-Hashtable* Hashtable_new(unsigned int size, bool owner) {
+Hashtable* Hashtable_new(size_t size, bool owner) {
Hashtable* this;
this = xMalloc(sizeof(Hashtable));
@@ -115,7 +129,7 @@ void Hashtable_clear(Hashtable* this) {
assert(Hashtable_isConsistent(this));
if (this->owner)
- for (unsigned int i = 0; i < this->size; i++)
+ for (size_t i = 0; i < this->size; i++)
free(this->buckets[i].value);
memset(this->buckets, 0, this->size * sizeof(HashtableItem));
@@ -124,11 +138,11 @@ void Hashtable_clear(Hashtable* this) {
assert(Hashtable_isConsistent(this));
}
-static void insert(Hashtable* this, hkey_t key, void* value) {
- unsigned int index = key % this->size;
- unsigned int probe = 0;
+static void insert(Hashtable* this, ht_key_t key, void* value) {
+ size_t index = key % this->size;
+ size_t probe = 0;
#ifndef NDEBUG
- unsigned int origIndex = index;
+ size_t origIndex = index;
#endif
for (;;) {
@@ -167,7 +181,7 @@ static void insert(Hashtable* this, hkey_t key, void* value) {
}
}
-void Hashtable_setSize(Hashtable* this, unsigned int size) {
+void Hashtable_setSize(Hashtable* this, size_t size) {
assert(Hashtable_isConsistent(this));
@@ -175,14 +189,14 @@ void Hashtable_setSize(Hashtable* this, unsigned int size) {
return;
HashtableItem* oldBuckets = this->buckets;
- unsigned int oldSize = this->size;
+ size_t oldSize = this->size;
this->size = nextPrime(size);
this->buckets = (HashtableItem*) xCalloc(this->size, sizeof(HashtableItem));
this->items = 0;
/* rehash */
- for (unsigned int i = 0; i < oldSize; i++) {
+ for (size_t i = 0; i < oldSize; i++) {
if (!oldBuckets[i].value)
continue;
@@ -194,15 +208,19 @@ void Hashtable_setSize(Hashtable* this, unsigned int size) {
assert(Hashtable_isConsistent(this));
}
-void Hashtable_put(Hashtable* this, hkey_t key, void* value) {
+void Hashtable_put(Hashtable* this, ht_key_t key, void* value) {
assert(Hashtable_isConsistent(this));
assert(this->size > 0);
assert(value);
/* grow on load-factor > 0.7 */
- if (10 * this->items > 7 * this->size)
+ if (10 * this->items > 7 * this->size) {
+ if (SIZE_MAX / 2 < this->size)
+ CRT_fatalError("Hashtable: size overflow");
+
Hashtable_setSize(this, 2 * this->size);
+ }
insert(this, key, value);
@@ -211,11 +229,11 @@ void Hashtable_put(Hashtable* this, hkey_t key, void* value) {
assert(this->size > this->items);
}
-void* Hashtable_remove(Hashtable* this, hkey_t key) {
- unsigned int index = key % this->size;
- unsigned int probe = 0;
+void* Hashtable_remove(Hashtable* this, ht_key_t key) {
+ size_t index = key % this->size;
+ size_t probe = 0;
#ifndef NDEBUG
- unsigned int origIndex = index;
+ size_t origIndex = index;
#endif
assert(Hashtable_isConsistent(this));
@@ -230,7 +248,7 @@ void* Hashtable_remove(Hashtable* this, hkey_t key) {
res = this->buckets[index].value;
}
- unsigned int next = (index + 1) % this->size;
+ size_t next = (index + 1) % this->size;
while (this->buckets[next].value && this->buckets[next].probe > 0) {
this->buckets[index] = this->buckets[next];
@@ -266,12 +284,12 @@ void* Hashtable_remove(Hashtable* this, hkey_t key) {
return res;
}
-void* Hashtable_get(Hashtable* this, hkey_t key) {
- unsigned int index = key % this->size;
- unsigned int probe = 0;
+void* Hashtable_get(Hashtable* this, ht_key_t key) {
+ size_t index = key % this->size;
+ size_t probe = 0;
void* res = NULL;
#ifndef NDEBUG
- unsigned int origIndex = index;
+ size_t origIndex = index;
#endif
assert(Hashtable_isConsistent(this));
@@ -296,7 +314,7 @@ void* Hashtable_get(Hashtable* this, hkey_t key) {
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData) {
assert(Hashtable_isConsistent(this));
- for (unsigned int i = 0; i < this->size; i++) {
+ for (size_t i = 0; i < this->size; i++) {
HashtableItem* walk = &this->buckets[i];
if (walk->value)
f(walk->key, walk->value, userData);
diff --git a/Hashtable.h b/Hashtable.h
index 6d93478..d6b7be2 100644
--- a/Hashtable.h
+++ b/Hashtable.h
@@ -8,44 +8,34 @@ in the source distribution for its full text.
*/
#include <stdbool.h>
+#include <stddef.h>
-typedef unsigned int hkey_t;
+typedef unsigned int ht_key_t;
-typedef void(*Hashtable_PairFunction)(hkey_t key, void* value, void* userdata);
+typedef void(*Hashtable_PairFunction)(ht_key_t key, void* value, void* userdata);
-typedef struct HashtableItem_ {
- hkey_t key;
- unsigned int probe;
- void* value;
-} HashtableItem;
-
-typedef struct Hashtable_ {
- unsigned int size;
- HashtableItem* buckets;
- unsigned int items;
- bool owner;
-} Hashtable;
+typedef struct Hashtable_ Hashtable;
#ifndef NDEBUG
-unsigned int Hashtable_count(const Hashtable* this);
+size_t Hashtable_count(const Hashtable* this);
#endif /* NDEBUG */
-Hashtable* Hashtable_new(unsigned int size, bool owner);
+Hashtable* Hashtable_new(size_t size, bool owner);
void Hashtable_delete(Hashtable* this);
void Hashtable_clear(Hashtable* this);
-void Hashtable_setSize(Hashtable* this, unsigned int size);
+void Hashtable_setSize(Hashtable* this, size_t size);
-void Hashtable_put(Hashtable* this, hkey_t key, void* value);
+void Hashtable_put(Hashtable* this, ht_key_t key, void* value);
-void* Hashtable_remove(Hashtable* this, hkey_t key);
+void* Hashtable_remove(Hashtable* this, ht_key_t key);
-void* Hashtable_get(Hashtable* this, hkey_t key);
+void* Hashtable_get(Hashtable* this, ht_key_t key);
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData);
diff --git a/IncSet.c b/IncSet.c
index d280caf..aba5e75 100644
--- a/IncSet.c
+++ b/IncSet.c
@@ -29,9 +29,9 @@ void IncSet_reset(IncSet* this, IncType type) {
IncMode_reset(&this->modes[type]);
}
-static const char* const searchFunctions[] = {"Next ", "Cancel ", " Search: ", NULL};
-static const char* const searchKeys[] = {"F3", "Esc", " "};
-static int searchEvents[] = {KEY_F(3), 27, ERR};
+static const char* const searchFunctions[] = {"Next ", "Prev ", "Cancel ", " Search: ", NULL};
+static const char* const searchKeys[] = {"F3", "S-F3", "Esc", " "};
+static const int searchEvents[] = {KEY_F(3), KEY_F(15), 27, ERR};
static inline void IncMode_initSearch(IncMode* search) {
memset(search, 0, sizeof(IncMode));
@@ -41,7 +41,7 @@ static inline void IncMode_initSearch(IncMode* search) {
static const char* const filterFunctions[] = {"Done ", "Clear ", " Filter: ", NULL};
static const char* const filterKeys[] = {"Enter", "Esc", " "};
-static int filterEvents[] = {13, 27, ERR};
+static const int filterEvents[] = {13, 27, ERR};
static inline void IncMode_initFilter(IncMode* filter) {
memset(filter, 0, sizeof(IncMode));
@@ -54,12 +54,13 @@ static inline void IncMode_done(IncMode* mode) {
}
IncSet* IncSet_new(FunctionBar* bar) {
- IncSet* this = xCalloc(1, sizeof(IncSet));
+ IncSet* this = xMalloc(sizeof(IncSet));
IncMode_initSearch(&(this->modes[INC_SEARCH]));
IncMode_initFilter(&(this->modes[INC_FILTER]));
this->active = NULL;
- this->filtering = false;
this->defaultBar = bar;
+ this->filtering = false;
+ this->found = false;
return this;
}
@@ -99,20 +100,14 @@ static void updateWeakPanel(IncSet* this, Panel* panel, Vector* lines) {
static bool search(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelValue) {
int size = Panel_size(panel);
- bool found = false;
for (int i = 0; i < size; i++) {
if (String_contains_i(getPanelValue(panel, i), mode->buffer)) {
Panel_setSelected(panel, i);
- found = true;
- break;
+ return true;
}
}
- FunctionBar_drawExtra(mode->bar,
- mode->buffer,
- found ? -1 : CRT_colors[FAILED_SEARCH],
- true);
- return found;
+ return false;
}
static bool IncMode_find(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelValue, int step) {
@@ -138,14 +133,6 @@ static bool IncMode_find(IncMode* mode, Panel* panel, IncMode_GetPanelValue getP
}
}
-bool IncSet_next(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue) {
- return IncMode_find(&this->modes[type], panel, getPanelValue, 1);
-}
-
-bool IncSet_prev(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue) {
- return IncMode_find(&this->modes[type], panel, getPanelValue, -1);
-}
-
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines) {
if (ch == ERR)
return true;
@@ -154,11 +141,11 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
int size = Panel_size(panel);
bool filterChanged = false;
bool doSearch = true;
- if (ch == KEY_F(3)) {
+ if (ch == KEY_F(3) || ch == KEY_F(15)) {
if (size == 0)
return true;
- IncMode_find(mode, panel, getPanelValue, 1);
+ IncMode_find(mode, panel, getPanelValue, ch == KEY_F(3) ? 1 : -1);
doSearch = false;
} else if (0 < ch && ch < 255 && isprint((unsigned char)ch)) {
if (mode->index < INCMODE_MAX) {
@@ -172,7 +159,7 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
}
}
}
- } else if ((ch == KEY_BACKSPACE || ch == 127)) {
+ } else if (ch == KEY_BACKSPACE || ch == 127) {
if (mode->index > 0) {
mode->index--;
mode->buffer[mode->index] = 0;
@@ -187,7 +174,7 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
doSearch = false;
}
} else if (ch == KEY_RESIZE) {
- Panel_resize(panel, COLS, LINES - panel->y - 1);
+ doSearch = (mode->index > 0);
} else {
if (mode->isFilter) {
filterChanged = true;
@@ -202,7 +189,6 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
}
this->active = NULL;
Panel_setDefaultBar(panel);
- FunctionBar_draw(this->defaultBar);
doSearch = false;
}
if (doSearch) {
@@ -221,13 +207,12 @@ const char* IncSet_getListItemValue(Panel* panel, int i) {
void IncSet_activate(IncSet* this, IncType type, Panel* panel) {
this->active = &(this->modes[type]);
- FunctionBar_drawExtra(this->active->bar, this->active->buffer, -1, true);
panel->currentBar = this->active->bar;
}
void IncSet_drawBar(const IncSet* this) {
if (this->active) {
- FunctionBar_drawExtra(this->active->bar, this->active->buffer, -1, true);
+ FunctionBar_drawExtra(this->active->bar, this->active->buffer, (this->active->isFilter || this->found) ? -1 : CRT_colors[FAILED_SEARCH], true);
} else {
FunctionBar_draw(this->defaultBar);
}
diff --git a/IncSet.h b/IncSet.h
index b07840f..2858002 100644
--- a/IncSet.h
+++ b/IncSet.h
@@ -48,10 +48,6 @@ IncSet* IncSet_new(FunctionBar* bar);
void IncSet_delete(IncSet* this);
-bool IncSet_next(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue);
-
-bool IncSet_prev(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue);
-
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines);
const char* IncSet_getListItemValue(Panel* panel, int i);
diff --git a/InfoScreen.c b/InfoScreen.c
index ceb29f7..9647b9f 100644
--- a/InfoScreen.c
+++ b/InfoScreen.c
@@ -19,14 +19,14 @@ static const char* const InfoScreenFunctions[] = {"Search ", "Filter ", "Refresh
static const char* const InfoScreenKeys[] = {"F3", "F4", "F5", "Esc"};
-static int InfoScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(5), 27};
+static const int InfoScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(5), 27};
InfoScreen* InfoScreen_init(InfoScreen* this, const Process* process, FunctionBar* bar, int height, const char* panelHeader) {
this->process = process;
if (!bar) {
bar = FunctionBar_new(InfoScreenFunctions, InfoScreenKeys, InfoScreenEvents);
}
- this->display = Panel_new(0, 1, COLS, height, false, Class(ListItem), bar);
+ this->display = Panel_new(0, 1, COLS, height, Class(ListItem), false, bar);
this->inc = IncSet_new(bar);
this->lines = Vector_new(this->display->items->type, true, DEFAULT_SIZE);
Panel_setHeader(this->display, panelHeader);
@@ -44,21 +44,21 @@ void InfoScreen_drawTitled(InfoScreen* this, const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
- char* title = xMalloc(COLS + 1);
- int len = vsnprintf(title, COLS + 1, fmt, ap);
+ char title[COLS + 1];
+ int len = vsnprintf(title, sizeof(title), fmt, ap);
+ va_end(ap);
+
if (len > COLS) {
memset(&title[COLS - 3], '.', 3);
}
attrset(CRT_colors[METER_TEXT]);
mvhline(0, 0, ' ', COLS);
- mvwprintw(stdscr, 0, 0, title);
+ mvaddstr(0, 0, title);
attrset(CRT_colors[DEFAULT_COLOR]);
- this->display->needsRedraw = true;
- Panel_draw(this->display, true, true);
+ Panel_draw(this->display, true, true, true, false);
+
IncSet_drawBar(this->inc);
- free(title);
- va_end(ap);
}
void InfoScreen_addLine(InfoScreen* this, const char* line) {
@@ -89,7 +89,8 @@ void InfoScreen_run(InfoScreen* this) {
bool looping = true;
while (looping) {
- Panel_draw(panel, true, true);
+ Panel_draw(panel, false, true, true, false);
+ IncSet_drawBar(this->inc);
if (this->inc->active) {
(void) move(LINES - 1, CRT_cursorX);
diff --git a/InfoScreen.h b/InfoScreen.h
index 0d80367..d7497be 100644
--- a/InfoScreen.h
+++ b/InfoScreen.h
@@ -16,7 +16,6 @@ typedef struct InfoScreen_ {
Object super;
const Process* process;
Panel* display;
- FunctionBar* bar;
IncSet* inc;
Vector* lines;
} InfoScreen;
diff --git a/ListItem.c b/ListItem.c
index c3c1a7d..7ccf8d7 100644
--- a/ListItem.c
+++ b/ListItem.c
@@ -29,7 +29,7 @@ static void ListItem_display(const Object* cast, RichString* out) {
assert (this != NULL);
if (this->moving) {
- RichString_write(out, CRT_colors[DEFAULT_COLOR],
+ RichString_writeWide(out, CRT_colors[DEFAULT_COLOR],
#ifdef HAVE_LIBNCURSESW
CRT_utf8 ? "↕ " :
#endif
@@ -37,7 +37,7 @@ static void ListItem_display(const Object* cast, RichString* out) {
} else {
RichString_prune(out);
}
- RichString_append(out, CRT_colors[DEFAULT_COLOR], this->value);
+ RichString_appendWide(out, CRT_colors[DEFAULT_COLOR], this->value);
}
ListItem* ListItem_new(const char* value, int key) {
@@ -57,7 +57,7 @@ void ListItem_append(ListItem* this, const char* text) {
this->value[newLen] = '\0';
}
-static long ListItem_compare(const void* cast1, const void* cast2) {
+static int ListItem_compare(const void* cast1, const void* cast2) {
const ListItem* obj1 = (const ListItem*) cast1;
const ListItem* obj2 = (const ListItem*) cast2;
return strcmp(obj1->value, obj2->value);
diff --git a/LoadAverageMeter.c b/LoadAverageMeter.c
index d5424cd..0c7b833 100644
--- a/LoadAverageMeter.c
+++ b/LoadAverageMeter.c
@@ -24,8 +24,36 @@ static const int LoadMeter_attributes[] = {
LOAD
};
+static const int OK_attributes[] = {
+ METER_VALUE_OK
+};
+
+static const int Medium_attributes[] = {
+ METER_VALUE_WARN
+};
+
+static const int High_attributes[] = {
+ METER_VALUE_ERROR
+};
+
static void LoadAverageMeter_updateValues(Meter* this, char* buffer, size_t size) {
Platform_getLoadAverage(&this->values[0], &this->values[1], &this->values[2]);
+
+ // only show bar for 1min value
+ this->curItems = 1;
+
+ // change bar color and total based on value
+ if (this->values[0] < 1.0) {
+ this->curAttributes = OK_attributes;
+ this->total = 1.0;
+ } else if (this->values[0] < this->pl->cpuCount) {
+ this->curAttributes = Medium_attributes;
+ this->total = this->pl->cpuCount;
+ } else {
+ this->curAttributes = High_attributes;
+ this->total = 2 * this->pl->cpuCount;
+ }
+
xSnprintf(buffer, size, "%.2f/%.2f/%.2f", this->values[0], this->values[1], this->values[2]);
}
@@ -33,19 +61,29 @@ static void LoadAverageMeter_display(const Object* cast, RichString* out) {
const Meter* this = (const Meter*)cast;
char buffer[20];
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
- RichString_write(out, CRT_colors[LOAD_AVERAGE_ONE], buffer);
+ RichString_writeAscii(out, CRT_colors[LOAD_AVERAGE_ONE], buffer);
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[1]);
- RichString_append(out, CRT_colors[LOAD_AVERAGE_FIVE], buffer);
+ RichString_appendAscii(out, CRT_colors[LOAD_AVERAGE_FIVE], buffer);
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[2]);
- RichString_append(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer);
+ RichString_appendAscii(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer);
}
static void LoadMeter_updateValues(Meter* this, char* buffer, size_t size) {
double five, fifteen;
Platform_getLoadAverage(&this->values[0], &five, &fifteen);
- if (this->values[0] > this->total) {
- this->total = this->values[0];
+
+ // change bar color and total based on value
+ if (this->values[0] < 1.0) {
+ this->curAttributes = OK_attributes;
+ this->total = 1.0;
+ } else if (this->values[0] < this->pl->cpuCount) {
+ this->curAttributes = Medium_attributes;
+ this->total = this->pl->cpuCount;
+ } else {
+ this->curAttributes = High_attributes;
+ this->total = 2 * this->pl->cpuCount;
}
+
xSnprintf(buffer, size, "%.2f", this->values[0]);
}
@@ -53,7 +91,7 @@ static void LoadMeter_display(const Object* cast, RichString* out) {
const Meter* this = (const Meter*)cast;
char buffer[20];
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
- RichString_write(out, CRT_colors[LOAD], buffer);
+ RichString_writeAscii(out, CRT_colors[LOAD], buffer);
}
const MeterClass LoadAverageMeter_class = {
diff --git a/MainPanel.c b/MainPanel.c
index 5e3a54c..859c513 100644
--- a/MainPanel.c
+++ b/MainPanel.c
@@ -25,7 +25,7 @@ static const char* const MainFunctions[] = {"Help ", "Setup ", "Search", "Filt
void MainPanel_updateTreeFunctions(MainPanel* this, bool mode) {
FunctionBar* bar = MainPanel_getFunctionBar(this);
- FunctionBar_setLabel(bar, KEY_F(5), mode ? "Sorted" : "Tree ");
+ FunctionBar_setLabel(bar, KEY_F(5), mode ? "List " : "Tree ");
}
void MainPanel_pidSearch(MainPanel* this, int ch) {
@@ -44,6 +44,11 @@ void MainPanel_pidSearch(MainPanel* this, int ch) {
}
}
+static const char* MainPanel_getValue(Panel* this, int i) {
+ const Process* p = (const Process*) Panel_get(this, i);
+ return Process_getCommand(p);
+}
+
static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
MainPanel* this = (MainPanel*) super;
@@ -51,6 +56,11 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
Htop_Reaction reaction = HTOP_OK;
+ /* Let supervising ScreenManager handle resize */
+ if (ch == KEY_RESIZE)
+ return IGNORED;
+
+ /* reset on every normal key */
if (ch != ERR)
this->state->hideProcessSelection = false;
@@ -60,7 +70,11 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
Settings* settings = this->state->settings;
int hx = super->scrollH + x + 1;
ProcessField field = ProcessList_keyAt(pl, hx);
- if (field == settings->sortKey) {
+ if (settings->treeView && settings->treeViewAlwaysByPID) {
+ settings->treeView = false;
+ settings->direction = 1;
+ reaction |= Action_setSortKey(settings, field);
+ } else if (field == Settings_getActiveSortKey(settings)) {
Settings_invertSortOrder(settings);
} else {
reaction |= Action_setSortKey(settings, field);
@@ -68,7 +82,7 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
reaction |= HTOP_RECALCULATE | HTOP_REDRAW_BAR | HTOP_SAVE_SETTINGS;
result = HANDLED;
} else if (ch != ERR && this->inc->active) {
- bool filterChanged = IncSet_handleKey(this->inc, ch, super, (IncMode_GetPanelValue) MainPanel_getValue, NULL);
+ bool filterChanged = IncSet_handleKey(this->inc, ch, super, MainPanel_getValue, NULL);
if (filterChanged) {
this->state->pl->incFilter = IncSet_filter(this->inc);
reaction = HTOP_REFRESH | HTOP_REDRAW_BAR;
@@ -96,16 +110,12 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
if (reaction & HTOP_REDRAW_BAR) {
MainPanel_updateTreeFunctions(this, this->state->settings->treeView);
- IncSet_drawBar(this->inc);
- if (this->state->pauseProcessUpdate) {
- FunctionBar_append("PAUSED", CRT_colors[PAUSED]);
- }
}
if (reaction & HTOP_UPDATE_PANELHDR) {
- ProcessList_printHeader(this->state->pl, Panel_getHeader(super));
+ result |= REDRAW;
}
if (reaction & HTOP_REFRESH) {
- result |= REDRAW;
+ result |= REFRESH;
}
if (reaction & HTOP_RECALCULATE) {
result |= RESCAN;
@@ -118,7 +128,7 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
}
if (!(reaction & HTOP_KEEP_FOLLOWING)) {
this->state->pl->following = -1;
- Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOCUS]);
+ Panel_setSelectionColor(super, PANEL_SELECTION_FOCUS);
}
return result;
}
@@ -131,11 +141,6 @@ int MainPanel_selectedPid(MainPanel* this) {
return -1;
}
-const char* MainPanel_getValue(MainPanel* this, int i) {
- Process* p = (Process*) Panel_get((Panel*)this, i);
- return Process_getCommand(p);
-}
-
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged) {
Panel* super = (Panel*) this;
bool ok = true;
@@ -160,12 +165,32 @@ bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Ar
return ok;
}
+static void MainPanel_drawFunctionBar(Panel* super, bool hideFunctionBar) {
+ MainPanel* this = (MainPanel*) super;
+
+ // Do not hide active search and filter bar.
+ if (hideFunctionBar && !this->inc->active)
+ return;
+
+ IncSet_drawBar(this->inc);
+ if (this->state->pauseProcessUpdate) {
+ FunctionBar_append("PAUSED", CRT_colors[PAUSED]);
+ }
+}
+
+static void MainPanel_printHeader(Panel* super) {
+ MainPanel* this = (MainPanel*) super;
+ ProcessList_printHeader(this->state->pl, &super->header);
+}
+
const PanelClass MainPanel_class = {
.super = {
.extends = Class(Panel),
.delete = MainPanel_delete
},
- .eventHandler = MainPanel_eventHandler
+ .eventHandler = MainPanel_eventHandler,
+ .drawFunctionBar = MainPanel_drawFunctionBar,
+ .printHeader = MainPanel_printHeader
};
MainPanel* MainPanel_new() {
diff --git a/MainPanel.h b/MainPanel.h
index 03a1aff..2427ca3 100644
--- a/MainPanel.h
+++ b/MainPanel.h
@@ -38,8 +38,6 @@ void MainPanel_pidSearch(MainPanel* this, int ch);
int MainPanel_selectedPid(MainPanel* this);
-const char* MainPanel_getValue(MainPanel* this, int i);
-
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged);
extern const PanelClass MainPanel_class;
diff --git a/Makefile.am b/Makefile.am
index 09790fa..fe70eef 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -133,6 +133,7 @@ linux_platform_headers = \
linux/LinuxProcessList.h \
linux/Platform.h \
linux/PressureStallMeter.h \
+ linux/ProcessField.h \
linux/SELinuxMeter.h \
linux/SystemdMeter.h \
linux/ZramMeter.h \
@@ -164,9 +165,10 @@ endif
# -------
freebsd_platform_headers = \
- freebsd/Platform.h \
freebsd/FreeBSDProcessList.h \
freebsd/FreeBSDProcess.h \
+ freebsd/Platform.h \
+ freebsd/ProcessField.h \
zfs/ZfsArcMeter.h \
zfs/ZfsCompressedArcMeter.h \
zfs/ZfsArcStats.h \
@@ -184,14 +186,16 @@ endif
# ------------
dragonflybsd_platform_headers = \
- dragonflybsd/Platform.h \
dragonflybsd/DragonFlyBSDProcessList.h \
- dragonflybsd/DragonFlyBSDProcess.h
+ dragonflybsd/DragonFlyBSDProcess.h \
+ dragonflybsd/Platform.h \
+ dragonflybsd/ProcessField.h
if HTOP_DRAGONFLYBSD
-AM_LDFLAGS += -lkvm -lkinfo
-myhtopplatsources = dragonflybsd/Platform.c dragonflybsd/DragonFlyBSDProcessList.c \
-dragonflybsd/DragonFlyBSDProcess.c
+myhtopplatsources = \
+ dragonflybsd/Platform.c \
+ dragonflybsd/DragonFlyBSDProcessList.c \
+ dragonflybsd/DragonFlyBSDProcess.c
myhtopplatheaders = $(dragonflybsd_platform_headers)
endif
@@ -200,9 +204,10 @@ endif
# -------
openbsd_platform_headers = \
- openbsd/Platform.h \
openbsd/OpenBSDProcessList.h \
- openbsd/OpenBSDProcess.h
+ openbsd/OpenBSDProcess.h \
+ openbsd/Platform.h \
+ openbsd/ProcessField.h
if HTOP_OPENBSD
myhtopplatsources = openbsd/Platform.c openbsd/OpenBSDProcessList.c \
@@ -215,9 +220,10 @@ endif
# ------
darwin_platform_headers = \
- darwin/Platform.h \
darwin/DarwinProcess.h \
darwin/DarwinProcessList.h \
+ darwin/Platform.h \
+ darwin/ProcessField.h \
zfs/ZfsArcMeter.h \
zfs/ZfsCompressedArcMeter.h \
zfs/ZfsArcStats.h \
@@ -237,6 +243,7 @@ endif
solaris_platform_headers = \
solaris/Platform.h \
+ solaris/ProcessField.h \
solaris/SolarisProcess.h \
solaris/SolarisProcessList.h \
zfs/ZfsArcMeter.h \
@@ -256,6 +263,7 @@ endif
unsupported_platform_headers = \
unsupported/Platform.h \
+ unsupported/ProcessField.h \
unsupported/UnsupportedProcess.h \
unsupported/UnsupportedProcessList.h
diff --git a/MemoryMeter.c b/MemoryMeter.c
index 9830bf5..e475442 100644
--- a/MemoryMeter.c
+++ b/MemoryMeter.c
@@ -34,18 +34,18 @@ static void MemoryMeter_updateValues(Meter* this, char* buffer, size_t size) {
static void MemoryMeter_display(const Object* cast, RichString* out) {
char buffer[50];
const Meter* this = (const Meter*)cast;
- RichString_write(out, CRT_colors[METER_TEXT], ":");
- Meter_humanUnit(buffer, this->total, 50);
- RichString_append(out, CRT_colors[METER_VALUE], buffer);
- Meter_humanUnit(buffer, this->values[0], 50);
- RichString_append(out, CRT_colors[METER_TEXT], " used:");
- RichString_append(out, CRT_colors[MEMORY_USED], buffer);
- Meter_humanUnit(buffer, this->values[1], 50);
- RichString_append(out, CRT_colors[METER_TEXT], " buffers:");
- RichString_append(out, CRT_colors[MEMORY_BUFFERS_TEXT], buffer);
- Meter_humanUnit(buffer, this->values[2], 50);
- RichString_append(out, CRT_colors[METER_TEXT], " cache:");
- RichString_append(out, CRT_colors[MEMORY_CACHE], buffer);
+ RichString_writeAscii(out, CRT_colors[METER_TEXT], ":");
+ Meter_humanUnit(buffer, this->total, sizeof(buffer));
+ RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
+ Meter_humanUnit(buffer, this->values[0], sizeof(buffer));
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " used:");
+ RichString_appendAscii(out, CRT_colors[MEMORY_USED], buffer);
+ Meter_humanUnit(buffer, this->values[1], sizeof(buffer));
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " buffers:");
+ RichString_appendAscii(out, CRT_colors[MEMORY_BUFFERS_TEXT], buffer);
+ Meter_humanUnit(buffer, this->values[2], sizeof(buffer));
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " cache:");
+ RichString_appendAscii(out, CRT_colors[MEMORY_CACHE], buffer);
}
const MeterClass MemoryMeter_class = {
diff --git a/Meter.c b/Meter.c
index 945911c..2fe949e 100644
--- a/Meter.c
+++ b/Meter.c
@@ -39,6 +39,7 @@ Meter* Meter_new(const struct ProcessList_* pl, int param, const MeterClass* typ
this->param = param;
this->pl = pl;
this->curItems = type->maxItems;
+ this->curAttributes = NULL;
this->values = type->maxItems ? xCalloc(type->maxItems, sizeof(double)) : NULL;
this->total = type->total;
this->caption = xStrdup(type->caption);
@@ -100,7 +101,7 @@ static inline void Meter_displayBuffer(const Meter* this, const char* buffer, Ri
if (Object_displayFn(this)) {
Object_display(this, out);
} else {
- RichString_write(out, CRT_colors[Meter_attributes(this)[0]], buffer);
+ RichString_writeWide(out, CRT_colors[Meter_attributes(this)[0]], buffer);
}
}
@@ -156,16 +157,20 @@ ListItem* Meter_toListItem(Meter* this, bool moving) {
static void TextMeterMode_draw(Meter* this, int x, int y, int w) {
char buffer[METER_BUFFER_LEN];
Meter_updateValues(this, buffer, sizeof(buffer));
- (void) w;
attrset(CRT_colors[METER_TEXT]);
- mvaddstr(y, x, this->caption);
+ mvaddnstr(y, x, this->caption, w - 1);
+ attrset(CRT_colors[RESET_COLOR]);
+
int captionLen = strlen(this->caption);
x += captionLen;
- attrset(CRT_colors[RESET_COLOR]);
+ w -= captionLen;
+ if (w <= 0)
+ return;
+
RichString_begin(out);
Meter_displayBuffer(this, buffer, &out);
- RichString_printVal(out, y, x);
+ RichString_printoffnVal(out, y, x, 0, w - 1);
RichString_end(out);
}
@@ -185,7 +190,7 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
w -= captionLen;
attrset(CRT_colors[BAR_BORDER]);
mvaddch(y, x, '[');
- mvaddch(y, x + w, ']');
+ mvaddch(y, x + MAXIMUM(w, 0), ']');
attrset(CRT_colors[RESET_COLOR]);
w--;
@@ -195,14 +200,29 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
return;
// The text in the bar is right aligned;
- // calculate needed padding and generate leading spaces
- const int textLen = mbstowcs(NULL, buffer, 0);
- const int padding = CLAMP(w - textLen, 0, w);
-
+ // Pad with maximal spaces and then calculate needed starting position offset
RichString_begin(bar);
- RichString_appendChr(&bar, ' ', padding);
- RichString_append(&bar, 0, buffer);
- assert(RichString_sizeVal(bar) >= w);
+ RichString_appendChr(&bar, ' ', w);
+ RichString_appendWide(&bar, 0, buffer);
+ int startPos = RichString_sizeVal(bar) - w;
+ if (startPos > w) {
+ // Text is too large for bar
+ // Truncate meter text at a space character
+ for (int pos = 2 * w; pos > w; pos--) {
+ if (RichString_getCharVal(bar, pos) == ' ') {
+ while (pos > w && RichString_getCharVal(bar, pos - 1) == ' ')
+ pos--;
+ startPos = pos - w;
+ break;
+ }
+ }
+
+ // If still to large, print the start not the end
+ startPos = MINIMUM(startPos, w);
+ }
+ assert(startPos >= 0);
+ assert(startPos <= w);
+ assert(startPos + w <= RichString_sizeVal(bar));
int blockSizes[10];
@@ -220,11 +240,11 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
// (Control against invalid values)
nextOffset = CLAMP(nextOffset, 0, w);
for (int j = offset; j < nextOffset; j++)
- if (RichString_getCharVal(bar, j) == ' ') {
+ if (RichString_getCharVal(bar, startPos + j) == ' ') {
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
- RichString_setChar(&bar, j, BarMeterMode_characters[i]);
+ RichString_setChar(&bar, startPos + j, BarMeterMode_characters[i]);
} else {
- RichString_setChar(&bar, j, '|');
+ RichString_setChar(&bar, startPos + j, '|');
}
}
offset = nextOffset;
@@ -233,14 +253,15 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
// ...then print the buffer.
offset = 0;
for (uint8_t i = 0; i < this->curItems; i++) {
- RichString_setAttrn(&bar, CRT_colors[Meter_attributes(this)[i]], offset, offset + blockSizes[i] - 1);
- RichString_printoffnVal(bar, y, x + offset, offset, blockSizes[i]);
+ int attr = this->curAttributes ? this->curAttributes[i] : Meter_attributes(this)[i];
+ RichString_setAttrn(&bar, CRT_colors[attr], startPos + offset, blockSizes[i]);
+ RichString_printoffnVal(bar, y, x + offset, startPos + offset, MINIMUM(blockSizes[i], w - offset));
offset += blockSizes[i];
offset = CLAMP(offset, 0, w);
}
if (offset < w) {
- RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], offset, w - 1);
- RichString_printoffnVal(bar, y, x + offset, offset, w - offset);
+ RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], startPos + offset, w - offset);
+ RichString_printoffnVal(bar, y, x + offset, startPos + offset, w - offset);
}
RichString_end(bar);
@@ -271,9 +292,6 @@ static const char* const GraphMeterMode_dotsAscii[] = {
/*20*/":", /*21*/":", /*22*/":"
};
-static const char* const* GraphMeterMode_dots;
-static int GraphMeterMode_pixPerRow;
-
static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
if (!this->drawData) {
@@ -282,6 +300,8 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
GraphData* data = this->drawData;
const int nValues = METER_BUFFER_LEN;
+ const char* const* GraphMeterMode_dots;
+ int GraphMeterMode_pixPerRow;
#ifdef HAVE_LIBNCURSESW
if (CRT_utf8) {
GraphMeterMode_dots = GraphMeterMode_dotsUtf8;
diff --git a/Meter.h b/Meter.h
index cb05405..2a78fd1 100644
--- a/Meter.h
+++ b/Meter.h
@@ -100,6 +100,7 @@ struct Meter_ {
int h;
const ProcessList* pl;
uint8_t curItems;
+ const int* curAttributes;
double* values;
double total;
void* meterData;
diff --git a/MetersPanel.c b/MetersPanel.c
index 7e47ad8..30991a0 100644
--- a/MetersPanel.c
+++ b/MetersPanel.c
@@ -20,9 +20,9 @@ in the source distribution for its full text.
// Note: In code the meters are known to have bar/text/graph "Modes", but in UI
// we call them "Styles".
-static const char* const MetersFunctions[] = {"Style ", "Move ", " ", "Delete", "Done ", NULL};
-static const char* const MetersKeys[] = {"Space", "Enter", " ", "Del", "F10"};
-static int MetersEvents[] = {' ', 13, ERR, KEY_DC, KEY_F(10)};
+static const char* const MetersFunctions[] = {"Style ", "Move ", " ", "Delete", "Done ", NULL};
+static const char* const MetersKeys[] = {"Space", "Enter", "", "Del", "F10"};
+static const int MetersEvents[] = {' ', 13, ERR, KEY_DC, KEY_F(10)};
// We avoid UTF-8 arrows ← → here as they might display full-width on Chinese
// terminals, breaking our aligning.
@@ -30,7 +30,7 @@ static int MetersEvents[] = {' ', 13, ERR, KEY_DC, KEY_F(10)};
// considered "Ambiguous characters".
static const char* const MetersMovingFunctions[] = {"Style ", "Lock ", "Up ", "Down ", "Left ", "Right ", " ", "Delete", "Done ", NULL};
static const char* const MetersMovingKeys[] = {"Space", "Enter", "Up", "Dn", "<-", "->", " ", "Del", "F10"};
-static int MetersMovingEvents[] = {' ', 13, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, ERR, KEY_DC, KEY_F(10)};
+static const int MetersMovingEvents[] = {' ', 13, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, ERR, KEY_DC, KEY_F(10)};
static FunctionBar* Meters_movingBar = NULL;
void MetersPanel_cleanup() {
@@ -55,13 +55,12 @@ void MetersPanel_setMoving(MetersPanel* this, bool moving) {
selected->moving = moving;
}
if (!moving) {
- Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOCUS]);
+ Panel_setSelectionColor(super, PANEL_SELECTION_FOCUS);
Panel_setDefaultBar(super);
} else {
- Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOLLOW]);
+ Panel_setSelectionColor(super, PANEL_SELECTION_FOLLOW);
super->currentBar = Meters_movingBar;
}
- FunctionBar_draw(this->super.currentBar);
}
static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int selected) {
diff --git a/NetworkIOMeter.c b/NetworkIOMeter.c
index 90ec990..a898b31 100644
--- a/NetworkIOMeter.c
+++ b/NetworkIOMeter.c
@@ -88,24 +88,24 @@ static void NetworkIOMeter_updateValues(ATTR_UNUSED Meter* this, char* buffer, s
static void NetworkIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
if (!hasData) {
- RichString_write(out, CRT_colors[METER_VALUE_ERROR], "no data");
+ RichString_writeAscii(out, CRT_colors[METER_VALUE_ERROR], "no data");
return;
}
char buffer[64];
- RichString_write(out, CRT_colors[METER_TEXT], "rx: ");
+ RichString_writeAscii(out, CRT_colors[METER_TEXT], "rx: ");
Meter_humanUnit(buffer, cached_rxb_diff, sizeof(buffer));
- RichString_append(out, CRT_colors[METER_VALUE_IOREAD], buffer);
- RichString_append(out, CRT_colors[METER_VALUE_IOREAD], "iB/s");
+ RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], "iB/s");
- RichString_append(out, CRT_colors[METER_TEXT], " tx: ");
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " tx: ");
Meter_humanUnit(buffer, cached_txb_diff, sizeof(buffer));
- RichString_append(out, CRT_colors[METER_VALUE_IOWRITE], buffer);
- RichString_append(out, CRT_colors[METER_VALUE_IOWRITE], "iB/s");
+ RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], "iB/s");
xSnprintf(buffer, sizeof(buffer), " (%lu/%lu packets) ", cached_rxp_diff, cached_txp_diff);
- RichString_append(out, CRT_colors[METER_TEXT], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], buffer);
}
const MeterClass NetworkIOMeter_class = {
diff --git a/Object.h b/Object.h
index 2c3ba9f..89933fa 100644
--- a/Object.h
+++ b/Object.h
@@ -24,7 +24,7 @@ struct Object_;
typedef struct Object_ Object;
typedef void(*Object_Display)(const Object*, RichString*);
-typedef long(*Object_Compare)(const void*, const void*);
+typedef int(*Object_Compare)(const void*, const void*);
typedef void(*Object_Delete)(Object*);
#define Object_getClass(obj_) ((const Object*)(obj_))->klass
diff --git a/OpenFilesScreen.c b/OpenFilesScreen.c
index b1137c7..75eb2d3 100644
--- a/OpenFilesScreen.c
+++ b/OpenFilesScreen.c
@@ -74,7 +74,7 @@ OpenFilesScreen* OpenFilesScreen_new(const Process* process) {
} else {
this->pid = process->pid;
}
- return (OpenFilesScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 3, " FD TYPE MODE DEVICE SIZE NODE NAME");
+ return (OpenFilesScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " FD TYPE MODE DEVICE SIZE NODE NAME");
}
void OpenFilesScreen_delete(Object* this) {
diff --git a/OptionItem.c b/OptionItem.c
index 00001fc..688fab8 100644
--- a/OptionItem.c
+++ b/OptionItem.c
@@ -29,14 +29,14 @@ static void CheckItem_display(const Object* cast, RichString* out) {
const CheckItem* this = (const CheckItem*)cast;
assert (this != NULL);
- RichString_write(out, CRT_colors[CHECK_BOX], "[");
+ RichString_writeAscii(out, CRT_colors[CHECK_BOX], "[");
if (CheckItem_get(this)) {
- RichString_append(out, CRT_colors[CHECK_MARK], "x");
+ RichString_appendAscii(out, CRT_colors[CHECK_MARK], "x");
} else {
- RichString_append(out, CRT_colors[CHECK_MARK], " ");
+ RichString_appendAscii(out, CRT_colors[CHECK_MARK], " ");
}
- RichString_append(out, CRT_colors[CHECK_BOX], "] ");
- RichString_append(out, CRT_colors[CHECK_TEXT], this->super.text);
+ RichString_appendAscii(out, CRT_colors[CHECK_BOX], "] ");
+ RichString_appendWide(out, CRT_colors[CHECK_TEXT], this->super.text);
}
static void NumberItem_display(const Object* cast, RichString* out) {
@@ -44,7 +44,7 @@ static void NumberItem_display(const Object* cast, RichString* out) {
assert (this != NULL);
char buffer[12];
- RichString_write(out, CRT_colors[CHECK_BOX], "[");
+ RichString_writeAscii(out, CRT_colors[CHECK_BOX], "[");
int written;
if (this->scale < 0) {
written = xSnprintf(buffer, sizeof(buffer), "%.*f", -this->scale, pow(10, this->scale) * NumberItem_get(this));
@@ -53,12 +53,12 @@ static void NumberItem_display(const Object* cast, RichString* out) {
} else {
written = xSnprintf(buffer, sizeof(buffer), "%d", NumberItem_get(this));
}
- RichString_append(out, CRT_colors[CHECK_MARK], buffer);
- RichString_append(out, CRT_colors[CHECK_BOX], "]");
+ RichString_appendAscii(out, CRT_colors[CHECK_MARK], buffer);
+ RichString_appendAscii(out, CRT_colors[CHECK_BOX], "]");
for (int i = written; i < 5; i++) {
- RichString_append(out, CRT_colors[CHECK_BOX], " ");
+ RichString_appendAscii(out, CRT_colors[CHECK_BOX], " ");
}
- RichString_append(out, CRT_colors[CHECK_TEXT], this->super.text);
+ RichString_appendWide(out, CRT_colors[CHECK_TEXT], this->super.text);
}
const OptionItemClass OptionItem_class = {
diff --git a/Panel.c b/Panel.c
index 21dfbe2..5d10375 100644
--- a/Panel.c
+++ b/Panel.c
@@ -30,7 +30,7 @@ const PanelClass Panel_class = {
.eventHandler = Panel_selectByTyping,
};
-Panel* Panel_new(int x, int y, int w, int h, bool owner, const ObjectClass* type, FunctionBar* fuBar) {
+Panel* Panel_new(int x, int y, int w, int h, const ObjectClass* type, bool owner, FunctionBar* fuBar) {
Panel* this;
this = xMalloc(sizeof(Panel));
Object_setClass(this, Class(Panel));
@@ -55,11 +55,13 @@ void Panel_init(Panel* this, int x, int y, int w, int h, const ObjectClass* type
this->scrollH = 0;
this->selected = 0;
this->oldSelected = 0;
+ this->selectedLen = 0;
this->needsRedraw = true;
+ this->wasFocus = false;
RichString_beginAllocated(this->header);
this->defaultBar = fuBar;
this->currentBar = fuBar;
- this->selectionColor = CRT_colors[PANEL_SELECTION_FOCUS];
+ this->selectionColorId = PANEL_SELECTION_FOCUS;
}
void Panel_done(Panel* this) {
@@ -70,19 +72,12 @@ void Panel_done(Panel* this) {
RichString_end(this->header);
}
-void Panel_setSelectionColor(Panel* this, int color) {
- this->selectionColor = color;
-}
-
-RichString* Panel_getHeader(Panel* this) {
- assert (this != NULL);
-
- this->needsRedraw = true;
- return &(this->header);
+void Panel_setSelectionColor(Panel* this, ColorElements colorId) {
+ this->selectionColorId = colorId;
}
inline void Panel_setHeader(Panel* this, const char* header) {
- RichString_write(&(this->header), CRT_colors[PANEL_HEADER_FOCUS], header);
+ RichString_writeWide(&(this->header), CRT_colors[PANEL_HEADER_FOCUS], header);
this->needsRedraw = true;
}
@@ -97,10 +92,6 @@ void Panel_move(Panel* this, int x, int y) {
void Panel_resize(Panel* this, int w, int h) {
assert (this != NULL);
- if (RichString_sizeVal(this->header) > 0) {
- h--;
- }
-
this->w = w;
this->h = h;
this->needsRedraw = true;
@@ -217,7 +208,7 @@ void Panel_splice(Panel* this, Vector* from) {
this->needsRedraw = true;
}
-void Panel_draw(Panel* this, bool focus, bool highlightSelected) {
+void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelected, bool hideFunctionBar) {
assert (this != NULL);
int size = Vector_size(this->items);
@@ -226,12 +217,21 @@ void Panel_draw(Panel* this, bool focus, bool highlightSelected) {
int x = this->x;
int h = this->h;
+ if (hideFunctionBar)
+ h++;
+
+ const int header_attr = focus
+ ? CRT_colors[PANEL_HEADER_FOCUS]
+ : CRT_colors[PANEL_HEADER_UNFOCUS];
+ if (force_redraw) {
+ if (Panel_printHeaderFn(this))
+ Panel_printHeader(this);
+ else
+ RichString_setAttr(&this->header, header_attr);
+ }
int headerLen = RichString_sizeVal(this->header);
if (headerLen > 0) {
- int attr = focus
- ? CRT_colors[PANEL_HEADER_FOCUS]
- : CRT_colors[PANEL_HEADER_UNFOCUS];
- attrset(attr);
+ attrset(header_attr);
mvhline(y, x, ' ', this->w);
if (scrollH < headerLen) {
RichString_printoffnVal(this->header, y, x, scrollH,
@@ -239,6 +239,7 @@ void Panel_draw(Panel* this, bool focus, bool highlightSelected) {
}
attrset(CRT_colors[RESET_COLOR]);
y++;
+ h--;
}
// ensure scroll area is on screen
@@ -262,10 +263,10 @@ void Panel_draw(Panel* this, bool focus, bool highlightSelected) {
int upTo = MINIMUM(first + h, size);
int selectionColor = focus
- ? this->selectionColor
+ ? CRT_colors[this->selectionColorId]
: CRT_colors[PANEL_SELECTION_UNFOCUS];
- if (this->needsRedraw) {
+ if (this->needsRedraw || force_redraw) {
int line = 0;
for (int i = first; line < h && i < upTo; i++) {
Object* itemObj = Vector_get(this->items, i);
@@ -293,7 +294,6 @@ void Panel_draw(Panel* this, bool focus, bool highlightSelected) {
mvhline(y + line, x, ' ', this->w);
line++;
}
- this->needsRedraw = false;
} else {
Object* oldObj = Vector_get(this->items, this->oldSelected);
@@ -319,17 +319,35 @@ void Panel_draw(Panel* this, bool focus, bool highlightSelected) {
RichString_end(new);
RichString_end(old);
}
+
+ if (focus && (this->needsRedraw || force_redraw || !this->wasFocus)) {
+ if (Panel_drawFunctionBarFn(this))
+ Panel_drawFunctionBar(this, hideFunctionBar);
+ else if (!hideFunctionBar)
+ FunctionBar_draw(this->currentBar);
+ }
+
this->oldSelected = this->selected;
+ this->wasFocus = focus;
+ this->needsRedraw = false;
move(0, 0);
}
+static int Panel_headerHeight(const Panel* this) {
+ return RichString_sizeVal(this->header) > 0 ? 1 : 0;
+}
+
bool Panel_onKey(Panel* this, int key) {
assert (this != NULL);
- int size = Vector_size(this->items);
+ const int size = Vector_size(this->items);
- #define CLAMP_INDEX(var, delta, min, max) \
- CLAMP((var) + (delta), (min), MAXIMUM(0, (max)))
+ #define PANEL_SCROLL(amount) \
+ do { \
+ this->selected += (amount); \
+ this->scrollV = CLAMP(this->scrollV + (amount), 0, MAXIMUM(0, (size - this->h - Panel_headerHeight(this)))); \
+ this->needsRedraw = true; \
+ } while (0)
switch (key) {
case KEY_DOWN:
@@ -363,27 +381,19 @@ bool Panel_onKey(Panel* this, int key) {
break;
case KEY_PPAGE:
- this->selected -= (this->h - 1);
- this->scrollV = CLAMP_INDEX(this->scrollV, -(this->h - 1), 0, size - this->h);
- this->needsRedraw = true;
+ PANEL_SCROLL(-(this->h - Panel_headerHeight(this)));
break;
case KEY_NPAGE:
- this->selected += (this->h - 1);
- this->scrollV = CLAMP_INDEX(this->scrollV, +(this->h - 1), 0, size - this->h);
- this->needsRedraw = true;
+ PANEL_SCROLL(+(this->h - Panel_headerHeight(this)));
break;
case KEY_WHEELUP:
- this->selected -= CRT_scrollWheelVAmount;
- this->scrollV = CLAMP_INDEX(this->scrollV, -CRT_scrollWheelVAmount, 0, size - this->h);
- this->needsRedraw = true;
+ PANEL_SCROLL(-CRT_scrollWheelVAmount);
break;
case KEY_WHEELDOWN:
- this->selected += CRT_scrollWheelVAmount;
- this->scrollV = CLAMP_INDEX(this->scrollV, +CRT_scrollWheelVAmount, 0, size - this->h);
- this->needsRedraw = true;
+ PANEL_SCROLL(+CRT_scrollWheelVAmount);
break;
case KEY_HOME:
@@ -408,7 +418,7 @@ bool Panel_onKey(Panel* this, int key) {
return false;
}
- #undef CLAMP_INDEX
+ #undef PANEL_SCROLL
// ensure selection within bounds
if (this->selected < 0 || size == 0) {
diff --git a/Panel.h b/Panel.h
index 86c134e..945718a 100644
--- a/Panel.h
+++ b/Panel.h
@@ -9,6 +9,7 @@ in the source distribution for its full text.
#include <stdbool.h>
+#include "CRT.h"
#include "FunctionBar.h"
#include "Object.h"
#include "RichString.h"
@@ -22,9 +23,10 @@ typedef enum HandlerResult_ {
HANDLED = 0x01,
IGNORED = 0x02,
BREAK_LOOP = 0x04,
- REDRAW = 0x08,
- RESCAN = 0x10,
- SYNTH_KEY = 0x20,
+ REFRESH = 0x08,
+ REDRAW = 0x10,
+ RESCAN = 0x20,
+ SYNTH_KEY = 0x40,
} HandlerResult;
#define EVENT_SET_SELECTED (-1)
@@ -33,16 +35,24 @@ typedef enum HandlerResult_ {
#define EVENT_IS_HEADER_CLICK(ev_) ((ev_) >= -10000 && (ev_) <= -9000)
#define EVENT_HEADER_CLICK_GET_X(ev_) ((ev_) + 10000)
-typedef HandlerResult(*Panel_EventHandler)(Panel*, int);
+typedef HandlerResult (*Panel_EventHandler)(Panel*, int);
+typedef void (*Panel_DrawFunctionBar)(Panel*, bool);
+typedef void (*Panel_PrintHeader)(Panel*);
typedef struct PanelClass_ {
const ObjectClass super;
const Panel_EventHandler eventHandler;
+ const Panel_DrawFunctionBar drawFunctionBar;
+ const Panel_PrintHeader printHeader;
} PanelClass;
-#define As_Panel(this_) ((const PanelClass*)((this_)->super.klass))
-#define Panel_eventHandlerFn(this_) As_Panel(this_)->eventHandler
-#define Panel_eventHandler(this_, ev_) As_Panel(this_)->eventHandler((Panel*)(this_), ev_)
+#define As_Panel(this_) ((const PanelClass*)((this_)->super.klass))
+#define Panel_eventHandlerFn(this_) As_Panel(this_)->eventHandler
+#define Panel_eventHandler(this_, ev_) (assert(As_Panel(this_)->eventHandler), As_Panel(this_)->eventHandler((Panel*)(this_), ev_))
+#define Panel_drawFunctionBarFn(this_) As_Panel(this_)->drawFunctionBar
+#define Panel_drawFunctionBar(this_, hideFB_) (assert(As_Panel(this_)->drawFunctionBar), As_Panel(this_)->drawFunctionBar((Panel*)(this_), hideFB_))
+#define Panel_printHeaderFn(this_) As_Panel(this_)->printHeader
+#define Panel_printHeader(this_) (assert(As_Panel(this_)->printHeader), As_Panel(this_)->printHeader((Panel*)(this_)))
struct Panel_ {
Object super;
@@ -55,10 +65,11 @@ struct Panel_ {
int scrollV;
short scrollH;
bool needsRedraw;
+ bool wasFocus;
FunctionBar* currentBar;
FunctionBar* defaultBar;
RichString header;
- int selectionColor;
+ ColorElements selectionColorId;
};
#define Panel_setDefaultBar(this_) do { (this_)->currentBar = (this_)->defaultBar; } while (0)
@@ -67,7 +78,7 @@ struct Panel_ {
extern const PanelClass Panel_class;
-Panel* Panel_new(int x, int y, int w, int h, bool owner, const ObjectClass* type, FunctionBar* fuBar);
+Panel* Panel_new(int x, int y, int w, int h, const ObjectClass* type, bool owner, FunctionBar* fuBar);
void Panel_delete(Object* cast);
@@ -75,9 +86,7 @@ void Panel_init(Panel* this, int x, int y, int w, int h, const ObjectClass* type
void Panel_done(Panel* this);
-void Panel_setSelectionColor(Panel* this, int color);
-
-RichString* Panel_getHeader(Panel* this);
+void Panel_setSelectionColor(Panel* this, ColorElements colorId);
void Panel_setHeader(Panel* this, const char* header);
@@ -109,7 +118,7 @@ int Panel_size(Panel* this);
void Panel_setSelected(Panel* this, int selected);
-void Panel_draw(Panel* this, bool focus, bool highlightSelected);
+void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelected, bool hideFunctionBar);
void Panel_splice(Panel* this, Vector* from);
diff --git a/Process.c b/Process.c
index 8245f86..a78fd23 100644
--- a/Process.c
+++ b/Process.c
@@ -38,23 +38,15 @@ in the source distribution for its full text.
static uid_t Process_getuid = (uid_t)-1;
-char Process_pidFormat[20] = "%7d ";
-
-static char Process_titleBuffer[20][20];
+int Process_pidDigits = 7;
void Process_setupColumnWidths() {
int maxPid = Platform_getMaxPid();
if (maxPid == -1)
return;
- int digits = ceil(log10(maxPid));
- assert(digits < 20);
- for (int i = 0; Process_pidColumns[i].label; i++) {
- assert(i < 20);
- xSnprintf(Process_titleBuffer[i], 20, "%*s ", digits, Process_pidColumns[i].label);
- Process_fields[Process_pidColumns[i].id].title = Process_titleBuffer[i];
- }
- xSnprintf(Process_pidFormat, sizeof(Process_pidFormat), "%%%dd ", digits);
+ Process_pidDigits = ceil(log10(maxPid));
+ assert(Process_pidDigits <= PROCESS_MAX_PID_DIGITS);
}
void Process_humanNumber(RichString* str, unsigned long long number, bool coloring) {
@@ -74,53 +66,53 @@ void Process_humanNumber(RichString* str, unsigned long long number, bool colori
if (number < 1000) {
//Plain number, no markings
len = xSnprintf(buffer, sizeof(buffer), "%5llu ", number);
- RichString_appendn(str, processColor, buffer, len);
+ 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_appendn(str, processMegabytesColor, buffer, len);
+ RichString_appendnAscii(str, processMegabytesColor, buffer, len);
number %= 1000;
len = xSnprintf(buffer, sizeof(buffer), "%03llu ", number);
- RichString_appendn(str, processColor, buffer, len);
+ 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_appendn(str, processMegabytesColor, buffer, len);
+ 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_appendn(str, processGigabytesColor, buffer, len);
+ RichString_appendnAscii(str, processGigabytesColor, buffer, len);
number %= 1000;
len = xSnprintf(buffer, sizeof(buffer), "%03lluM ", number);
- RichString_appendn(str, processMegabytesColor, buffer, len);
+ 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_appendn(str, processGigabytesColor, buffer, len);
+ RichString_appendnAscii(str, processGigabytesColor, buffer, len);
number %= 10;
len = xSnprintf(buffer, sizeof(buffer), ".%1llu", number);
- RichString_appendn(str, processMegabytesColor, buffer, len);
- RichString_append(str, processGigabytesColor, "G ");
+ 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_appendn(str, processGigabytesColor, buffer, len);
+ 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_appendn(str, largeNumberColor, buffer, len);
+ RichString_appendnAscii(str, largeNumberColor, buffer, len);
number %= 1000;
len = xSnprintf(buffer, sizeof(buffer), "%03lluG ", number);
- RichString_appendn(str, processGigabytesColor, buffer, len);
+ RichString_appendnAscii(str, processGigabytesColor, buffer, len);
} else {
//2 digit TB and above
len = xSnprintf(buffer, sizeof(buffer), "%4.1lfT ", (double)number/ONE_G);
- RichString_appendn(str, largeNumberColor, buffer, len);
+ RichString_appendnAscii(str, largeNumberColor, buffer, len);
}
}
@@ -139,26 +131,25 @@ void Process_colorNumber(RichString* str, unsigned long long number, bool colori
}
if (number == ULLONG_MAX) {
- int len = xSnprintf(buffer, sizeof(buffer), " N/A ");
- RichString_appendn(str, CRT_colors[PROCESS_SHADOW], buffer, len);
+ 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_appendn(str, largeNumberColor, buffer, 12);
+ RichString_appendnAscii(str, largeNumberColor, buffer, 12);
} else if (number >= 100LL * ONE_DECIMAL_T) {
xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_M);
- RichString_appendn(str, largeNumberColor, buffer, 8);
- RichString_appendn(str, processMegabytesColor, buffer+8, 4);
+ 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_appendn(str, largeNumberColor, buffer, 5);
- RichString_appendn(str, processMegabytesColor, buffer+5, 3);
- RichString_appendn(str, processColor, buffer+8, 4);
+ 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_appendn(str, largeNumberColor, buffer, 2);
- RichString_appendn(str, processMegabytesColor, buffer+2, 3);
- RichString_appendn(str, processColor, buffer+5, 3);
- RichString_appendn(str, processShadowColor, buffer+8, 4);
+ 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);
}
}
@@ -172,16 +163,16 @@ void Process_printTime(RichString* str, unsigned long long totalHundredths) {
char buffer[10];
if (hours >= 100) {
xSnprintf(buffer, sizeof(buffer), "%7lluh ", hours);
- RichString_append(str, CRT_colors[LARGE_NUMBER], buffer);
+ RichString_appendAscii(str, CRT_colors[LARGE_NUMBER], buffer);
} else {
if (hours) {
xSnprintf(buffer, sizeof(buffer), "%2lluh", hours);
- RichString_append(str, CRT_colors[LARGE_NUMBER], buffer);
+ RichString_appendAscii(str, CRT_colors[LARGE_NUMBER], buffer);
xSnprintf(buffer, sizeof(buffer), "%02d:%02d ", minutes, seconds);
} else {
xSnprintf(buffer, sizeof(buffer), "%2d:%02d.%02d ", minutes, seconds, hundredths);
}
- RichString_append(str, CRT_colors[DEFAULT_COLOR], buffer);
+ RichString_appendAscii(str, CRT_colors[DEFAULT_COLOR], buffer);
}
}
@@ -192,34 +183,34 @@ void Process_fillStarttimeBuffer(Process* this) {
}
static inline void Process_writeCommand(const Process* this, int attr, int baseattr, RichString* str) {
- int start = RichString_size(str), finish = 0;
+ int start = RichString_size(str);
+ int len = 0;
const char* comm = this->comm;
if (this->settings->highlightBaseName || !this->settings->showProgramPath) {
- int i, basename = 0;
- for (i = 0; i < this->basenameOffset; i++) {
+ int basename = 0;
+ for (int i = 0; i < this->basenameOffset; i++) {
if (comm[i] == '/') {
basename = i + 1;
} else if (comm[i] == ':') {
- finish = i + 1;
+ len = i + 1;
break;
}
}
- if (!finish) {
+ if (len == 0) {
if (this->settings->showProgramPath) {
start += basename;
} else {
comm += basename;
}
- finish = this->basenameOffset - basename;
+ len = this->basenameOffset - basename;
}
- finish += start - 1;
}
- RichString_append(str, attr, comm);
+ RichString_appendWide(str, attr, comm);
if (this->settings->highlightBaseName) {
- RichString_setAttrn(str, baseattr, start, finish);
+ RichString_setAttrn(str, baseattr, start, len);
}
}
@@ -234,26 +225,30 @@ void Process_outputRate(RichString* str, char* buffer, size_t n, double rate, in
}
if (isnan(rate)) {
- int len = xSnprintf(buffer, n, " N/A ");
- RichString_appendn(str, CRT_colors[PROCESS_SHADOW], buffer, len);
+ RichString_appendAscii(str, CRT_colors[PROCESS_SHADOW], " N/A ");
} else if (rate < ONE_K) {
int len = snprintf(buffer, n, "%7.2f B/s ", rate);
- RichString_appendn(str, processColor, buffer, len);
+ RichString_appendnAscii(str, processColor, buffer, len);
} else if (rate < ONE_M) {
int len = snprintf(buffer, n, "%7.2f K/s ", rate / ONE_K);
- RichString_appendn(str, processColor, buffer, len);
+ RichString_appendnAscii(str, processColor, buffer, len);
} else if (rate < ONE_G) {
int len = snprintf(buffer, n, "%7.2f M/s ", rate / ONE_M);
- RichString_appendn(str, processMegabytesColor, buffer, len);
+ RichString_appendnAscii(str, processMegabytesColor, buffer, len);
} else if (rate < ONE_T) {
int len = snprintf(buffer, n, "%7.2f G/s ", rate / ONE_G);
- RichString_appendn(str, largeNumberColor, buffer, len);
+ RichString_appendnAscii(str, largeNumberColor, buffer, len);
} else {
int len = snprintf(buffer, n, "%7.2f T/s ", rate / ONE_T);
- RichString_appendn(str, largeNumberColor, buffer, len);
+ RichString_appendnAscii(str, largeNumberColor, buffer, len);
}
}
+void Process_printLeftAlignedField(RichString* str, int attr, const char* content, unsigned int width) {
+ int c = RichString_appendnWide(str, attr, content, MINIMUM(width, strlen(content)));
+ RichString_appendChr(str, ' ', width + 1 - c);
+}
+
void Process_writeField(const Process* this, RichString* str, ProcessField field) {
char buffer[256]; buffer[255] = '\0';
int attr = CRT_colors[DEFAULT_COLOR];
@@ -320,17 +315,18 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
buf += written;
n -= written;
}
- const char* draw = CRT_treeStr[lastItem ? (this->settings->direction == 1 ? TREE_STR_BEND : TREE_STR_TEND) : TREE_STR_RTEE];
+
+ const char* draw = CRT_treeStr[lastItem ? TREE_STR_BEND : TREE_STR_RTEE];
xSnprintf(buf, n, "%s%s ", draw, this->showChildren ? CRT_treeStr[TREE_STR_SHUT] : CRT_treeStr[TREE_STR_OPEN] );
- RichString_append(str, CRT_colors[PROCESS_TREE], buffer);
+ RichString_appendWide(str, CRT_colors[PROCESS_TREE], buffer);
Process_writeCommand(this, attr, baseattr, str);
return;
}
}
case MAJFLT: Process_colorNumber(str, this->majflt, coloring); return;
case MINFLT: Process_colorNumber(str, this->minflt, coloring); return;
- case M_RESIDENT: Process_humanNumber(str, this->m_resident * CRT_pageSizeKB, coloring); return;
- case M_VIRT: Process_humanNumber(str, this->m_virt * CRT_pageSizeKB, coloring); return;
+ case M_RESIDENT: Process_humanNumber(str, this->m_resident, coloring); return;
+ case M_VIRT: Process_humanNumber(str, this->m_virt, coloring); return;
case NICE: {
xSnprintf(buffer, n, "%3ld ", this->nice);
attr = this->nice < 0 ? CRT_colors[PROCESS_HIGH_PRIORITY]
@@ -339,9 +335,9 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
break;
}
case NLWP: xSnprintf(buffer, n, "%4ld ", this->nlwp); break;
- case PGRP: xSnprintf(buffer, n, Process_pidFormat, this->pgrp); break;
- case PID: xSnprintf(buffer, n, Process_pidFormat, this->pid); break;
- case PPID: xSnprintf(buffer, n, Process_pidFormat, this->ppid); 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 PRIORITY: {
if(this->priority <= -100)
xSnprintf(buffer, n, " RT ");
@@ -350,7 +346,7 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
break;
}
case PROCESSOR: xSnprintf(buffer, n, "%3d ", Settings_cpuId(this->settings, this->processor)); break;
- case SESSION: xSnprintf(buffer, n, Process_pidFormat, this->session); 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 ", this->state);
@@ -366,27 +362,25 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
}
case ST_UID: xSnprintf(buffer, n, "%5d ", this->st_uid); break;
case TIME: Process_printTime(str, this->time); return;
- case TGID: xSnprintf(buffer, n, Process_pidFormat, this->tgid); break;
- case TPGID: xSnprintf(buffer, n, Process_pidFormat, this->tpgid); break;
+ case TGID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->tgid); break;
+ case TPGID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->tpgid); break;
case TTY_NR: xSnprintf(buffer, n, "%3u:%3u ", major(this->tty_nr), minor(this->tty_nr)); break;
case USER: {
if (Process_getuid != this->st_uid)
attr = CRT_colors[PROCESS_SHADOW];
+
if (this->user) {
- xSnprintf(buffer, n, "%-9s ", this->user);
- } else {
- xSnprintf(buffer, n, "%-9d ", this->st_uid);
- }
- if (buffer[9] != '\0') {
- buffer[9] = ' ';
- buffer[10] = '\0';
+ Process_printLeftAlignedField(str, attr, this->user, 9);
+ return;
}
+
+ xSnprintf(buffer, n, "%-9d ", this->st_uid);
break;
}
default:
xSnprintf(buffer, n, "- ");
}
- RichString_append(str, attr, buffer);
+ RichString_appendWide(str, attr, buffer);
}
void Process_display(const Object* cast, RichString* out) {
@@ -449,13 +443,13 @@ void Process_init(Process* this, const struct Settings_* settings) {
}
void Process_toggleTag(Process* this) {
- this->tag = this->tag == true ? false : true;
+ this->tag = !this->tag;
}
bool Process_isNew(const Process* this) {
assert(this->processList);
if (this->processList->scanTs >= this->seenTs) {
- return this->processList->scanTs - this->seenTs <= this->processList->settings->highlightDelaySecs;
+ return this->processList->scanTs - this->seenTs <= 1000 * this->processList->settings->highlightDelaySecs;
}
return false;
}
@@ -486,18 +480,18 @@ bool Process_sendSignal(Process* this, Arg sgn) {
return ok;
}
-long Process_pidCompare(const void* v1, const void* v2) {
+int Process_pidCompare(const void* v1, const void* v2) {
const Process* p1 = (const Process*)v1;
const Process* p2 = (const Process*)v2;
- return (p1->pid - p2->pid);
+
+ return SPACESHIP_NUMBER(p1->pid, p2->pid);
}
-long Process_compare(const void* v1, const void* v2) {
+int Process_compare(const void* v1, const void* v2) {
const Process *p1, *p2;
const Settings *settings = ((const Process*)v1)->settings;
- int r;
- if (settings->direction == 1) {
+ if (Settings_getActiveDirection(settings) == 1) {
p1 = (const Process*)v1;
p2 = (const Process*)v2;
} else {
@@ -505,7 +499,21 @@ long Process_compare(const void* v1, const void* v2) {
p1 = (const Process*)v2;
}
- switch (settings->sortKey) {
+ ProcessField key = Settings_getActiveSortKey(settings);
+
+ int result = Process_compareByKey(p1, p2, key);
+
+ // Implement tie-breaker (needed to make tree mode more stable)
+ if (!result)
+ result = SPACESHIP_NUMBER(p1->pid, p2->pid);
+
+ return result;
+}
+
+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(p2->percent_cpu, p1->percent_cpu);
diff --git a/Process.h b/Process.h
index 48e31b1..1a88a63 100644
--- a/Process.h
+++ b/Process.h
@@ -13,17 +13,14 @@ in the source distribution for its full text.
#include <sys/types.h>
#include "Object.h"
+#include "ProcessField.h"
#include "RichString.h"
-#ifdef __ANDROID__
-#define SYS_ioprio_get __NR_ioprio_get
-#define SYS_ioprio_set __NR_ioprio_set
-#endif
#define PROCESS_FLAG_IO 0x0001
#define DEFAULT_HIGHLIGHT_SECS 5
-typedef enum ProcessFields {
+typedef enum ProcessField_ {
NULL_PROCESSFIELD = 0,
PID = 1,
COMM = 2,
@@ -49,12 +46,12 @@ typedef enum ProcessFields {
NLWP = 51,
TGID = 52,
PERCENT_NORM_CPU = 53,
-} ProcessField;
-typedef struct ProcessPidColumn_ {
- int id;
- const char* label;
-} ProcessPidColumn;
+ /* Platform specific fields, defined in ${platform}/ProcessField.h */
+ PLATFORM_PROCESS_FIELDS
+
+ LAST_PROCESSFIELD
+} ProcessField;
struct Settings_;
@@ -120,30 +117,34 @@ typedef struct ProcessFieldData_ {
const char* title;
const char* description;
uint32_t flags;
+ bool pidColumn;
} ProcessFieldData;
// Implemented in platform-specific code:
void Process_writeField(const Process* this, RichString* str, ProcessField field);
-long Process_compare(const void* v1, const void* v2);
+int Process_compare(const void* v1, const void* v2);
void Process_delete(Object* cast);
bool Process_isThread(const Process* this);
-extern ProcessFieldData Process_fields[];
-extern ProcessPidColumn Process_pidColumns[];
-extern char Process_pidFormat[20];
+extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
+#define PROCESS_MAX_PID_DIGITS 19
+extern int Process_pidDigits;
typedef Process*(*Process_New)(const struct Settings_*);
typedef void (*Process_WriteField)(const Process*, RichString*, ProcessField);
+typedef int (*Process_CompareByKey)(const Process*, const Process*, ProcessField);
typedef const char* (*Process_GetCommandStr)(const Process*);
typedef struct ProcessClass_ {
const ObjectClass super;
const Process_WriteField writeField;
+ const Process_CompareByKey compareByKey;
const Process_GetCommandStr getCommandStr;
} ProcessClass;
-#define As_Process(this_) ((const ProcessClass*)((this_)->super.klass))
+#define As_Process(this_) ((const ProcessClass*)((this_)->super.klass))
-#define Process_getCommand(this_) (As_Process(this_)->getCommandStr ? As_Process(this_)->getCommandStr((const Process*)(this_)) : ((const Process*)(this_))->comm)
+#define Process_getCommand(this_) (As_Process(this_)->getCommandStr ? As_Process(this_)->getCommandStr((const Process*)(this_)) : ((const Process*)(this_))->comm)
+#define Process_compareByKey(p1_, p2_, key_) (As_Process(p1_)->compareByKey ? (As_Process(p1_)->compareByKey(p1_, p2_, key_)) : Process_compareByKey_Base(p1_, p2_, key_))
static inline pid_t Process_getParentPid(const Process* this) {
return this->tgid == this->pid ? this->ppid : this->tgid;
@@ -178,6 +179,8 @@ void Process_fillStarttimeBuffer(Process* this);
void Process_outputRate(RichString* str, char* buffer, size_t n, double rate, int coloring);
+void Process_printLeftAlignedField(RichString* str, int attr, const char* content, unsigned int width);
+
void Process_display(const Object* cast, RichString* out);
void Process_done(Process* this);
@@ -198,6 +201,8 @@ bool Process_changePriorityBy(Process* this, Arg delta);
bool Process_sendSignal(Process* this, Arg sgn);
-long Process_pidCompare(const void* v1, const void* v2);
+int Process_pidCompare(const void* v1, const void* v2);
+
+int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField key);
#endif
diff --git a/ProcessList.c b/ProcessList.c
index 2d27339..055ad1f 100644
--- a/ProcessList.c
+++ b/ProcessList.c
@@ -10,8 +10,8 @@ in the source distribution for its full text.
#include <assert.h>
#include <stdlib.h>
#include <string.h>
-#include <time.h>
+#include "Compat.h"
#include "CRT.h"
#include "Hashtable.h"
#include "Macros.h"
@@ -79,22 +79,48 @@ void ProcessList_setPanel(ProcessList* this, Panel* panel) {
this->panel = panel;
}
+static const char* alignedProcessFieldTitle(ProcessField field) {
+ const char* title = Process_fields[field].title;
+ if (!title)
+ return "- ";
+
+ if (!Process_fields[field].pidColumn)
+ return title;
+
+ static char titleBuffer[PROCESS_MAX_PID_DIGITS + /* space */ 1 + /* null-terminator */ + 1];
+ xSnprintf(titleBuffer, sizeof(titleBuffer), "%*s ", Process_pidDigits, title);
+
+ return titleBuffer;
+}
+
void ProcessList_printHeader(ProcessList* this, RichString* header) {
RichString_prune(header);
- const ProcessField* fields = this->settings->fields;
+ const Settings* settings = this->settings;
+ const ProcessField* fields = settings->fields;
+
+ ProcessField key = Settings_getActiveSortKey(settings);
for (int i = 0; fields[i]; i++) {
- const char* field = Process_fields[fields[i]].title;
- if (!field) {
- field = "- ";
+ int color;
+ if (settings->treeView && settings->treeViewAlwaysByPID) {
+ color = CRT_colors[PANEL_HEADER_FOCUS];
+ } else if (key == fields[i]) {
+ color = CRT_colors[PANEL_SELECTION_FOCUS];
+ } else {
+ color = CRT_colors[PANEL_HEADER_FOCUS];
}
- int color = (this->settings->sortKey == fields[i]) ?
- CRT_colors[PANEL_SELECTION_FOCUS] : CRT_colors[PANEL_HEADER_FOCUS];
- RichString_append(header, color, field);
- if (COMM == fields[i] && this->settings->showMergedCommand) {
- RichString_append(header, color, "(merged)");
+ RichString_appendWide(header, color, alignedProcessFieldTitle(fields[i]));
+ if (key == fields[i] && RichString_getCharVal(*header, RichString_size(header) - 1) == ' ') {
+ header->chlen--; // 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],
+ 1);
+ }
+ if (COMM == fields[i] && settings->showMergedCommand) {
+ RichString_appendAscii(header, color, "(merged)");
}
}
}
@@ -122,7 +148,7 @@ void ProcessList_remove(ProcessList* this, Process* p) {
Process* pp = Hashtable_remove(this->processTable, p->pid);
assert(pp == p); (void)pp;
- unsigned int pid = p->pid;
+ pid_t pid = p->pid;
int idx = Vector_indexOf(this->processes, p, Process_pidCompare);
assert(idx != -1);
@@ -130,7 +156,12 @@ void ProcessList_remove(ProcessList* this, Process* p) {
Vector_remove(this->processes, idx);
}
- assert(Hashtable_get(this->processTable, pid) == NULL); (void)pid;
+ if (this->following != -1 && this->following == pid) {
+ this->following = -1;
+ Panel_setSelectionColor(this->panel, PANEL_SELECTION_FOCUS);
+ }
+
+ assert(Hashtable_get(this->processTable, pid) == NULL);
assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
}
@@ -149,7 +180,7 @@ int ProcessList_size(ProcessList* this) {
//
// The algorithm is based on `depth-first search`,
// even though `breadth-first search` approach may be more efficient on first glance,
-// after comparision it may be not, as it's not safe to go deeper without first updating the tree structure.
+// after comparison it may be not, as it's not safe to go deeper without first updating the tree structure.
// If it would be safe that approach would likely bring an advantage in performance.
//
// Each call of the function looks for a 'layer'. A 'layer' is a list of processes with the same depth.
@@ -329,14 +360,14 @@ static void ProcessList_buildTreeBranch(ProcessList* this, pid_t pid, int level,
Vector_delete(children);
}
-static long ProcessList_treeProcessCompare(const void* v1, const void* v2) {
+static int ProcessList_treeProcessCompare(const void* v1, const void* v2) {
const Process *p1 = (const Process*)v1;
const Process *p2 = (const Process*)v2;
return SPACESHIP_NUMBER(p1->tree_left, p2->tree_left);
}
-static long ProcessList_treeProcessCompareByPID(const void* v1, const void* v2) {
+static int ProcessList_treeProcessCompareByPID(const void* v1, const void* v2) {
const Process *p1 = (const Process*)v1;
const Process *p2 = (const Process*)v2;
@@ -347,7 +378,7 @@ static long ProcessList_treeProcessCompareByPID(const void* v1, const void* v2)
static void ProcessList_buildTree(ProcessList* this) {
int node_counter = 1;
int node_index = 0;
- int direction = this->settings->direction;
+ int direction = Settings_getActiveDirection(this->settings);
// Sort by PID
Vector_quickSortCustomCompare(this->processes, ProcessList_treeProcessCompareByPID);
@@ -446,12 +477,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++) {
- const char* title = Process_fields[field].title;
- if (!title) {
- title = "- ";
- }
-
- int len = strlen(title);
+ int len = strlen(alignedProcessFieldTitle(field));
if (at >= x && at <= x + len) {
return field;
}
@@ -472,30 +498,26 @@ void ProcessList_rebuildPanel(ProcessList* this) {
const char* incFilter = this->incFilter;
int currPos = Panel_getSelectedIndex(this->panel);
- pid_t currPid = this->following != -1 ? this->following : 0;
int currScrollV = this->panel->scrollV;
Panel_prune(this->panel);
int size = ProcessList_size(this);
int idx = 0;
for (int i = 0; i < size; i++) {
- bool hidden = false;
Process* p = ProcessList_get(this, i);
if ( (!p->show)
|| (this->userId != (uid_t) -1 && (p->st_uid != this->userId))
|| (incFilter && !(String_contains_i(Process_getCommand(p), incFilter)))
|| (this->pidMatchList && !Hashtable_get(this->pidMatchList, p->tgid)) )
- hidden = true;
+ continue;
- if (!hidden) {
- Panel_set(this->panel, idx, (Object*)p);
- if ((this->following == -1 && idx == currPos) || (this->following != -1 && p->pid == currPid)) {
- Panel_setSelected(this->panel, idx);
- this->panel->scrollV = currScrollV;
- }
- idx++;
+ Panel_set(this->panel, idx, (Object*)p);
+ if ((this->following == -1 && idx == currPos) || (this->following != -1 && p->pid == this->following)) {
+ Panel_setSelected(this->panel, idx);
+ this->panel->scrollV = currScrollV;
}
+ idx++;
}
}
@@ -541,8 +563,10 @@ void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate) {
if (!firstScanDone) {
this->scanTs = 0;
firstScanDone = true;
- } else if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) {
- this->scanTs = now.tv_sec;
+ } 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);
@@ -558,7 +582,7 @@ void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate) {
// process no longer exists
if (this->settings->highlightChanges && p->wasShown) {
// mark tombed
- p->tombTs = this->scanTs + this->settings->highlightDelaySecs;
+ p->tombTs = this->scanTs + 1000 * this->settings->highlightDelaySecs;
} else {
// immediately remove
ProcessList_remove(this, p);
diff --git a/ProcessLocksScreen.c b/ProcessLocksScreen.c
index 3e7762a..5759615 100644
--- a/ProcessLocksScreen.c
+++ b/ProcessLocksScreen.c
@@ -27,7 +27,7 @@ ProcessLocksScreen* ProcessLocksScreen_new(const Process* process) {
this->pid = process->tgid;
else
this->pid = process->pid;
- return (ProcessLocksScreen*) InfoScreen_init(&this->super, process, NULL, LINES-3, " ID TYPE EXCLUSION READ/WRITE DEVICE:INODE START END FILENAME");
+ return (ProcessLocksScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " ID TYPE EXCLUSION READ/WRITE DEVICE:INODE START END FILENAME");
}
void ProcessLocksScreen_delete(Object* this) {
diff --git a/RichString.c b/RichString.c
index 790c15a..0130580 100644
--- a/RichString.c
+++ b/RichString.c
@@ -7,6 +7,7 @@ in the source distribution for its full text.
#include "RichString.h"
+#include <ctype.h>
#include <stdlib.h>
#include <string.h>
@@ -47,25 +48,35 @@ static void RichString_setLen(RichString* this, int len) {
#ifdef HAVE_LIBNCURSESW
-static inline void RichString_writeFrom(RichString* this, int attrs, const char* data_c, int from, int len) {
+static inline int RichString_writeFromWide(RichString* this, int attrs, const char* data_c, int from, int len) {
wchar_t data[len + 1];
len = mbstowcs(data, data_c, len);
- if (len < 0)
- return;
+ if (len <= 0)
+ return 0;
int newLen = from + len;
RichString_setLen(this, newLen);
for (int i = from, j = 0; i < newLen; i++, j++) {
this->chptr[i] = (CharType) { .attr = attrs & 0xffffff, .chars = { (iswprint(data[j]) ? data[j] : '?') } };
}
+
+ return wcswidth(data, len);
}
-inline void RichString_setAttrn(RichString* this, int attrs, int start, int finish) {
- cchar_t* ch = this->chptr + start;
- finish = CLAMP(finish, 0, this->chlen - 1);
- for (int i = start; i <= finish; i++) {
- ch->attr = attrs;
- ch++;
+static inline int RichString_writeFromAscii(RichString* this, int attrs, const char* data, int from, int len) {
+ int newLen = from + len;
+ RichString_setLen(this, newLen);
+ for (int i = from, j = 0; i < newLen; i++, j++) {
+ this->chptr[i] = (CharType) { .attr = attrs & 0xffffff, .chars = { (isprint(data[j]) ? data[j] : '?') } };
+ }
+
+ return len;
+}
+
+inline void RichString_setAttrn(RichString* this, int attrs, int start, int charcount) {
+ int end = CLAMP(start + charcount, 0, this->chlen);
+ for (int i = start; i < end; i++) {
+ this->chptr[i].attr = attrs;
}
}
@@ -82,21 +93,25 @@ int RichString_findChar(RichString* this, char c, int start) {
#else /* HAVE_LIBNCURSESW */
-static inline void RichString_writeFrom(RichString* this, int attrs, const char* data_c, int from, int len) {
+static inline int RichString_writeFromWide(RichString* this, int attrs, const char* data_c, int from, int len) {
int newLen = from + len;
RichString_setLen(this, newLen);
for (int i = from, j = 0; i < newLen; i++, j++) {
this->chptr[i] = (((unsigned char)data_c[j]) >= 32 ? ((unsigned char)data_c[j]) : '?') | attrs;
}
this->chptr[newLen] = 0;
+
+ return len;
}
-void RichString_setAttrn(RichString* this, int attrs, int start, int finish) {
- chtype* ch = this->chptr + start;
- finish = CLAMP(finish, 0, this->chlen - 1);
- for (int i = start; i <= finish; i++) {
- *ch = (*ch & 0xff) | attrs;
- ch++;
+static inline int RichString_writeFromAscii(RichString* this, int attrs, const char* data_c, int from, int len) {
+ return RichString_writeFromWide(this, attrs, data_c, from, len);
+}
+
+void RichString_setAttrn(RichString* this, int attrs, int start, int charcount) {
+ int end = CLAMP(start + charcount, 0, this->chlen);
+ for (int i = start; i < end; i++) {
+ this->chptr[i] = (this->chptr[i] & 0xff) | attrs;
}
}
@@ -129,17 +144,29 @@ void RichString_appendChr(RichString* this, char c, int count) {
}
void RichString_setAttr(RichString* this, int attrs) {
- RichString_setAttrn(this, attrs, 0, this->chlen - 1);
+ RichString_setAttrn(this, attrs, 0, this->chlen);
+}
+
+int RichString_appendWide(RichString* this, int attrs, const char* data) {
+ return RichString_writeFromWide(this, attrs, data, this->chlen, strlen(data));
+}
+
+int RichString_appendnWide(RichString* this, int attrs, const char* data, int len) {
+ return RichString_writeFromWide(this, attrs, data, this->chlen, len);
+}
+
+int RichString_writeWide(RichString* this, int attrs, const char* data) {
+ return RichString_writeFromWide(this, attrs, data, 0, strlen(data));
}
-void RichString_append(RichString* this, int attrs, const char* data) {
- RichString_writeFrom(this, attrs, data, this->chlen, strlen(data));
+int RichString_appendAscii(RichString* this, int attrs, const char* data) {
+ return RichString_writeFromAscii(this, attrs, data, this->chlen, strlen(data));
}
-void RichString_appendn(RichString* this, int attrs, const char* data, int len) {
- RichString_writeFrom(this, attrs, data, this->chlen, len);
+int RichString_appendnAscii(RichString* this, int attrs, const char* data, int len) {
+ return RichString_writeFromAscii(this, attrs, data, this->chlen, len);
}
-void RichString_write(RichString* this, int attrs, const char* data) {
- RichString_writeFrom(this, attrs, data, 0, strlen(data));
+int RichString_writeAscii(RichString* this, int attrs, const char* data) {
+ return RichString_writeFromAscii(this, attrs, data, 0, strlen(data));
}
diff --git a/RichString.h b/RichString.h
index 262befc..4145b0d 100644
--- a/RichString.h
+++ b/RichString.h
@@ -42,7 +42,7 @@ typedef struct RichString_ {
int highlightAttr;
} RichString;
-void RichString_setAttrn(RichString* this, int attrs, int start, int finish);
+void RichString_setAttrn(RichString* this, int attrs, int start, int charcount);
int RichString_findChar(RichString* this, char c, int start);
@@ -52,10 +52,16 @@ void RichString_setAttr(RichString* this, int attrs);
void RichString_appendChr(RichString* this, char c, int count);
-void RichString_append(RichString* this, int attrs, const char* data);
+int RichString_appendWide(RichString* this, int attrs, const char* data);
-void RichString_appendn(RichString* this, int attrs, const char* data, int len);
+int RichString_appendnWide(RichString* this, int attrs, const char* data, int len);
-void RichString_write(RichString* this, int attrs, const char* data);
+int RichString_writeWide(RichString* this, int attrs, const char* data);
+
+int RichString_appendAscii(RichString* this, int attrs, const char* data);
+
+int RichString_appendnAscii(RichString* this, int attrs, const char* data, int len);
+
+int RichString_writeAscii(RichString* this, int attrs, const char* data);
#endif
diff --git a/ScreenManager.c b/ScreenManager.c
index ac93721..0ab5231 100644
--- a/ScreenManager.c
+++ b/ScreenManager.c
@@ -106,7 +106,7 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi
if (*rescan) {
*oldTime = newTime;
ProcessList_scan(pl, this->state->pauseProcessUpdate);
- if (*sortTimeout == 0 || this->settings->treeView) {
+ if (!this->state->pauseProcessUpdate && (*sortTimeout == 0 || this->settings->treeView)) {
ProcessList_sort(pl);
*sortTimeout = 1;
}
@@ -119,29 +119,20 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi
*rescan = false;
}
-static void ScreenManager_drawPanels(ScreenManager* this, int focus) {
+static void ScreenManager_drawPanels(ScreenManager* this, int focus, bool force_redraw) {
const int nPanels = this->panelCount;
for (int i = 0; i < nPanels; i++) {
Panel* panel = (Panel*) Vector_get(this->panels, i);
- Panel_draw(panel, i == focus, !((panel == this->state->panel) && this->state->hideProcessSelection));
- mvvline(panel->y, panel->x + panel->w, ' ', panel->h + 1);
+ Panel_draw(panel, force_redraw, i == focus, !((panel == this->state->panel) && this->state->hideProcessSelection), State_hideFunctionBar(this->state));
+ mvvline(panel->y, panel->x + panel->w, ' ', panel->h + (State_hideFunctionBar(this->state) ? 1 : 0));
}
}
-static Panel* setCurrentPanel(const ScreenManager* this, Panel* panel) {
- FunctionBar_draw(panel->currentBar);
- if (panel == this->state->panel && this->state->pauseProcessUpdate) {
- FunctionBar_append("PAUSED", CRT_colors[PAUSED]);
- }
-
- return panel;
-}
-
void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
bool quit = false;
int focus = 0;
- Panel* panelFocus = setCurrentPanel(this, (Panel*) Vector_get(this->panels, focus));
+ Panel* panelFocus = (Panel*) Vector_get(this->panels, focus);
double oldTime = 0.0;
@@ -150,6 +141,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
bool timedOut = true;
bool redraw = true;
+ bool force_redraw = true;
bool rescan = false;
int sortTimeout = 0;
int resetSortTimeout = 5;
@@ -159,8 +151,9 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
checkRecalculation(this, &oldTime, &sortTimeout, &redraw, &rescan, &timedOut);
}
- if (redraw) {
- ScreenManager_drawPanels(this, focus);
+ if (redraw || force_redraw) {
+ ScreenManager_drawPanels(this, focus, force_redraw);
+ force_redraw = false;
}
int prevCh = ch;
@@ -187,7 +180,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
ch = KEY_MOUSE;
if (panel == panelFocus || this->allowFocusChange) {
focus = i;
- panelFocus = setCurrentPanel(this, panel);
+ panelFocus = panel;
Object* oldSelection = Panel_getSelected(panel);
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
if (Panel_getSelected(panel) == oldSelection) {
@@ -234,9 +227,12 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
if (result & SYNTH_KEY) {
ch = result >> 16;
}
- if (result & REDRAW) {
+ if (result & REFRESH) {
sortTimeout = 0;
}
+ if (result & REDRAW) {
+ force_redraw = true;
+ }
if (result & RESCAN) {
rescan = true;
sortTimeout = 0;
@@ -269,7 +265,7 @@ tryLeft:
focus--;
}
- panelFocus = setCurrentPanel(this, (Panel*) Vector_get(this->panels, focus));
+ panelFocus = (Panel*) Vector_get(this->panels, focus);
if (Panel_size(panelFocus) == 0 && focus > 0) {
goto tryLeft;
}
@@ -290,7 +286,7 @@ tryRight:
focus++;
}
- panelFocus = setCurrentPanel(this, (Panel*) Vector_get(this->panels, focus));
+ panelFocus = (Panel*) Vector_get(this->panels, focus);
if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1) {
goto tryRight;
}
diff --git a/Settings.c b/Settings.c
index 0b4d0ed..ef607f0 100644
--- a/Settings.c
+++ b/Settings.c
@@ -96,10 +96,10 @@ static void readFields(ProcessField* fields, uint32_t* flags, const char* line)
free(trim);
int i, j;
*flags = 0;
- for (j = 0, i = 0; i < Platform_numberOfFields && ids[i]; i++) {
+ for (j = 0, i = 0; i < LAST_PROCESSFIELD && ids[i]; i++) {
// This "+1" is for compatibility with the older enum format.
int id = atoi(ids[i]) + 1;
- if (id > 0 && id < Platform_numberOfFields && Process_fields[id].name) {
+ if (id > 0 && id < LAST_PROCESSFIELD && Process_fields[id].name) {
fields[j] = id;
*flags |= Process_fields[id].flags;
j++;
@@ -137,10 +137,17 @@ static bool Settings_read(Settings* this, const char* fileName, int initialCpuCo
} else if (String_eq(option[0], "sort_key")) {
// This "+1" is for compatibility with the older enum format.
this->sortKey = atoi(option[1]) + 1;
+ } else if (String_eq(option[0], "tree_sort_key")) {
+ // This "+1" is for compatibility with the older enum format.
+ this->treeSortKey = atoi(option[1]) + 1;
} else if (String_eq(option[0], "sort_direction")) {
this->direction = atoi(option[1]);
+ } else if (String_eq(option[0], "tree_sort_direction")) {
+ this->treeDirection = atoi(option[1]);
} else if (String_eq(option[0], "tree_view")) {
this->treeView = atoi(option[1]);
+ } else if (String_eq(option[0], "tree_view_always_by_pid")) {
+ this->treeViewAlwaysByPID = atoi(option[1]);
} else if (String_eq(option[0], "hide_kernel_threads")) {
this->hideKernelThreads = atoi(option[1]);
} else if (String_eq(option[0], "hide_userland_threads")) {
@@ -214,6 +221,8 @@ static bool Settings_read(Settings* this, const char* fileName, int initialCpuCo
} else if (String_eq(option[0], "right_meter_modes")) {
Settings_readMeterModes(this, option[1], 1);
didReadMeters = true;
+ } else if (String_eq(option[0], "hide_function_bar")) {
+ this->hideFunctionBar = atoi(option[1]);
#ifdef HAVE_LIBHWLOC
} else if (String_eq(option[0], "topology_affinity")) {
this->topologyAffinity = !!atoi(option[1]);
@@ -273,6 +282,8 @@ bool Settings_write(Settings* this) {
// This "-1" is for compatibility with the older enum format.
fprintf(fd, "sort_key=%d\n", (int) this->sortKey - 1);
fprintf(fd, "sort_direction=%d\n", (int) this->direction);
+ fprintf(fd, "tree_sort_key=%d\n", (int) this->treeSortKey - 1);
+ fprintf(fd, "tree_sort_direction=%d\n", (int) this->treeDirection);
fprintf(fd, "hide_kernel_threads=%d\n", (int) this->hideKernelThreads);
fprintf(fd, "hide_userland_threads=%d\n", (int) this->hideUserlandThreads);
fprintf(fd, "shadow_other_users=%d\n", (int) this->shadowOtherUsers);
@@ -287,6 +298,7 @@ bool Settings_write(Settings* this) {
fprintf(fd, "strip_exe_from_cmdline=%d\n", (int) this->stripExeFromCmdline);
fprintf(fd, "show_merged_command=%d\n", (int) this->showMergedCommand);
fprintf(fd, "tree_view=%d\n", (int) this->treeView);
+ fprintf(fd, "tree_view_always_by_pid=%d\n", (int) this->treeViewAlwaysByPID);
fprintf(fd, "header_margin=%d\n", (int) this->headerMargin);
fprintf(fd, "detailed_cpu_time=%d\n", (int) this->detailedCPUTime);
fprintf(fd, "cpu_count_from_one=%d\n", (int) this->countCPUsFromOne);
@@ -305,6 +317,7 @@ bool Settings_write(Settings* this) {
fprintf(fd, "left_meter_modes="); writeMeterModes(this, fd, 0);
fprintf(fd, "right_meters="); writeMeters(this, fd, 1);
fprintf(fd, "right_meter_modes="); writeMeterModes(this, fd, 1);
+ fprintf(fd, "hide_function_bar=%d\n", (int) this->hideFunctionBar);
#ifdef HAVE_LIBHWLOC
fprintf(fd, "topology_affinity=%d\n", (int) this->topologyAffinity);
#endif
@@ -316,7 +329,9 @@ Settings* Settings_new(int initialCpuCount) {
Settings* this = xCalloc(1, sizeof(Settings));
this->sortKey = PERCENT_CPU;
+ this->treeSortKey = PID;
this->direction = 1;
+ this->treeDirection = 1;
this->shadowOtherUsers = false;
this->showThreadNames = false;
this->hideKernelThreads = false;
@@ -340,14 +355,15 @@ Settings* Settings_new(int initialCpuCount) {
this->findCommInCmdline = true;
this->stripExeFromCmdline = true;
this->showMergedCommand = false;
+ this->hideFunctionBar = 0;
#ifdef HAVE_LIBHWLOC
this->topologyAffinity = false;
#endif
- this->fields = xCalloc(Platform_numberOfFields + 1, sizeof(ProcessField));
+ this->fields = xCalloc(LAST_PROCESSFIELD + 1, sizeof(ProcessField));
// TODO: turn 'fields' into a Vector,
// (and ProcessFields into proper objects).
this->flags = 0;
- ProcessField* defaults = Platform_defaultFields;
+ const ProcessField* defaults = Platform_defaultFields;
for (int i = 0; defaults[i]; i++) {
this->fields[i] = defaults[i];
this->flags |= Process_fields[defaults[i]].flags;
@@ -427,9 +443,17 @@ Settings* Settings_new(int initialCpuCount) {
}
void Settings_invertSortOrder(Settings* this) {
- if (this->direction == 1) {
- this->direction = -1;
- } else {
+ int* attr = (this->treeView) ? &(this->treeDirection) : &(this->direction);
+ *attr = (*attr == 1) ? -1 : 1;
+}
+
+void Settings_setSortKey(Settings* this, ProcessField sortKey) {
+ if (this->treeViewAlwaysByPID || !this->treeView) {
+ this->sortKey = sortKey;
this->direction = 1;
+ this->treeView = false;
+ } else {
+ this->treeSortKey = sortKey;
+ this->treeDirection = 1;
}
}
diff --git a/Settings.h b/Settings.h
index 752970a..fdaf3e3 100644
--- a/Settings.h
+++ b/Settings.h
@@ -33,7 +33,9 @@ typedef struct Settings_ {
int delay;
int direction;
+ int treeDirection;
ProcessField sortKey;
+ ProcessField treeSortKey;
bool countCPUsFromOne;
bool detailedCPUTime;
@@ -44,6 +46,7 @@ typedef struct Settings_ {
bool degreeFahrenheit;
#endif
bool treeView;
+ bool treeViewAlwaysByPID;
bool showProgramPath;
bool shadowOtherUsers;
bool showThreadNames;
@@ -61,6 +64,7 @@ typedef struct Settings_ {
bool accountGuestInCPUMeter;
bool headerMargin;
bool enableMouse;
+ int hideFunctionBar; // 0 - off, 1 - on ESC until next input, 2 - permanently
#ifdef HAVE_LIBHWLOC
bool topologyAffinity;
#endif
@@ -70,6 +74,16 @@ typedef struct Settings_ {
#define Settings_cpuId(settings, cpu) ((settings)->countCPUsFromOne ? (cpu)+1 : (cpu))
+static inline ProcessField Settings_getActiveSortKey(const Settings* this) {
+ return (this->treeView)
+ ? (this->treeViewAlwaysByPID ? PID : this->treeSortKey)
+ : this->sortKey;
+}
+
+static inline int Settings_getActiveDirection(const Settings* this) {
+ return this->treeView ? this->treeDirection : this->direction;
+}
+
void Settings_delete(Settings* this);
bool Settings_write(Settings* this);
@@ -78,4 +92,6 @@ Settings* Settings_new(int initialCpuCount);
void Settings_invertSortOrder(Settings* this);
+void Settings_setSortKey(Settings* this, ProcessField sortKey);
+
#endif
diff --git a/SignalsPanel.c b/SignalsPanel.c
index 436fc57..055e3e6 100644
--- a/SignalsPanel.c
+++ b/SignalsPanel.c
@@ -19,7 +19,7 @@ in the source distribution for its full text.
Panel* SignalsPanel_new() {
- Panel* this = Panel_new(1, 1, 1, 1, true, Class(ListItem), FunctionBar_newEnterEsc("Send ", "Cancel "));
+ Panel* this = Panel_new(1, 1, 1, 1, Class(ListItem), true, FunctionBar_newEnterEsc("Send ", "Cancel "));
const int defaultSignal = SIGTERM;
int defaultPosition = 15;
unsigned int i;
diff --git a/SwapMeter.c b/SwapMeter.c
index 8e39c75..e39cfd9 100644
--- a/SwapMeter.c
+++ b/SwapMeter.c
@@ -32,12 +32,12 @@ static void SwapMeter_updateValues(Meter* this, char* buffer, size_t size) {
static void SwapMeter_display(const Object* cast, RichString* out) {
char buffer[50];
const Meter* this = (const Meter*)cast;
- RichString_write(out, CRT_colors[METER_TEXT], ":");
- Meter_humanUnit(buffer, this->total, 50);
- RichString_append(out, CRT_colors[METER_VALUE], buffer);
- Meter_humanUnit(buffer, this->values[0], 50);
- RichString_append(out, CRT_colors[METER_TEXT], " used:");
- RichString_append(out, CRT_colors[METER_VALUE], buffer);
+ RichString_writeAscii(out, CRT_colors[METER_TEXT], ":");
+ Meter_humanUnit(buffer, this->total, sizeof(buffer));
+ RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
+ Meter_humanUnit(buffer, this->values[0], sizeof(buffer));
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " used:");
+ RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
}
const MeterClass SwapMeter_class = {
diff --git a/TasksMeter.c b/TasksMeter.c
index 7696988..a760ce0 100644
--- a/TasksMeter.c
+++ b/TasksMeter.c
@@ -46,7 +46,7 @@ static void TasksMeter_display(const Object* cast, RichString* out) {
int processes = (int) this->values[2];
xSnprintf(buffer, sizeof(buffer), "%d", processes);
- RichString_write(out, CRT_colors[METER_VALUE], buffer);
+ RichString_writeAscii(out, CRT_colors[METER_VALUE], buffer);
int threadValueColor = CRT_colors[METER_VALUE];
int threadCaptionColor = CRT_colors[METER_TEXT];
if (settings->highlightThreads) {
@@ -54,21 +54,21 @@ static void TasksMeter_display(const Object* cast, RichString* out) {
threadCaptionColor = CRT_colors[PROCESS_THREAD];
}
if (!settings->hideUserlandThreads) {
- RichString_append(out, CRT_colors[METER_TEXT], ", ");
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], ", ");
xSnprintf(buffer, sizeof(buffer), "%d", (int)this->values[1]);
- RichString_append(out, threadValueColor, buffer);
- RichString_append(out, threadCaptionColor, " thr");
+ RichString_appendAscii(out, threadValueColor, buffer);
+ RichString_appendAscii(out, threadCaptionColor, " thr");
}
if (!settings->hideKernelThreads) {
- RichString_append(out, CRT_colors[METER_TEXT], ", ");
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], ", ");
xSnprintf(buffer, sizeof(buffer), "%d", (int)this->values[0]);
- RichString_append(out, threadValueColor, buffer);
- RichString_append(out, threadCaptionColor, " kthr");
+ RichString_appendAscii(out, threadValueColor, buffer);
+ RichString_appendAscii(out, threadCaptionColor, " kthr");
}
- RichString_append(out, CRT_colors[METER_TEXT], "; ");
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], "; ");
xSnprintf(buffer, sizeof(buffer), "%d", (int)this->values[3]);
- RichString_append(out, CRT_colors[TASKS_RUNNING], buffer);
- RichString_append(out, CRT_colors[METER_TEXT], " running");
+ RichString_appendAscii(out, CRT_colors[TASKS_RUNNING], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " running");
}
const MeterClass TasksMeter_class = {
diff --git a/TraceScreen.c b/TraceScreen.c
index 47cf0ab..da98e02 100644
--- a/TraceScreen.c
+++ b/TraceScreen.c
@@ -33,17 +33,7 @@ static const char* const TraceScreenFunctions[] = {"Search ", "Filter ", "AutoSc
static const char* const TraceScreenKeys[] = {"F3", "F4", "F8", "F9", "Esc"};
-static int TraceScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(8), KEY_F(9), 27};
-
-const InfoScreenClass TraceScreen_class = {
- .super = {
- .extends = Class(Object),
- .delete = TraceScreen_delete
- },
- .draw = TraceScreen_draw,
- .onErr = TraceScreen_updateTrace,
- .onKey = TraceScreen_onKey,
-};
+static const int TraceScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(8), KEY_F(9), 27};
TraceScreen* TraceScreen_new(Process* process) {
// This initializes all TraceScreen variables to "false" so only default = true ones need to be set below
@@ -70,12 +60,8 @@ void TraceScreen_delete(Object* cast) {
free(InfoScreen_done((InfoScreen*)this));
}
-void TraceScreen_draw(InfoScreen* this) {
- attrset(CRT_colors[PANEL_HEADER_FOCUS]);
- mvhline(0, 0, ' ', COLS);
- mvprintw(0, 0, "Trace of process %d - %s", this->process->pid, Process_getCommand(this->process));
- attrset(CRT_colors[DEFAULT_COLOR]);
- IncSet_drawBar(this->inc);
+static void TraceScreen_draw(InfoScreen* this) {
+ InfoScreen_drawTitled(this, "Trace of process %d - %s", this->process->pid, Process_getCommand(this->process));
}
bool TraceScreen_forkTracer(TraceScreen* this) {
@@ -131,7 +117,7 @@ err:
return false;
}
-void TraceScreen_updateTrace(InfoScreen* super) {
+static void TraceScreen_updateTrace(InfoScreen* super) {
TraceScreen* this = (TraceScreen*) super;
char buffer[1025];
@@ -176,7 +162,7 @@ void TraceScreen_updateTrace(InfoScreen* super) {
}
}
-bool TraceScreen_onKey(InfoScreen* super, int ch) {
+static bool TraceScreen_onKey(InfoScreen* super, int ch) {
TraceScreen* this = (TraceScreen*) super;
switch(ch) {
case 'f':
@@ -195,3 +181,13 @@ bool TraceScreen_onKey(InfoScreen* super, int ch) {
this->follow = false;
return false;
}
+
+const InfoScreenClass TraceScreen_class = {
+ .super = {
+ .extends = Class(Object),
+ .delete = TraceScreen_delete
+ },
+ .draw = TraceScreen_draw,
+ .onErr = TraceScreen_updateTrace,
+ .onKey = TraceScreen_onKey,
+};
diff --git a/TraceScreen.h b/TraceScreen.h
index 8192047..3a2902a 100644
--- a/TraceScreen.h
+++ b/TraceScreen.h
@@ -32,12 +32,6 @@ TraceScreen* TraceScreen_new(Process* process);
void TraceScreen_delete(Object* cast);
-void TraceScreen_draw(InfoScreen* this);
-
bool TraceScreen_forkTracer(TraceScreen* this);
-void TraceScreen_updateTrace(InfoScreen* super);
-
-bool TraceScreen_onKey(InfoScreen* super, int ch);
-
#endif
diff --git a/Vector.h b/Vector.h
index ee51413..875f361 100644
--- a/Vector.h
+++ b/Vector.h
@@ -58,7 +58,7 @@ unsigned int Vector_count(const Vector* this);
#else /* NDEBUG */
-static inline Object* Vector_get(Vector* this, int idx) {
+static inline Object* Vector_get(const Vector* this, int idx) {
return this->array[idx];
}
diff --git a/XUtils.c b/XUtils.c
index cd5edb9..01f3342 100644
--- a/XUtils.c
+++ b/XUtils.c
@@ -13,6 +13,7 @@ in the source distribution for its full text.
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -36,9 +37,21 @@ void* xMalloc(size_t size) {
return data;
}
+void* xMallocArray(size_t nmemb, size_t size) {
+ assert(nmemb > 0);
+ assert(size > 0);
+ if (SIZE_MAX / nmemb < size) {
+ fail();
+ }
+ return xMalloc(nmemb * size);
+}
+
void* xCalloc(size_t nmemb, size_t size) {
assert(nmemb > 0);
assert(size > 0);
+ if (SIZE_MAX / nmemb < size) {
+ fail();
+ }
void* data = calloc(nmemb, size);
if (!data) {
fail();
@@ -56,6 +69,15 @@ void* xRealloc(void* ptr, size_t size) {
return data;
}
+void* xReallocArray(void* ptr, size_t nmemb, size_t size) {
+ assert(nmemb > 0);
+ assert(size > 0);
+ if (SIZE_MAX / nmemb < size) {
+ fail();
+ }
+ return xRealloc(ptr, nmemb * size);
+}
+
char* String_cat(const char* s1, const char* s2) {
const size_t l1 = strlen(s1);
const size_t l2 = strlen(s2);
diff --git a/XUtils.h b/XUtils.h
index 19cfadb..9e5e62c 100644
--- a/XUtils.h
+++ b/XUtils.h
@@ -23,10 +23,14 @@ void fail(void) ATTR_NORETURN;
void* xMalloc(size_t size);
+void* xMallocArray(size_t nmemb, size_t size);
+
void* xCalloc(size_t nmemb, size_t size);
void* xRealloc(void* ptr, size_t size);
+void* xReallocArray(void* ptr, size_t nmemb, size_t size);
+
/*
* String_startsWith gives better performance if strlen(match) can be computed
* at compile time (e.g. when they are immutable string literals). :)
diff --git a/configure.ac b/configure.ac
index f624664..be406c6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.65)
-AC_INIT([htop],[3.0.3],[htop@groups.io])
+AC_INIT([htop],[3.0.5],[htop@groups.io])
AC_CONFIG_SRCDIR([htop.c])
AC_CONFIG_AUX_DIR([.])
@@ -93,13 +93,16 @@ AC_TYPE_UINT64_T
AC_FUNC_CLOSEDIR_VOID
AC_FUNC_STAT
AC_CHECK_FUNCS([\
+ clock_gettime\
faccessat\
fstatat\
+ host_get_clock_service\
openat\
readlinkat\
])
AC_SEARCH_LIBS([dlopen], [dl dld])
+AC_SEARCH_LIBS([clock_gettime], [rt])
save_cflags="${CFLAGS}"
CFLAGS="${CFLAGS} -std=c99"
@@ -165,7 +168,7 @@ m4_define([HTOP_CHECK_SCRIPT],
LIBS="$htop_config_script_libs $LIBS "
htop_script_success=yes
], [
- CFLAGS="$htop_save_CFLAGS"
+ CFLAGS="$htop_save_CFLAGS"
])
LDFLAGS="$htop_save_LDFLAGS"
fi
@@ -188,15 +191,15 @@ AC_DEFUN([AX_CHECK_COMPILE_FLAG],
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
- ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
- _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
- AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
- [AS_VAR_SET(CACHEVAR,[yes])],
- [AS_VAR_SET(CACHEVAR,[no])])
- _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
+ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
+ _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
+ AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
+ [AS_VAR_SET(CACHEVAR,[yes])],
+ [AS_VAR_SET(CACHEVAR,[no])])
+ _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
AS_VAR_IF(CACHEVAR,yes,
- [m4_default([$2], :)],
- [m4_default([$3], :)])
+ [m4_default([$2], :)],
+ [m4_default([$3], :)])
AS_VAR_POPDEF([CACHEVAR])dnl
])dnl AX_CHECK_COMPILE_FLAGS
@@ -209,14 +212,18 @@ if test "x$enable_unicode" = xyes; then
HTOP_CHECK_LIB([ncursesw6], [addnwstr], [HAVE_LIBNCURSESW],
HTOP_CHECK_LIB([ncursesw], [addnwstr], [HAVE_LIBNCURSESW],
HTOP_CHECK_LIB([ncurses], [addnwstr], [HAVE_LIBNCURSESW],
- missing_libraries="$missing_libraries libncursesw"
- AC_MSG_ERROR([You may want to use --disable-unicode or install libncursesw.])
+ missing_libraries="$missing_libraries libncursesw"
+ AC_MSG_ERROR([You may want to use --disable-unicode or install libncursesw.])
)))))))
AC_CHECK_HEADERS([ncursesw/curses.h],[:],
[AC_CHECK_HEADERS([ncurses/ncurses.h],[:],
[AC_CHECK_HEADERS([ncurses/curses.h],[:],
[AC_CHECK_HEADERS([ncurses.h],[:],[missing_headers="$missing_headers $ac_header"])])])])
+
+ # check if additional linker flags are needed for keypad(3)
+ # (at this point we already link against a working ncurses library with wide character support)
+ AC_SEARCH_LIBS([keypad], [tinfow tinfo])
else
HTOP_CHECK_SCRIPT([ncurses6], [refresh], [HAVE_LIBNCURSES], "ncurses6-config",
HTOP_CHECK_SCRIPT([ncurses], [refresh], [HAVE_LIBNCURSES], "ncurses5-config",
@@ -229,6 +236,19 @@ else
[AC_CHECK_HEADERS([ncurses/curses.h],[:],
[AC_CHECK_HEADERS([ncurses/ncurses.h],[:],
[AC_CHECK_HEADERS([ncurses.h],[:],[missing_headers="$missing_headers $ac_header"])])])])
+
+ # check if additional linker flags are needed for keypad(3)
+ # (at this point we already link against a working ncurses library)
+ AC_SEARCH_LIBS([keypad], [tinfo])
+fi
+
+if test "$my_htop_platform" = "darwin"; then
+ AC_CHECK_HEADERS([mach/mach_time.h])
+ AC_CHECK_FUNCS([mach_timebase_info])
+fi
+
+if test "$my_htop_platform" = "dragonflybsd"; then
+ AC_CHECK_LIB([kvm], [kvm_open], [], [missing_libraries="$missing_libraries libkvm"])
fi
if test "$my_htop_platform" = "freebsd"; then
@@ -246,8 +266,7 @@ if test "$my_htop_platform" = "solaris"; then
fi
AC_ARG_ENABLE(hwloc, [AS_HELP_STRING([--enable-hwloc], [enable hwloc support for CPU affinity, disables Linux affinity])],, enable_hwloc="no")
-if test "x$enable_hwloc" = xyes
-then
+if test "x$enable_hwloc" = xyes; then
AC_CHECK_LIB([hwloc], [hwloc_get_proc_cpubind], [], [missing_libraries="$missing_libraries libhwloc"])
AC_CHECK_HEADERS([hwloc.h],[:], [missing_headers="$missing_headers $ac_header"])
fi
@@ -269,9 +288,9 @@ if test "x$enable_linux_affinity" = xcheck; then
if (errno == ENOSYS) return 1;
]])],
[enable_linux_affinity=yes
- AC_MSG_RESULT([yes])],
+ AC_MSG_RESULT([yes])],
[enable_linux_affinity=no
- AC_MSG_RESULT([no])],
+ AC_MSG_RESULT([no])],
[AC_MSG_RESULT([yes (assumed while cross compiling)])])
fi
fi
@@ -279,20 +298,17 @@ if test "x$enable_linux_affinity" = xyes; then
AC_DEFINE(HAVE_LINUX_AFFINITY, 1, [Define if Linux sched_setaffinity and sched_getaffinity are to be used.])
fi
-if test "x$enable_linux_affinity" = xyes -a "x$enable_hwloc" = xyes
-then
+if test "x$enable_linux_affinity" = xyes -a "x$enable_hwloc" = xyes; then
AC_MSG_ERROR([--enable-hwloc and --enable-linux-affinity are mutual exclusive. Specify at most one of them.])
fi
AC_ARG_ENABLE(setuid, [AS_HELP_STRING([--enable-setuid], [enable setuid support for platforms that need it])],, enable_setuid="no")
-if test "x$enable_setuid" = xyes
-then
+if test "x$enable_setuid" = xyes; then
AC_DEFINE(HAVE_SETUID_ENABLED, 1, [Define if setuid support should be enabled.])
fi
AC_ARG_ENABLE(delayacct, [AS_HELP_STRING([--enable-delayacct], [enable Linux delay accounting])],, enable_delayacct="no")
-if test "x$enable_delayacct" = xyes
-then
+if test "x$enable_delayacct" = xyes; then
m4_ifdef([PKG_PROG_PKG_CONFIG], [
PKG_PROG_PKG_CONFIG()
PKG_CHECK_MODULES(LIBNL3, libnl-3.0, [], [missing_libraries="$missing_libraries libnl-3"])
@@ -321,6 +337,7 @@ AM_CFLAGS="\
-Wcast-qual\
-Wextra\
-Wfloat-equal\
+ -Wformat=2\
-Wmissing-format-attribute\
-Wmissing-noreturn\
-Wmissing-prototypes\
@@ -346,10 +363,10 @@ AC_SUBST([AM_CPPFLAGS])
# Bail out on errors.
# ----------------------------------------------------------------------
if test ! -z "$missing_libraries"; then
- AC_MSG_ERROR([missing libraries: $missing_libraries])
+ AC_MSG_ERROR([missing libraries: $missing_libraries])
fi
if test ! -z "$missing_headers"; then
- AC_MSG_ERROR([missing headers: $missing_headers])
+ AC_MSG_ERROR([missing headers: $missing_headers])
fi
AC_DEFINE_UNQUOTED(COPYRIGHT, "(C) 2004-2019 Hisham Muhammad. (C) 2020 htop dev team.", [Copyright message.])
@@ -367,8 +384,7 @@ AC_SUBST(my_htop_platform)
AC_CONFIG_FILES([Makefile htop.1])
AC_OUTPUT
-if test "$my_htop_platform" = "unsupported"
-then
+if test "$my_htop_platform" = "unsupported"; then
echo ""
echo "****************************************************************"
echo "WARNING! This platform is not currently supported by htop."
diff --git a/darwin/DarwinProcess.c b/darwin/DarwinProcess.c
index f3c3425..bedfefe 100644
--- a/darwin/DarwinProcess.c
+++ b/darwin/DarwinProcess.c
@@ -14,17 +14,37 @@ in the source distribution for its full text.
#include <mach/mach.h>
#include "CRT.h"
+#include "Platform.h"
#include "Process.h"
-const ProcessClass DarwinProcess_class = {
- .super = {
- .extends = Class(Process),
- .display = Process_display,
- .delete = Process_delete,
- .compare = Process_compare
- },
- .writeField = Process_writeField,
+const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
+ [0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
+ [PID] = { .name = "PID", .title = "PID", .description = "Process/thread ID", .flags = 0, .pidColumn = true, },
+ [COMM] = { .name = "Command", .title = "Command ", .description = "Command line", .flags = 0, },
+ [STATE] = { .name = "STATE", .title = "S ", .description = "Process state (S sleeping, R running, D disk, Z zombie, T traced, W paging)", .flags = 0, },
+ [PPID] = { .name = "PPID", .title = "PPID", .description = "Parent process ID", .flags = 0, .pidColumn = true, },
+ [PGRP] = { .name = "PGRP", .title = "PGRP", .description = "Process group ID", .flags = 0, .pidColumn = true, },
+ [SESSION] = { .name = "SESSION", .title = "SID", .description = "Process's session ID", .flags = 0, .pidColumn = true, },
+ [TTY_NR] = { .name = "TTY_NR", .title = " TTY ", .description = "Controlling terminal", .flags = 0, },
+ [TPGID] = { .name = "TPGID", .title = "TPGID", .description = "Process ID of the fg process group of the controlling terminal", .flags = 0, .pidColumn = true, },
+ [MINFLT] = { .name = "MINFLT", .title = " MINFLT ", .description = "Number of minor faults which have not required loading a memory page from disk", .flags = 0, },
+ [MAJFLT] = { .name = "MAJFLT", .title = " MAJFLT ", .description = "Number of major faults which have required loading a memory page from disk", .flags = 0, },
+ [PRIORITY] = { .name = "PRIORITY", .title = "PRI ", .description = "Kernel's internal priority for the process", .flags = 0, },
+ [NICE] = { .name = "NICE", .title = " NI ", .description = "Nice value (the higher the value, the more it lets other processes take priority)", .flags = 0, },
+ [STARTTIME] = { .name = "STARTTIME", .title = "START ", .description = "Time the process was started", .flags = 0, },
+
+ [PROCESSOR] = { .name = "PROCESSOR", .title = "CPU ", .description = "Id of the CPU the process last executed on", .flags = 0, },
+ [M_VIRT] = { .name = "M_VIRT", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, },
+ [M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, },
+ [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
+ [PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, },
+ [PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, },
+ [USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
+ [TIME] = { .name = "TIME", .title = " TIME+ ", .description = "Total time the process has spent in user and system time", .flags = 0, },
+ [NLWP] = { .name = "NLWP", .title = "NLWP ", .description = "Number of threads in the process", .flags = 0, },
+ [TGID] = { .name = "TGID", .title = "TGID", .description = "Thread group ID (i.e. process ID)", .flags = 0, .pidColumn = true, },
+ [TRANSLATED] = { .name = "TRANSLATED", .title = "T ", .description = "Translation info (T translated, N native)", .flags = 0, },
};
Process* DarwinProcess_new(const Settings* settings) {
@@ -35,6 +55,7 @@ Process* DarwinProcess_new(const Settings* settings) {
this->utime = 0;
this->stime = 0;
this->taskAccess = true;
+ this->translated = false;
return &this->super;
}
@@ -46,6 +67,34 @@ void Process_delete(Object* cast) {
free(this);
}
+static void DarwinProcess_writeField(const Process* this, RichString* str, ProcessField field) {
+ const DarwinProcess* dp = (const DarwinProcess*) this;
+ char buffer[256]; buffer[255] = '\0';
+ int attr = CRT_colors[DEFAULT_COLOR];
+ int n = sizeof(buffer) - 1;
+ switch (field) {
+ // add Platform-specific fields here
+ case TRANSLATED: xSnprintf(buffer, n, "%c ", dp->translated ? 'T' : 'N'); break;
+ default:
+ Process_writeField(this, str, field);
+ return;
+ }
+ RichString_appendWide(str, attr, buffer);
+}
+
+static int DarwinProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
+ const DarwinProcess* p1 = (const DarwinProcess*)v1;
+ const DarwinProcess* p2 = (const DarwinProcess*)v2;
+
+ switch (key) {
+ // add Platform-specific fields here
+ case TRANSLATED:
+ return SPACESHIP_NUMBER(p1->translated, p2->translated);
+ default:
+ return Process_compareByKey_Base(v1, v2, key);
+ }
+}
+
bool Process_isThread(const Process* this) {
(void) this;
return false;
@@ -195,6 +244,8 @@ ERROR_A:
}
void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps, bool exists) {
+ DarwinProcess* dp = (DarwinProcess*)proc;
+
const struct extern_proc* ep = &ps->kp_proc;
/* UNSET HERE :
@@ -223,6 +274,7 @@ void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps,
/* e_tdev = (major << 24) | (minor & 0xffffff) */
/* e_tdev == -1 for "no device" */
proc->tty_nr = ps->kp_eproc.e_tdev & 0xff; /* TODO tty_nr is unsigned */
+ dp->translated = ps->kp_proc.p_flag & P_TRANSLATED;
proc->starttime_ctime = ep->p_starttime.tv_sec;
Process_fillStarttimeBuffer(proc);
@@ -240,26 +292,24 @@ void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps,
proc->updated = true;
}
-void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList* dpl) {
+void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList* dpl, double time_interval) {
struct proc_taskinfo pti;
if (sizeof(pti) == proc_pidinfo(proc->super.pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti))) {
- if (0 != proc->utime || 0 != proc->stime) {
- uint64_t diff = (pti.pti_total_system - proc->stime)
- + (pti.pti_total_user - proc->utime);
-
- proc->super.percent_cpu = (double)diff * (double)dpl->super.cpuCount
- / ((double)dpl->global_diff * 100000.0);
-
-// fprintf(stderr, "%f %llu %llu %llu %llu %llu\n", proc->super.percent_cpu,
-// proc->stime, proc->utime, pti.pti_total_system, pti.pti_total_user, dpl->global_diff);
-// exit(7);
+ uint64_t total_existing_time = proc->stime + proc->utime;
+ uint64_t total_current_time = pti.pti_total_system + pti.pti_total_user;
+
+ if (total_existing_time && 1E-6 < time_interval) {
+ uint64_t total_time_diff = total_current_time - total_existing_time;
+ proc->super.percent_cpu = ((double)total_time_diff / time_interval) * 100.0;
+ } else {
+ proc->super.percent_cpu = 0.0;
}
- proc->super.time = (pti.pti_total_system + pti.pti_total_user) / 10000000;
+ proc->super.time = total_current_time / 10000000;
proc->super.nlwp = pti.pti_threadnum;
- proc->super.m_virt = pti.pti_virtual_size / CRT_pageSize;
- proc->super.m_resident = pti.pti_resident_size / CRT_pageSize;
+ proc->super.m_virt = pti.pti_virtual_size / ONE_K;
+ proc->super.m_resident = pti.pti_resident_size / ONE_K;
proc->super.majflt = pti.pti_faults;
proc->super.percent_mem = (double)pti.pti_resident_size * 100.0
/ (double)dpl->host_info.max_mem;
@@ -341,3 +391,15 @@ void DarwinProcess_scanThreads(DarwinProcess* dp) {
}
proc->state = state;
}
+
+
+const ProcessClass DarwinProcess_class = {
+ .super = {
+ .extends = Class(Process),
+ .display = Process_display,
+ .delete = Process_delete,
+ .compare = Process_compare
+ },
+ .writeField = DarwinProcess_writeField,
+ .compareByKey = DarwinProcess_compareByKey,
+};
diff --git a/darwin/DarwinProcess.h b/darwin/DarwinProcess.h
index 98897c9..f87dd18 100644
--- a/darwin/DarwinProcess.h
+++ b/darwin/DarwinProcess.h
@@ -19,10 +19,13 @@ typedef struct DarwinProcess_ {
uint64_t utime;
uint64_t stime;
bool taskAccess;
+ bool translated;
} DarwinProcess;
extern const ProcessClass DarwinProcess_class;
+extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
+
Process* DarwinProcess_new(const Settings* settings);
void Process_delete(Object* cast);
@@ -31,7 +34,7 @@ bool Process_isThread(const Process* this);
void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps, bool exists);
-void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList* dpl);
+void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList* dpl, double time_interval);
/*
* Scan threads for process state information.
diff --git a/darwin/DarwinProcessList.c b/darwin/DarwinProcessList.c
index ae1efb1..4333710 100644
--- a/darwin/DarwinProcessList.c
+++ b/darwin/DarwinProcessList.c
@@ -7,7 +7,6 @@ in the source distribution for its full text.
#include "DarwinProcessList.h"
-#include <err.h>
#include <errno.h>
#include <libproc.h>
#include <stdbool.h>
@@ -21,6 +20,7 @@ in the source distribution for its full text.
#include "CRT.h"
#include "DarwinProcess.h"
+#include "Platform.h"
#include "ProcessList.h"
#include "zfs/openzfs_sysctl.h"
#include "zfs/ZfsArcStats.h"
@@ -71,14 +71,14 @@ static void ProcessList_getHostInfo(host_basic_info_data_t* p) {
mach_msg_type_number_t info_size = HOST_BASIC_INFO_COUNT;
if (0 != host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)p, &info_size)) {
- CRT_fatalError("Unable to retrieve host info\n");
+ CRT_fatalError("Unable to retrieve host info");
}
}
static void ProcessList_freeCPULoadInfo(processor_cpu_load_info_t* p) {
if (NULL != p && NULL != *p) {
if (0 != munmap(*p, vm_page_size)) {
- CRT_fatalError("Unable to free old CPU load information\n");
+ CRT_fatalError("Unable to free old CPU load information");
}
*p = NULL;
}
@@ -90,7 +90,7 @@ static unsigned ProcessList_allocateCPULoadInfo(processor_cpu_load_info_t* p) {
// TODO Improving the accuracy of the load counts woule help a lot.
if (0 != host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &cpu_count, (processor_info_array_t*)p, &info_size)) {
- CRT_fatalError("Unable to retrieve CPU info\n");
+ CRT_fatalError("Unable to retrieve CPU info");
}
return cpu_count;
@@ -100,7 +100,7 @@ static void ProcessList_getVMStats(vm_statistics_t p) {
mach_msg_type_number_t info_size = HOST_VM_INFO_COUNT;
if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)p, &info_size) != 0) {
- CRT_fatalError("Unable to retrieve VM statistics\n");
+ CRT_fatalError("Unable to retrieve VM statistics");
}
}
@@ -131,7 +131,7 @@ static struct kinfo_proc* ProcessList_getKInfoProcs(size_t* count) {
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
DarwinProcessList* this = xCalloc(1, sizeof(DarwinProcessList));
- ProcessList_init(&this->super, Class(Process), usersTable, pidMatchList, userId);
+ ProcessList_init(&this->super, Class(DarwinProcess), usersTable, pidMatchList, userId);
/* Initialize the CPU information */
this->super.cpuCount = ProcessList_allocateCPULoadInfo(&this->prev_load);
@@ -158,6 +158,11 @@ void ProcessList_delete(ProcessList* this) {
free(this);
}
+static double ticksToNanoseconds(const double ticks) {
+ const double nanos_per_sec = 1e9;
+ return (ticks / Platform_timebaseToNS) * (nanos_per_sec / (double) Platform_clockTicksPerSec);
+}
+
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
DarwinProcessList* dpl = (DarwinProcessList*)super;
bool preExisting = true;
@@ -185,6 +190,8 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
}
}
+ const double time_interval = ticksToNanoseconds(dpl->global_diff) / (double) dpl->super.cpuCount;
+
/* Clear the thread counts */
super->kernelThreads = 0;
super->userlandThreads = 0;
@@ -204,7 +211,7 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
proc = (DarwinProcess*)ProcessList_getProcess(super, ps[i].kp_proc.p_pid, &preExisting, DarwinProcess_new);
DarwinProcess_setFromKInfoProc(&proc->super, &ps[i], preExisting);
- DarwinProcess_setFromLibprocPidinfo(proc, dpl);
+ DarwinProcess_setFromLibprocPidinfo(proc, dpl, time_interval);
// Disabled for High Sierra due to bug in macOS High Sierra
bool isScanThreadSupported = ! ( CompareKernelVersion(17, 0, 0) >= 0 && CompareKernelVersion(17, 5, 0) < 0);
diff --git a/darwin/Platform.c b/darwin/Platform.c
index e24b67b..a4ed464 100644
--- a/darwin/Platform.c
+++ b/darwin/Platform.c
@@ -6,32 +6,42 @@ Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
+#include "config.h" // IWYU pragma: keep
+
#include "Platform.h"
-#include "Macros.h"
-#include "CPUMeter.h"
-#include "MemoryMeter.h"
-#include "SwapMeter.h"
-#include "TasksMeter.h"
-#include "LoadAverageMeter.h"
+
+#include <errno.h>
+#include <math.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <CoreFoundation/CFString.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/ps/IOPowerSources.h>
+#include <IOKit/ps/IOPSKeys.h>
+
#include "ClockMeter.h"
+#include "CPUMeter.h"
+#include "CRT.h"
+#include "DarwinProcessList.h"
#include "DateMeter.h"
#include "DateTimeMeter.h"
#include "HostnameMeter.h"
+#include "LoadAverageMeter.h"
+#include "Macros.h"
+#include "MemoryMeter.h"
#include "ProcessLocksScreen.h"
+#include "SwapMeter.h"
+#include "TasksMeter.h"
#include "UptimeMeter.h"
#include "zfs/ZfsArcMeter.h"
#include "zfs/ZfsCompressedArcMeter.h"
-#include "DarwinProcessList.h"
-#include <math.h>
-#include <stdlib.h>
+#ifdef HAVE_MACH_MACH_TIME_H
+#include <mach/mach_time.h>
+#endif
-#include <CoreFoundation/CoreFoundation.h>
-#include <CoreFoundation/CFString.h>
-#include <IOKit/ps/IOPowerSources.h>
-#include <IOKit/ps/IOPSKeys.h>
-ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
+const ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
const SignalItem Platform_signals[] = {
{ .name = " 0 Cancel", .number = 0 },
@@ -71,35 +81,6 @@ const SignalItem Platform_signals[] = {
const unsigned int Platform_numberOfSignals = ARRAYSIZE(Platform_signals);
-ProcessFieldData Process_fields[] = {
- [0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
- [PID] = { .name = "PID", .title = " PID ", .description = "Process/thread ID", .flags = 0, },
- [COMM] = { .name = "Command", .title = "Command ", .description = "Command line", .flags = 0, },
- [STATE] = { .name = "STATE", .title = "S ", .description = "Process state (S sleeping, R running, D disk, Z zombie, T traced, W paging)", .flags = 0, },
- [PPID] = { .name = "PPID", .title = " PPID ", .description = "Parent process ID", .flags = 0, },
- [PGRP] = { .name = "PGRP", .title = " PGRP ", .description = "Process group ID", .flags = 0, },
- [SESSION] = { .name = "SESSION", .title = " SID ", .description = "Process's session ID", .flags = 0, },
- [TTY_NR] = { .name = "TTY_NR", .title = " TTY ", .description = "Controlling terminal", .flags = 0, },
- [TPGID] = { .name = "TPGID", .title = " TPGID ", .description = "Process ID of the fg process group of the controlling terminal", .flags = 0, },
- [MINFLT] = { .name = "MINFLT", .title = " MINFLT ", .description = "Number of minor faults which have not required loading a memory page from disk", .flags = 0, },
- [MAJFLT] = { .name = "MAJFLT", .title = " MAJFLT ", .description = "Number of major faults which have required loading a memory page from disk", .flags = 0, },
- [PRIORITY] = { .name = "PRIORITY", .title = "PRI ", .description = "Kernel's internal priority for the process", .flags = 0, },
- [NICE] = { .name = "NICE", .title = " NI ", .description = "Nice value (the higher the value, the more it lets other processes take priority)", .flags = 0, },
- [STARTTIME] = { .name = "STARTTIME", .title = "START ", .description = "Time the process was started", .flags = 0, },
-
- [PROCESSOR] = { .name = "PROCESSOR", .title = "CPU ", .description = "Id of the CPU the process last executed on", .flags = 0, },
- [M_VIRT] = { .name = "M_VIRT", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, },
- [M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, },
- [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
- [PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, },
- [PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, },
- [USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
- [TIME] = { .name = "TIME", .title = " TIME+ ", .description = "Total time the process has spent in user and system time", .flags = 0, },
- [NLWP] = { .name = "NLWP", .title = "NLWP ", .description = "Number of threads in the process", .flags = 0, },
- [TGID] = { .name = "TGID", .title = " TGID ", .description = "Thread group ID (i.e. process ID)", .flags = 0, },
- [100] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
-};
-
const MeterClass* const Platform_meterTypes[] = {
&CPUMeter_class,
&ClockMeter_class,
@@ -131,10 +112,28 @@ const MeterClass* const Platform_meterTypes[] = {
NULL
};
-int Platform_numberOfFields = 100;
+double Platform_timebaseToNS = 1.0;
+
+long Platform_clockTicksPerSec = -1;
void Platform_init(void) {
- /* no platform-specific setup needed */
+ // Check if we can determine the timebase used on this system.
+ // If the API is unavailable assume we get our timebase in nanoseconds.
+#ifdef HAVE_MACH_TIMEBASE_INFO
+ mach_timebase_info_data_t info;
+ mach_timebase_info(&info);
+ Platform_timebaseToNS = (double)info.numer / (double)info.denom;
+#else
+ Platform_timebaseToNS = 1.0;
+#endif
+
+ // Determine the number of clock ticks per second
+ errno = 0;
+ Platform_clockTicksPerSec = sysconf(_SC_CLK_TCK);
+
+ if (errno || Platform_clockTicksPerSec < 1) {
+ CRT_fatalError("Unable to retrieve clock tick rate");
+ }
}
void Platform_done(void) {
@@ -179,16 +178,6 @@ int Platform_getMaxPid() {
return 99999;
}
-ProcessPidColumn Process_pidColumns[] = {
- { .id = PID, .label = "PID" },
- { .id = PPID, .label = "PPID" },
- { .id = TPGID, .label = "TPGID" },
- { .id = TGID, .label = "TGID" },
- { .id = PGRP, .label = "PGRP" },
- { .id = SESSION, .label = "SID" },
- { .id = 0, .label = NULL },
-};
-
static double Platform_setCPUAverageValues(Meter* mtr) {
const ProcessList* dpl = mtr->pl;
int cpus = dpl->cpuCount;
diff --git a/darwin/Platform.h b/darwin/Platform.h
index e1f8355..623063b 100644
--- a/darwin/Platform.h
+++ b/darwin/Platform.h
@@ -19,11 +19,12 @@ in the source distribution for its full text.
#include "ProcessLocksScreen.h"
#include "SignalsPanel.h"
-extern ProcessFieldData Process_fields[];
-extern ProcessField Platform_defaultFields[];
+extern const ProcessField Platform_defaultFields[];
-extern int Platform_numberOfFields;
+extern double Platform_timebaseToNS;
+
+extern long Platform_clockTicksPerSec;
extern const SignalItem Platform_signals[];
@@ -43,8 +44,6 @@ void Platform_getLoadAverage(double* one, double* five, double* fifteen);
int Platform_getMaxPid(void);
-extern ProcessPidColumn Process_pidColumns[];
-
double Platform_setCPUValues(Meter* mtr, int cpu);
void Platform_setMemoryValues(Meter* mtr);
diff --git a/darwin/ProcessField.h b/darwin/ProcessField.h
new file mode 100644
index 0000000..5a8090f
--- /dev/null
+++ b/darwin/ProcessField.h
@@ -0,0 +1,16 @@
+#ifndef HEADER_DarwinProcessField
+#define HEADER_DarwinProcessField
+/*
+htop - darwin/ProcessField.h
+(C) 2020 htop dev team
+Released under the GNU GPLv2, see the COPYING file
+in the source distribution for its full text.
+*/
+
+
+#define PLATFORM_PROCESS_FIELDS \
+ TRANSLATED = 100, \
+ // End of list
+
+
+#endif /* HEADER_DarwinProcessField */
diff --git a/dragonflybsd/DragonFlyBSDProcess.c b/dragonflybsd/DragonFlyBSDProcess.c
index 9311f03..15b1a69 100644
--- a/dragonflybsd/DragonFlyBSDProcess.c
+++ b/dragonflybsd/DragonFlyBSDProcess.c
@@ -18,26 +18,16 @@ in the source distribution for its full text.
#include <sys/syscall.h>
-const ProcessClass DragonFlyBSDProcess_class = {
- .super = {
- .extends = Class(Process),
- .display = Process_display,
- .delete = Process_delete,
- .compare = DragonFlyBSDProcess_compare
- },
- .writeField = DragonFlyBSDProcess_writeField,
-};
-
-ProcessFieldData Process_fields[] = {
+const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
[0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
- [PID] = { .name = "PID", .title = " PID ", .description = "Process/thread ID", .flags = 0, },
+ [PID] = { .name = "PID", .title = "PID", .description = "Process/thread ID", .flags = 0, .pidColumn = true, },
[COMM] = { .name = "Command", .title = "Command ", .description = "Command line", .flags = 0, },
[STATE] = { .name = "STATE", .title = "S ", .description = "Process state (S sleeping (<20s), I Idle, Q Queued for Run, R running, D disk, Z zombie, T traced, W paging, B Blocked, A AskedPage, C Core, J Jailed)", .flags = 0, },
- [PPID] = { .name = "PPID", .title = " PPID ", .description = "Parent process ID", .flags = 0, },
- [PGRP] = { .name = "PGRP", .title = " PGRP ", .description = "Process group ID", .flags = 0, },
- [SESSION] = { .name = "SESSION", .title = " SID ", .description = "Process's session ID", .flags = 0, },
+ [PPID] = { .name = "PPID", .title = "PPID", .description = "Parent process ID", .flags = 0, .pidColumn = true, },
+ [PGRP] = { .name = "PGRP", .title = "PGRP", .description = "Process group ID", .flags = 0, .pidColumn = true, },
+ [SESSION] = { .name = "SESSION", .title = "SID", .description = "Process's session ID", .flags = 0, .pidColumn = true, },
[TTY_NR] = { .name = "TTY_NR", .title = " TTY ", .description = "Controlling terminal", .flags = 0, },
- [TPGID] = { .name = "TPGID", .title = " TPGID ", .description = "Process ID of the fg process group of the controlling terminal", .flags = 0, },
+ [TPGID] = { .name = "TPGID", .title = "TPGID", .description = "Process ID of the fg process group of the controlling terminal", .flags = 0, .pidColumn = true, },
[MINFLT] = { .name = "MINFLT", .title = " MINFLT ", .description = "Number of minor faults which have not required loading a memory page from disk", .flags = 0, },
[MAJFLT] = { .name = "MAJFLT", .title = " MAJFLT ", .description = "Number of major faults which have required loading a memory page from disk", .flags = 0, },
[PRIORITY] = { .name = "PRIORITY", .title = "PRI ", .description = "Kernel's internal priority for the process", .flags = 0, },
@@ -53,21 +43,9 @@ ProcessFieldData Process_fields[] = {
[USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
[TIME] = { .name = "TIME", .title = " TIME+ ", .description = "Total time the process has spent in user and system time", .flags = 0, },
[NLWP] = { .name = "NLWP", .title = "NLWP ", .description = "Number of threads in the process", .flags = 0, },
- [TGID] = { .name = "TGID", .title = " TGID ", .description = "Thread group ID (i.e. process ID)", .flags = 0, },
- [JID] = { .name = "JID", .title = " JID ", .description = "Jail prison ID", .flags = 0, },
+ [TGID] = { .name = "TGID", .title = "TGID", .description = "Thread group ID (i.e. process ID)", .flags = 0, .pidColumn = true, },
+ [JID] = { .name = "JID", .title = "JID", .description = "Jail prison ID", .flags = 0, .pidColumn = true, },
[JAIL] = { .name = "JAIL", .title = "JAIL ", .description = "Jail prison name", .flags = 0, },
- [LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
-};
-
-ProcessPidColumn Process_pidColumns[] = {
- { .id = JID, .label = "JID" },
- { .id = PID, .label = "PID" },
- { .id = PPID, .label = "PPID" },
- { .id = TPGID, .label = "TPGID" },
- { .id = TGID, .label = "TGID" },
- { .id = PGRP, .label = "PGRP" },
- { .id = SESSION, .label = "SID" },
- { .id = 0, .label = NULL },
};
Process* DragonFlyBSDProcess_new(const Settings* settings) {
@@ -84,50 +62,35 @@ void Process_delete(Object* cast) {
free(this);
}
-void DragonFlyBSDProcess_writeField(const Process* this, RichString* str, ProcessField field) {
+static void DragonFlyBSDProcess_writeField(const Process* this, RichString* str, ProcessField field) {
const DragonFlyBSDProcess* fp = (const DragonFlyBSDProcess*) this;
char buffer[256]; buffer[255] = '\0';
int attr = CRT_colors[DEFAULT_COLOR];
- int n = sizeof(buffer) - 1;
- switch ((int) field) {
+ size_t n = sizeof(buffer) - 1;
+ switch (field) {
// add Platform-specific fields here
- case PID: xSnprintf(buffer, n, Process_pidFormat, (fp->kernel ? -1 : this->pid)); break;
- case JID: xSnprintf(buffer, n, Process_pidFormat, fp->jid); break;
- case JAIL: {
- xSnprintf(buffer, n, "%-11s ", fp->jname);
- if (buffer[11] != '\0') {
- buffer[11] = ' ';
- buffer[12] = '\0';
- }
- break;
- }
+ case PID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, (fp->kernel ? -1 : this->pid)); break;
+ case JID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, fp->jid); break;
+ case JAIL: Process_printLeftAlignedField(str, attr, fp->jname, 11); return;
default:
Process_writeField(this, str, field);
return;
}
- RichString_append(str, attr, buffer);
+ RichString_appendWide(str, attr, buffer);
}
-long DragonFlyBSDProcess_compare(const void* v1, const void* v2) {
- const DragonFlyBSDProcess *p1, *p2;
- const Settings *settings = ((const Process*)v1)->settings;
+static int DragonFlyBSDProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
+ const DragonFlyBSDProcess* p1 = (const DragonFlyBSDProcess*)v1;
+ const DragonFlyBSDProcess* p2 = (const DragonFlyBSDProcess*)v2;
- if (settings->direction == 1) {
- p1 = (const DragonFlyBSDProcess*)v1;
- p2 = (const DragonFlyBSDProcess*)v2;
- } else {
- p2 = (const DragonFlyBSDProcess*)v1;
- p1 = (const DragonFlyBSDProcess*)v2;
- }
-
- switch ((int) settings->sortKey) {
+ switch (key) {
// add Platform-specific fields here
case JID:
return SPACESHIP_NUMBER(p1->jid, p2->jid);
case JAIL:
return SPACESHIP_NULLSTR(p1->jname, p2->jname);
default:
- return Process_compare(v1, v2);
+ return Process_compareByKey_Base(v1, v2, key);
}
}
@@ -140,3 +103,14 @@ bool Process_isThread(const Process* this) {
return (Process_isUserlandThread(this));
}
}
+
+const ProcessClass DragonFlyBSDProcess_class = {
+ .super = {
+ .extends = Class(Process),
+ .display = Process_display,
+ .delete = Process_delete,
+ .compare = Process_compare
+ },
+ .writeField = DragonFlyBSDProcess_writeField,
+ .compareByKey = DragonFlyBSDProcess_compareByKey
+};
diff --git a/dragonflybsd/DragonFlyBSDProcess.h b/dragonflybsd/DragonFlyBSDProcess.h
index 1befd94..dc40a99 100644
--- a/dragonflybsd/DragonFlyBSDProcess.h
+++ b/dragonflybsd/DragonFlyBSDProcess.h
@@ -8,13 +8,6 @@ Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
-typedef enum DragonFlyBSDProcessFields {
- // Add platform-specific fields here, with ids >= 100
- JID = 100,
- JAIL = 101,
- LAST_PROCESSFIELD = 102,
-} DragonFlyBSDProcessField;
-
typedef struct DragonFlyBSDProcess_ {
Process super;
int kernel;
@@ -29,18 +22,12 @@ typedef struct DragonFlyBSDProcess_ {
extern const ProcessClass DragonFlyBSDProcess_class;
-extern ProcessFieldData Process_fields[];
-
-extern ProcessPidColumn Process_pidColumns[];
+extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
Process* DragonFlyBSDProcess_new(const Settings* settings);
void Process_delete(Object* cast);
-void DragonFlyBSDProcess_writeField(const Process* this, RichString* str, ProcessField field);
-
-long DragonFlyBSDProcess_compare(const void* v1, const void* v2);
-
bool Process_isThread(const Process* this);
#endif
diff --git a/dragonflybsd/DragonFlyBSDProcessList.c b/dragonflybsd/DragonFlyBSDProcessList.c
index 940ec03..edf2c86 100644
--- a/dragonflybsd/DragonFlyBSDProcessList.c
+++ b/dragonflybsd/DragonFlyBSDProcessList.c
@@ -15,7 +15,6 @@ in the source distribution for its full text.
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/user.h>
-#include <err.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>
@@ -55,12 +54,9 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
len = 2; sysctlnametomib("hw.physmem", MIB_hw_physmem, &len);
len = sizeof(pageSize);
- if (sysctlbyname("vm.stats.vm.v_page_size", &pageSize, &len, NULL, 0) == -1) {
- pageSize = CRT_pageSize;
- pageSizeKb = CRT_pageSizeKB;
- } else {
- pageSizeKb = pageSize / ONE_K;
- }
+ if (sysctlbyname("vm.stats.vm.v_page_size", &pageSize, &len, NULL, 0) == -1)
+ CRT_fatalError("Cannot get pagesize by sysctl");
+ pageSizeKb = pageSize / ONE_K;
// usable page count vm.stats.vm.v_page_count
// actually usable memory : vm.stats.vm.v_page_count * vm.stats.vm.v_page_size
@@ -115,7 +111,7 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
dfpl->kd = kvm_openfiles(NULL, "/dev/null", NULL, 0, errbuf);
if (dfpl->kd == NULL) {
- errx(1, "kvm_open: %s", errbuf);
+ CRT_fatalError("kvm_openfiles() failed");
}
return pl;
@@ -265,7 +261,7 @@ static inline void DragonFlyBSDProcessList_scanMemoryInfo(ProcessList* pl) {
pl->usedSwap *= pageSizeKb;
}
-char* DragonFlyBSDProcessList_readProcessName(kvm_t* kd, struct kinfo_proc* kproc, int* basenameEnd) {
+static char* DragonFlyBSDProcessList_readProcessName(kvm_t* kd, const struct kinfo_proc* kproc, int* basenameEnd) {
char** argv = kvm_getargv(kd, kproc, 0);
if (!argv) {
return xStrdup(kproc->kp_comm);
@@ -297,25 +293,20 @@ static inline void DragonFlyBSDProcessList_scanJails(DragonFlyBSDProcessList* df
char* nextpos;
if (sysctlbyname("jail.list", NULL, &len, NULL, 0) == -1) {
- fprintf(stderr, "initial sysctlbyname / jail.list failed\n");
- exit(3);
+ CRT_fatalError("initial sysctlbyname / jail.list failed");
}
retry:
if (len == 0)
return;
jls = xMalloc(len);
- if (jls == NULL) {
- fprintf(stderr, "xMalloc failed\n");
- exit(4);
- }
+
if (sysctlbyname("jail.list", jls, &len, NULL, 0) == -1) {
if (errno == ENOMEM) {
free(jls);
goto retry;
}
- fprintf(stderr, "sysctlbyname / jail.list failed\n");
- exit(5);
+ CRT_fatalError("sysctlbyname / jail.list failed");
}
if (dfpl->jails) {
@@ -346,7 +337,7 @@ retry:
free(jls);
}
-char* DragonFlyBSDProcessList_readJailName(DragonFlyBSDProcessList* dfpl, int jailid) {
+static char* DragonFlyBSDProcessList_readJailName(DragonFlyBSDProcessList* dfpl, int jailid) {
char* hostname;
char* jname;
@@ -376,10 +367,10 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
int count = 0;
// TODO Kernel Threads seem to be skipped, need to figure out the correct flag
- struct kinfo_proc* kprocs = kvm_getprocs(dfpl->kd, KERN_PROC_ALL | (!hideUserlandThreads ? KERN_PROC_FLAG_LWP : 0), 0, &count);
+ const struct kinfo_proc* kprocs = kvm_getprocs(dfpl->kd, KERN_PROC_ALL | (!hideUserlandThreads ? KERN_PROC_FLAG_LWP : 0), 0, &count);
for (int i = 0; i < count; i++) {
- struct kinfo_proc* kproc = &kprocs[i];
+ const struct kinfo_proc* kproc = &kprocs[i];
bool preExisting = false;
bool ATTR_UNUSED isIdleProcess = false;
@@ -433,13 +424,13 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
}
}
- proc->m_virt = kproc->kp_vm_map_size / pageSize;
- proc->m_resident = kproc->kp_vm_rssize;
+ proc->m_virt = kproc->kp_vm_map_size / ONE_K;
+ proc->m_resident = kproc->kp_vm_rssize * pageSizeKb;
proc->nlwp = kproc->kp_nthreads; // number of lwp thread
proc->time = (kproc->kp_swtime + 5000) / 10000;
proc->percent_cpu = 100.0 * ((double)kproc->kp_lwp.kl_pctcpu / (double)kernelFScale);
- proc->percent_mem = 100.0 * (proc->m_resident * pageSizeKb) / (double)(super->totalMem);
+ proc->percent_mem = 100.0 * proc->m_resident / (double)(super->totalMem);
if (proc->percent_cpu > 0.1) {
// system idle process should own all CPU time left regardless of CPU count
diff --git a/dragonflybsd/DragonFlyBSDProcessList.h b/dragonflybsd/DragonFlyBSDProcessList.h
index 682971e..80fb9f3 100644
--- a/dragonflybsd/DragonFlyBSDProcessList.h
+++ b/dragonflybsd/DragonFlyBSDProcessList.h
@@ -11,16 +11,12 @@ in the source distribution for its full text.
#include <kvm.h>
#include <sys/param.h>
#include <osreldate.h>
-#include <sys/kinfo.h>
-#include <kinfo.h>
#include <sys/jail.h>
#include <sys/uio.h>
#include <sys/resource.h>
#include "Hashtable.h"
#include "DragonFlyBSDProcess.h"
-#define JAIL_ERRMSGLEN 1024
-extern char jail_errmsg[JAIL_ERRMSGLEN];
typedef struct CPUData_ {
double userPercent;
@@ -55,10 +51,6 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
void ProcessList_delete(ProcessList* this);
-char* DragonFlyBSDProcessList_readProcessName(kvm_t* kd, struct kinfo_proc* kproc, int* basenameEnd);
-
-char* DragonFlyBSDProcessList_readJailName(DragonFlyBSDProcessList* dfpl, int jailid);
-
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
#endif
diff --git a/dragonflybsd/Platform.c b/dragonflybsd/Platform.c
index 40a7348..8ce216c 100644
--- a/dragonflybsd/Platform.c
+++ b/dragonflybsd/Platform.c
@@ -31,9 +31,7 @@ in the source distribution for its full text.
#include <math.h>
-ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
-
-int Platform_numberOfFields = LAST_PROCESSFIELD;
+const ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
const SignalItem Platform_signals[] = {
{ .name = " 0 Cancel", .number = 0 },
diff --git a/dragonflybsd/Platform.h b/dragonflybsd/Platform.h
index 5456539..3c5d9cb 100644
--- a/dragonflybsd/Platform.h
+++ b/dragonflybsd/Platform.h
@@ -17,11 +17,8 @@ in the source distribution for its full text.
#include "ProcessLocksScreen.h"
#include "SignalsPanel.h"
-extern ProcessFieldData Process_fields[];
-extern ProcessField Platform_defaultFields[];
-
-extern int Platform_numberOfFields;
+extern const ProcessField Platform_defaultFields[];
extern const SignalItem Platform_signals[];
diff --git a/dragonflybsd/ProcessField.h b/dragonflybsd/ProcessField.h
new file mode 100644
index 0000000..a32e3d3
--- /dev/null
+++ b/dragonflybsd/ProcessField.h
@@ -0,0 +1,17 @@
+#ifndef HEADER_DragonFlyBSDProcessField
+#define HEADER_DragonFlyBSDProcessField
+/*
+htop - dragonflybsd/ProcessField.h
+(C) 2020 htop dev team
+Released under the GNU GPLv2, see the COPYING file
+in the source distribution for its full text.
+*/
+
+
+#define PLATFORM_PROCESS_FIELDS \
+ JID = 100, \
+ JAIL = 101, \
+ // End of list
+
+
+#endif /* HEADER_DragonFlyBSDProcessField */
diff --git a/freebsd/FreeBSDProcess.c b/freebsd/FreeBSDProcess.c
index d6d67b7..28d482e 100644
--- a/freebsd/FreeBSDProcess.c
+++ b/freebsd/FreeBSDProcess.c
@@ -18,16 +18,16 @@ in the source distribution for its full text.
const char* const nodevStr = "nodev";
-ProcessFieldData Process_fields[] = {
+const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
[0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
- [PID] = { .name = "PID", .title = " PID ", .description = "Process/thread ID", .flags = 0, },
+ [PID] = { .name = "PID", .title = "PID", .description = "Process/thread ID", .flags = 0, .pidColumn = true, },
[COMM] = { .name = "Command", .title = "Command ", .description = "Command line", .flags = 0, },
[STATE] = { .name = "STATE", .title = "S ", .description = "Process state (S sleeping, R running, D disk, Z zombie, T traced, W paging)", .flags = 0, },
- [PPID] = { .name = "PPID", .title = " PPID ", .description = "Parent process ID", .flags = 0, },
- [PGRP] = { .name = "PGRP", .title = " PGRP ", .description = "Process group ID", .flags = 0, },
- [SESSION] = { .name = "SESSION", .title = " SID ", .description = "Process's session ID", .flags = 0, },
+ [PPID] = { .name = "PPID", .title = "PPID", .description = "Parent process ID", .flags = 0, .pidColumn = true, },
+ [PGRP] = { .name = "PGRP", .title = "PGRP", .description = "Process group ID", .flags = 0, .pidColumn = true, },
+ [SESSION] = { .name = "SESSION", .title = "SID", .description = "Process's session ID", .flags = 0, .pidColumn = true, },
[TTY_NR] = { .name = "TTY_NR", .title = " TTY ", .description = "Controlling terminal", .flags = PROCESS_FLAG_FREEBSD_TTY, },
- [TPGID] = { .name = "TPGID", .title = " TPGID ", .description = "Process ID of the fg process group of the controlling terminal", .flags = 0, },
+ [TPGID] = { .name = "TPGID", .title = "TPGID", .description = "Process ID of the fg process group of the controlling terminal", .flags = 0, .pidColumn = true, },
[MINFLT] = { .name = "MINFLT", .title = " MINFLT ", .description = "Number of minor faults which have not required loading a memory page from disk", .flags = 0, },
[MAJFLT] = { .name = "MAJFLT", .title = " MAJFLT ", .description = "Number of major faults which have required loading a memory page from disk", .flags = 0, },
[PRIORITY] = { .name = "PRIORITY", .title = "PRI ", .description = "Kernel's internal priority for the process", .flags = 0, },
@@ -44,21 +44,9 @@ ProcessFieldData Process_fields[] = {
[USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
[TIME] = { .name = "TIME", .title = " TIME+ ", .description = "Total time the process has spent in user and system time", .flags = 0, },
[NLWP] = { .name = "NLWP", .title = "NLWP ", .description = "Number of threads in the process", .flags = 0, },
- [TGID] = { .name = "TGID", .title = " TGID ", .description = "Thread group ID (i.e. process ID)", .flags = 0, },
- [JID] = { .name = "JID", .title = " JID ", .description = "Jail prison ID", .flags = 0, },
+ [TGID] = { .name = "TGID", .title = "TGID", .description = "Thread group ID (i.e. process ID)", .flags = 0, .pidColumn = true, },
+ [JID] = { .name = "JID", .title = "JID", .description = "Jail prison ID", .flags = 0, .pidColumn = true, },
[JAIL] = { .name = "JAIL", .title = "JAIL ", .description = "Jail prison name", .flags = 0, },
- [LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
-};
-
-ProcessPidColumn Process_pidColumns[] = {
- { .id = JID, .label = "JID" },
- { .id = PID, .label = "PID" },
- { .id = PPID, .label = "PPID" },
- { .id = TPGID, .label = "TPGID" },
- { .id = TGID, .label = "TGID" },
- { .id = PGRP, .label = "PGRP" },
- { .id = SESSION, .label = "SID" },
- { .id = 0, .label = NULL },
};
Process* FreeBSDProcess_new(const Settings* settings) {
@@ -80,17 +68,12 @@ static void FreeBSDProcess_writeField(const Process* this, RichString* str, Proc
char buffer[256]; buffer[255] = '\0';
int attr = CRT_colors[DEFAULT_COLOR];
int n = sizeof(buffer) - 1;
- switch ((int) field) {
+ switch (field) {
// add FreeBSD-specific fields here
- case JID: xSnprintf(buffer, n, Process_pidFormat, fp->jid); break;
- case JAIL: {
- xSnprintf(buffer, n, "%-11s ", fp->jname);
- if (buffer[11] != '\0') {
- buffer[11] = ' ';
- buffer[12] = '\0';
- }
- break;
- }
+ case JID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, fp->jid); break;
+ case JAIL:
+ Process_printLeftAlignedField(str, attr, fp->jname ? fp->jname : "N/A", 11);
+ return;
case TTY_NR:
if (fp->ttyPath) {
if (fp->ttyPath == nodevStr)
@@ -105,22 +88,14 @@ static void FreeBSDProcess_writeField(const Process* this, RichString* str, Proc
Process_writeField(this, str, field);
return;
}
- RichString_append(str, attr, buffer);
+ RichString_appendWide(str, attr, buffer);
}
-static long FreeBSDProcess_compare(const void* v1, const void* v2) {
- const FreeBSDProcess *p1, *p2;
- const Settings *settings = ((const Process*)v1)->settings;
-
- if (settings->direction == 1) {
- p1 = (const FreeBSDProcess*)v1;
- p2 = (const FreeBSDProcess*)v2;
- } else {
- p2 = (const FreeBSDProcess*)v1;
- p1 = (const FreeBSDProcess*)v2;
- }
+static int FreeBSDProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
+ const FreeBSDProcess* p1 = (const FreeBSDProcess*)v1;
+ const FreeBSDProcess* p2 = (const FreeBSDProcess*)v2;
- switch ((int) settings->sortKey) {
+ switch (key) {
// add FreeBSD-specific fields here
case JID:
return SPACESHIP_NUMBER(p1->jid, p2->jid);
@@ -129,7 +104,7 @@ static long FreeBSDProcess_compare(const void* v1, const void* v2) {
case TTY_NR:
return SPACESHIP_NULLSTR(p1->ttyPath, p2->ttyPath);
default:
- return Process_compare(v1, v2);
+ return Process_compareByKey_Base(v1, v2, key);
}
}
@@ -148,7 +123,8 @@ const ProcessClass FreeBSDProcess_class = {
.extends = Class(Process),
.display = Process_display,
.delete = Process_delete,
- .compare = FreeBSDProcess_compare
+ .compare = Process_compare
},
.writeField = FreeBSDProcess_writeField,
+ .compareByKey = FreeBSDProcess_compareByKey
};
diff --git a/freebsd/FreeBSDProcess.h b/freebsd/FreeBSDProcess.h
index 8911976..6bf2c93 100644
--- a/freebsd/FreeBSDProcess.h
+++ b/freebsd/FreeBSDProcess.h
@@ -18,13 +18,6 @@ in the source distribution for its full text.
extern const char* const nodevStr;
-typedef enum FreeBSDProcessFields_ {
- // Add platform-specific fields here, with ids >= 100
- JID = 100,
- JAIL = 101,
- LAST_PROCESSFIELD = 102,
-} FreeBSDProcessField;
-
typedef struct FreeBSDProcess_ {
Process super;
int kernel;
@@ -43,9 +36,7 @@ static inline bool Process_isUserlandThread(const Process* this) {
extern const ProcessClass FreeBSDProcess_class;
-extern ProcessFieldData Process_fields[];
-
-extern ProcessPidColumn Process_pidColumns[];
+extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
Process* FreeBSDProcess_new(const Settings* settings);
diff --git a/freebsd/FreeBSDProcessList.c b/freebsd/FreeBSDProcessList.c
index 9aaab5d..679f640 100644
--- a/freebsd/FreeBSDProcessList.c
+++ b/freebsd/FreeBSDProcessList.c
@@ -9,12 +9,10 @@ in the source distribution for its full text.
#include <assert.h>
#include <dirent.h>
-#include <err.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/_iovec.h>
-#include <sys/dirent.h>
#include <sys/errno.h>
#include <sys/param.h> // needs to be included before <sys/jail.h> for MAXPATHLEN
#include <sys/jail.h>
@@ -72,12 +70,9 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
len = 2; sysctlnametomib("hw.physmem", MIB_hw_physmem, &len);
len = sizeof(pageSize);
- if (sysctlbyname("vm.stats.vm.v_page_size", &pageSize, &len, NULL, 0) == -1) {
- pageSize = CRT_pageSize;
- pageSizeKb = CRT_pageSize;
- } else {
- pageSizeKb = pageSize / ONE_K;
- }
+ if (sysctlbyname("vm.stats.vm.v_page_size", &pageSize, &len, NULL, 0) == -1)
+ CRT_fatalError("Cannot get pagesize by sysctl");
+ pageSizeKb = pageSize / ONE_K;
// usable page count vm.stats.vm.v_page_count
// actually usable memory : vm.stats.vm.v_page_count * vm.stats.vm.v_page_size
@@ -149,7 +144,7 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
fpl->kd = kvm_openfiles(NULL, "/dev/null", NULL, 0, errbuf);
if (fpl->kd == NULL) {
- errx(1, "kvm_open: %s", errbuf);
+ CRT_fatalError("kvm_openfiles() failed");
}
fpl->ttys = Hashtable_new(20, true);
@@ -419,7 +414,7 @@ static char* FreeBSDProcessList_readJailName(const struct kinfo_proc* kproc) {
char* jname = NULL;
char jnamebuf[MAXHOSTNAMELEN];
- if (kproc->ki_jid != 0 ) {
+ if (kproc->ki_jid != 0) {
struct iovec jiov[6];
memset(jnamebuf, 0, sizeof(jnamebuf));
@@ -526,13 +521,13 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
}
// from FreeBSD source /src/usr.bin/top/machine.c
- proc->m_virt = kproc->ki_size / pageSize;
- proc->m_resident = kproc->ki_rssize;
+ proc->m_virt = kproc->ki_size / ONE_K;
+ proc->m_resident = kproc->ki_rssize * pageSizeKb;
proc->nlwp = kproc->ki_numthreads;
proc->time = (kproc->ki_runtime + 5000) / 10000;
proc->percent_cpu = 100.0 * ((double)kproc->ki_pctcpu / (double)kernelFScale);
- proc->percent_mem = 100.0 * (proc->m_resident * pageSizeKb) / (double)(super->totalMem);
+ proc->percent_mem = 100.0 * proc->m_resident / (double)(super->totalMem);
/*
* TODO
diff --git a/freebsd/Platform.c b/freebsd/Platform.c
index bc77cf4..c74ab6d 100644
--- a/freebsd/Platform.c
+++ b/freebsd/Platform.c
@@ -47,9 +47,7 @@ in the source distribution for its full text.
#include "zfs/ZfsCompressedArcMeter.h"
-ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
-
-int Platform_numberOfFields = LAST_PROCESSFIELD;
+const ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
const SignalItem Platform_signals[] = {
{ .name = " 0 Cancel", .number = 0 },
diff --git a/freebsd/Platform.h b/freebsd/Platform.h
index 5b3b019..36895b8 100644
--- a/freebsd/Platform.h
+++ b/freebsd/Platform.h
@@ -19,11 +19,7 @@ in the source distribution for its full text.
#include "SignalsPanel.h"
-extern ProcessFieldData Process_fields[];
-
-extern ProcessField Platform_defaultFields[];
-
-extern int Platform_numberOfFields;
+extern const ProcessField Platform_defaultFields[];
extern const SignalItem Platform_signals[];
diff --git a/freebsd/ProcessField.h b/freebsd/ProcessField.h
new file mode 100644
index 0000000..cc89282
--- /dev/null
+++ b/freebsd/ProcessField.h
@@ -0,0 +1,17 @@
+#ifndef HEADER_FreeBSDProcessField
+#define HEADER_FreeBSDProcessField
+/*
+htop - freebsd/ProcessField.h
+(C) 2020 htop dev team
+Released under the GNU GPLv2, see the COPYING file
+in the source distribution for its full text.
+*/
+
+
+#define PLATFORM_PROCESS_FIELDS \
+ JID = 100, \
+ JAIL = 101, \
+ // End of list
+
+
+#endif /* HEADER_FreeBSDProcessField */
diff --git a/htop.1.in b/htop.1.in
index 0205a99..cd98478 100644
--- a/htop.1.in
+++ b/htop.1.in
@@ -2,11 +2,9 @@
.SH "NAME"
htop \- interactive process viewer
.SH "SYNOPSIS"
-.LP
.B htop
.RB [ \-dCFhpustvH ]
.SH "DESCRIPTION"
-.LP
.B htop
is a cross-platform ncurses-based process viewer.
.LP
@@ -22,9 +20,7 @@ Tasks related to processes (killing, renicing) can be done without
entering their PIDs.
.br
.SH "COMMAND-LINE OPTIONS"
-.LP
Mandatory arguments to long options are mandatory for short options too.
-.LP
.TP
\fB\-d \-\-delay=DELAY\fR
Delay between updates, in tenths of seconds. If the delay value is
@@ -46,7 +42,8 @@ Display a help message and exit
Show only the given PIDs
.TP
\fB\-s \-\-sort\-key COLUMN\fR
-Sort by this column (use \-\-sort\-key help for a column list)
+Sort by this column (use \-\-sort\-key help for a column list).
+This will force a list view unless you specify -t at the same time.
.TP
\fB\-u \-\-user=USERNAME\fR
Show only the processes of a given user
@@ -61,15 +58,14 @@ Disable support of mouse control
Output version information and exit
.TP
\fB\-t \-\-tree
-Show processes in tree view
+Show processes in tree view. This can be used to force a tree view when
+requesting a sort order with -s.
.TP
\fB\-H \-\-highlight-changes=DELAY\fR
Highlight new and old processes
.SH "INTERACTIVE COMMANDS"
-.LP
The following commands are supported while in
.BR htop :
-.LP
.TP 5
.B Up, Alt-k
Select (highlight) the previous process in the process list. Scroll the list
@@ -141,6 +137,7 @@ select which columns are displayed, in which order.
Incrementally search the command lines of all the displayed processes. The
currently selected (highlighted) command will update as you type. While in
search mode, pressing F3 will cycle through matching occurrences.
+Pressing Shift-F3 will cycle backwards.
Alternatively the search can be started by simply typing the command
you are looking for, although for the first character normal key
@@ -157,11 +154,9 @@ between them as a tree. Toggling the key will switch between tree and
your previously selected sort view. Selecting a sort view will exit
tree view.
.TP
-.B F6
-On sorted view, select a field for sorting, also accessible through < and >.
+.B F6, <, >
+Selects a field for sorting, also accessible through < and >.
The current sort field is indicated by a highlight in the header.
-On tree view, expand or collapse the current subtree. A "+" indicator in the
-tree node indicates that it is collapsed.
.TP
.B F7, ]
Increase the selected process's priority (subtract from 'nice' value).
@@ -192,6 +187,9 @@ Set CPU affinity: mark which CPUs a process is allowed to use.
.B u
Show only processes owned by a specified user.
.TP
+.B N
+Sort by PID.
+.TP
.B M
Sort by memory usage (top compatibility key).
.TP
@@ -232,7 +230,6 @@ Refresh: redraw screen and recalculate values.
PID search: type in process ID and the selection highlight will be moved to it.
.PD
.SH "COLUMNS"
-.LP
The following columns can display data about each process. A value of '\-' in
all the rows indicates that a column is unsupported on your system, or
currently unimplemented in
@@ -242,7 +239,6 @@ The names below are the ones used in the
shown in
.BR htop 's
main screen, it is shown below in parenthesis.
-.LP
.TP 5
.B Command
The full command line of the process (i.e. program name and arguments). If the
@@ -460,8 +456,48 @@ The executable file of the process as reported by the kernel. Requires CAP_SYS_P
.TP
.B All other flags
Currently unsupported (always displays '-').
+.SH "EXTERNAL LIBRARIES"
+While
+.B htop
+depends on most of the libraries it uses at build time there are two
+noteworthy exceptions to this rule. These exceptions both relate to
+data displayed in meters displayed in the header of
+.B htop
+and were intentionally created as optional runtime dependencies instead.
+These exceptions are described below:
+.TP
+.B libsystemd
+The bindings for libsystemd are used in the SystemD meter to determine
+the number of active services and the overall system state. Looking for
+the functions to determine these information at runtime allows for
+builds to support these meters without forcing the package manager
+to install these libraries on systems that otherwise don't use systemd.
+
+Summary: no build time dependency, optional runtime dependency on
+.B libsystemd
+via dynamic loading, with
+.B systemctl(1)
+fallback.
+.TP
+.B libsensors
+The bindings for libsensors are used for the CPU temperature readings
+in the CPU usage meters if displaying the temperature is enabled through
+the setup screen. In order for
+.B htop
+to show these temperatures correctly though, a proper configuration
+of libsensors through its usual configuration files is assumed and that
+all CPU cores correspond to temperature sensors from the
+.B coretemp
+driver with core 0 corresponding to a sensor labelled "Core 0". The
+package temperature may be given as "Package id 0". If missing it is
+inferred as the maximum value from the available per-core readings.
+
+Summary: build time dependency on
+.B libsensors(3)
+C header files, optional runtime dependency on
+.B libsensors(3)
+via dynamic loading.
.SH "CONFIG FILE"
-.LP
By default
.B htop
reads its configuration from the XDG-compliant path
@@ -479,7 +515,6 @@ You may override the location of the configuration file using the $HTOPRC
environment variable (so you can have multiple configurations for different
machines that share the same home directory, for example).
.SH "MEMORY SIZES"
-.LP
Memory sizes in
.B htop
are displayed in a human-readable form.
@@ -497,7 +532,6 @@ space and make memory size representations consistent throughout
and
.BR limits.conf (5).
.SH "AUTHORS"
-.LP
.B htop
was originally developed by Hisham Muhammad.
Nowadays it is maintained by the community at <htop@groups.io>.
diff --git a/htop.c b/htop.c
index 23da081..00ff1da 100644
--- a/htop.c
+++ b/htop.c
@@ -49,8 +49,8 @@ static void printHelpFlag(void) {
"-H --highlight-changes[=DELAY] Highlight new and old processes\n"
"-M --no-mouse Disable the mouse\n"
"-p --pid=PID[,PID,PID...] Show only the given PIDs\n"
- "-s --sort-key=COLUMN Sort by COLUMN (try --sort-key=help for a list)\n"
- "-t --tree Show the tree view by default\n"
+ "-s --sort-key=COLUMN Sort by COLUMN in list view (try --sort-key=help for a list)\n"
+ "-t --tree Show the tree view (can be combined with -s)\n"
"-u --user[=USERNAME] Show only processes for a given user (or $USER)\n"
"-U --no-unicode Do not use unicode but plain ASCII\n"
"-V --version Print version info\n"
@@ -93,7 +93,7 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
.highlightDelaySecs = -1,
};
- static struct option long_opts[] =
+ const struct option long_opts[] =
{
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
@@ -125,14 +125,14 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
case 's':
assert(optarg); /* please clang analyzer, cause optarg can be NULL in the 'u' case */
if (String_eq(optarg, "help")) {
- for (int j = 1; j < Platform_numberOfFields; j++) {
+ for (int j = 1; j < LAST_PROCESSFIELD; j++) {
const char* name = Process_fields[j].name;
if (name) printf ("%s\n", name);
}
exit(0);
}
flags.sortKey = 0;
- for (int j = 1; j < Platform_numberOfFields; j++) {
+ for (int j = 1; j < LAST_PROCESSFIELD; j++) {
if (Process_fields[j].name == NULL)
continue;
if (String_eq(optarg, Process_fields[j].name)) {
@@ -204,6 +204,7 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
}
case 'F': {
assert(optarg);
+ free(flags.commFilter);
flags.commFilter = xStrdup(optarg);
break;
@@ -298,9 +299,12 @@ int main(int argc, char** argv) {
if (flags.highlightDelaySecs != -1)
settings->highlightDelaySecs = flags.highlightDelaySecs;
if (flags.sortKey > 0) {
- settings->sortKey = flags.sortKey;
- settings->treeView = false;
- settings->direction = 1;
+ // -t -s <key> means "tree sorted by key"
+ // -s <key> means "list sorted by key" (previous existing behavior)
+ if (!flags.treeView) {
+ settings->treeView = false;
+ }
+ Settings_setSortKey(settings, flags.sortKey);
}
CRT_init(&(settings->delay), settings->colorScheme, flags.allowUnicode);
@@ -310,8 +314,6 @@ int main(int argc, char** argv) {
MainPanel_updateTreeFunctions(panel, settings->treeView);
- ProcessList_printHeader(pl, Panel_getHeader((Panel*)panel));
-
State state = {
.settings = settings,
.ut = ut,
diff --git a/iwyu/htop.imp b/iwyu/htop.imp
index 7fe432c..100625c 100644
--- a/iwyu/htop.imp
+++ b/iwyu/htop.imp
@@ -8,6 +8,8 @@
{ include: ["<bits/getopt_core.h>", "private", "<unistd.h>", "public"] },
+ { include: ["<sys/dirent.h>", "private", "<dirent.h>", "public"] },
+
{ include: ["<sys/signal.h>", "private", "<signal.h>", "public"] },
{ include: ["<sys/_stdarg.h>", "private", "<stdarg.h>", "public"] },
diff --git a/linux/IOPriorityPanel.c b/linux/IOPriorityPanel.c
index c5a4a4c..25d2199 100644
--- a/linux/IOPriorityPanel.c
+++ b/linux/IOPriorityPanel.c
@@ -17,7 +17,7 @@ in the source distribution for its full text.
Panel* IOPriorityPanel_new(IOPriority currPrio) {
- Panel* this = Panel_new(1, 1, 1, 1, true, Class(ListItem), FunctionBar_newEnterEsc("Set ", "Cancel "));
+ Panel* this = Panel_new(1, 1, 1, 1, Class(ListItem), true, FunctionBar_newEnterEsc("Set ", "Cancel "));
Panel_setHeader(this, "IO Priority:");
Panel_add(this, (Object*) ListItem_new("None (based on nice)", IOPriority_None));
diff --git a/linux/LibSensors.c b/linux/LibSensors.c
index a30e21b..158829a 100644
--- a/linux/LibSensors.c
+++ b/linux/LibSensors.c
@@ -4,6 +4,7 @@
#include <dlfcn.h>
#include <errno.h>
+#include <math.h>
#include <sensors/sensors.h>
#include "XUtils.h"
@@ -16,13 +17,20 @@ static int (*sym_sensors_snprintf_chip_name)(char*, size_t, const sensors_chip_n
static const sensors_feature* (*sym_sensors_get_features)(const sensors_chip_name*, int*);
static const sensors_subfeature* (*sym_sensors_get_subfeature)(const sensors_chip_name*, const sensors_feature*, sensors_subfeature_type);
static int (*sym_sensors_get_value)(const sensors_chip_name*, int, double*);
+static char* (*sym_sensors_get_label)(const sensors_chip_name*, const sensors_feature*);
static void* dlopenHandle = NULL;
int LibSensors_init(FILE* input) {
if (!dlopenHandle) {
+ /* Find the unversioned libsensors.so (symlink) and prefer that, but Debian has .so.5 and Fedora .so.4 without
+ matching symlinks (unless people install the -dev packages) */
dlopenHandle = dlopen("libsensors.so", RTLD_LAZY);
if (!dlopenHandle)
+ dlopenHandle = dlopen("libsensors.so.5", RTLD_LAZY);
+ if (!dlopenHandle)
+ dlopenHandle = dlopen("libsensors.so.4", RTLD_LAZY);
+ if (!dlopenHandle)
goto dlfailure;
/* Clear any errors */
@@ -41,6 +49,7 @@ int LibSensors_init(FILE* input) {
resolve(sensors_get_features);
resolve(sensors_get_subfeature);
resolve(sensors_get_value);
+ resolve(sensors_get_label);
#undef resolve
}
@@ -64,17 +73,23 @@ void LibSensors_cleanup(void) {
}
}
-int LibSensors_getCPUTemperatures(CPUData* cpus, int cpuCount) {
+void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int cpuCount) {
+ for (unsigned int i = 0; i <= cpuCount; i++)
+ cpus[i].temperature = NAN;
+
if (!dlopenHandle)
- return -ENOTSUP;
+ return;
- int tempCount = 0;
+ unsigned int coreTempCount = 0;
int n = 0;
for (const sensors_chip_name *chip = sym_sensors_get_detected_chips(NULL, &n); chip; chip = sym_sensors_get_detected_chips(NULL, &n)) {
char buffer[32];
sym_sensors_snprintf_chip_name(buffer, sizeof(buffer), chip);
- if (!String_startsWith(buffer, "coretemp") && !String_startsWith(buffer, "cpu_thermal"))
+ if (!String_startsWith(buffer, "coretemp") &&
+ !String_startsWith(buffer, "cpu_thermal") &&
+ !String_startsWith(buffer, "k10temp") &&
+ !String_startsWith(buffer, "zenpower"))
continue;
int m = 0;
@@ -82,7 +97,27 @@ int LibSensors_getCPUTemperatures(CPUData* cpus, int cpuCount) {
if (feature->type != SENSORS_FEATURE_TEMP)
continue;
- if (feature->number > cpuCount)
+ char* label = sym_sensors_get_label(chip, feature);
+ if (!label)
+ continue;
+
+ unsigned int tempId;
+ if (String_startsWith(label, "Package ")) {
+ tempId = 0;
+ } else if (String_startsWith(label, "temp")) {
+ /* Raspberry Pi has only temp1 */
+ tempId = 0;
+ } else if (String_startsWith(label, "Tdie")) {
+ tempId = 0;
+ } else if (String_startsWith(label, "Core ")) {
+ tempId = 1 + atoi(label + strlen("Core "));
+ } else {
+ tempId = UINT_MAX;
+ }
+
+ free(label);
+
+ if (tempId > cpuCount)
continue;
const sensors_subfeature *sub_feature = sym_sensors_get_subfeature(chip, feature, SENSORS_SUBFEATURE_TEMP_INPUT);
@@ -92,13 +127,43 @@ int LibSensors_getCPUTemperatures(CPUData* cpus, int cpuCount) {
if (r != 0)
continue;
- cpus[feature->number].temperature = temp;
- tempCount++;
+ cpus[tempId].temperature = temp;
+ if (tempId > 0)
+ coreTempCount++;
}
}
}
- return tempCount;
+ const double packageTemp = cpus[0].temperature;
+
+ /* Only package temperature - copy to all cpus */
+ if (coreTempCount == 0 && !isnan(packageTemp)) {
+ for (unsigned int i = 1; i <= cpuCount; i++)
+ cpus[i].temperature = packageTemp;
+
+ return;
+ }
+
+ /* No package temperature - set to max core temperature */
+ if (isnan(packageTemp) && coreTempCount != 0) {
+ double maxTemp = NAN;
+ for (unsigned int i = 1; i <= cpuCount; i++) {
+ const double coreTemp = cpus[i].temperature;
+ if (isnan(coreTemp))
+ continue;
+
+ maxTemp = MAXIMUM(maxTemp, coreTemp);
+ }
+
+ cpus[0].temperature = maxTemp;
+ }
+
+ /* Half the temperatures, probably HT/SMT - copy to second half */
+ const unsigned int delta = cpuCount / 2;
+ if (coreTempCount == delta) {
+ for (unsigned int i = 1; i <= delta; i++)
+ cpus[i + delta].temperature = cpus[i].temperature;
+ }
}
#endif /* HAVE_SENSORS_SENSORS_H */
diff --git a/linux/LibSensors.h b/linux/LibSensors.h
index ed9be7b..cceeedb 100644
--- a/linux/LibSensors.h
+++ b/linux/LibSensors.h
@@ -11,6 +11,6 @@
int LibSensors_init(FILE* input);
void LibSensors_cleanup(void);
-int LibSensors_getCPUTemperatures(CPUData* cpus, int cpuCount);
+void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int cpuCount);
#endif /* HEADER_LibSensors */
diff --git a/linux/LinuxProcess.c b/linux/LinuxProcess.c
index 8298000..ce6d34d 100644
--- a/linux/LinuxProcess.c
+++ b/linux/LinuxProcess.c
@@ -24,22 +24,22 @@ in the source distribution for its full text.
/* semi-global */
-long long btime;
+int pageSize;
+int pageSizeKB;
/* Used to identify kernel threads in Comm and Exe columns */
static const char *const kthreadID = "KTHREAD";
-ProcessFieldData Process_fields[] = {
+const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
[0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
- [PID] = { .name = "PID", .title = " PID ", .description = "Process/thread ID", .flags = 0, },
+ [PID] = { .name = "PID", .title = "PID", .description = "Process/thread ID", .flags = 0, .pidColumn = true, },
[COMM] = { .name = "Command", .title = "Command ", .description = "Command line", .flags = 0, },
[STATE] = { .name = "STATE", .title = "S ", .description = "Process state (S sleeping, R running, D disk, Z zombie, T traced, W paging, I idle)", .flags = 0, },
- [PPID] = { .name = "PPID", .title = " PPID ", .description = "Parent process ID", .flags = 0, },
- [PGRP] = { .name = "PGRP", .title = " PGRP ", .description = "Process group ID", .flags = 0, },
- [SESSION] = { .name = "SESSION", .title = " SID ", .description = "Process's session ID", .flags = 0, },
+ [PPID] = { .name = "PPID", .title = "PPID", .description = "Parent process ID", .flags = 0, .pidColumn = true, },
+ [PGRP] = { .name = "PGRP", .title = "PGRP", .description = "Process group ID", .flags = 0, .pidColumn = true, },
+ [SESSION] = { .name = "SESSION", .title = "SID", .description = "Process's session ID", .flags = 0, .pidColumn = true, },
[TTY_NR] = { .name = "TTY_NR", .title = "TTY ", .description = "Controlling terminal", .flags = 0, },
- [TPGID] = { .name = "TPGID", .title = " TPGID ", .description = "Process ID of the fg process group of the controlling terminal", .flags = 0, },
- [FLAGS] = { .name = "FLAGS", .title = NULL, .description = NULL, .flags = 0, },
+ [TPGID] = { .name = "TPGID", .title = "TPGID", .description = "Process ID of the fg process group of the controlling terminal", .flags = 0, .pidColumn = true, },
[MINFLT] = { .name = "MINFLT", .title = " MINFLT ", .description = "Number of minor faults which have not required loading a memory page from disk", .flags = 0, },
[CMINFLT] = { .name = "CMINFLT", .title = " CMINFLT ", .description = "Children processes' minor faults", .flags = 0, },
[MAJFLT] = { .name = "MAJFLT", .title = " MAJFLT ", .description = "Number of major faults which have required loading a memory page from disk", .flags = 0, },
@@ -50,24 +50,7 @@ ProcessFieldData Process_fields[] = {
[CSTIME] = { .name = "CSTIME", .title = " CSTIME+ ", .description = "Children processes' system CPU time", .flags = 0, },
[PRIORITY] = { .name = "PRIORITY", .title = "PRI ", .description = "Kernel's internal priority for the process", .flags = 0, },
[NICE] = { .name = "NICE", .title = " NI ", .description = "Nice value (the higher the value, the more it lets other processes take priority)", .flags = 0, },
- [ITREALVALUE] = { .name = "ITREALVALUE", .title = NULL, .description = NULL, .flags = 0, },
[STARTTIME] = { .name = "STARTTIME", .title = "START ", .description = "Time the process was started", .flags = 0, },
- [VSIZE] = { .name = "VSIZE", .title = NULL, .description = NULL, .flags = 0, },
- [RSS] = { .name = "RSS", .title = NULL, .description = NULL, .flags = 0, },
- [RLIM] = { .name = "RLIM", .title = NULL, .description = NULL, .flags = 0, },
- [STARTCODE] = { .name = "STARTCODE", .title = NULL, .description = NULL, .flags = 0, },
- [ENDCODE] = { .name = "ENDCODE", .title = NULL, .description = NULL, .flags = 0, },
- [STARTSTACK] = { .name = "STARTSTACK", .title = NULL, .description = NULL, .flags = 0, },
- [KSTKESP] = { .name = "KSTKESP", .title = NULL, .description = NULL, .flags = 0, },
- [KSTKEIP] = { .name = "KSTKEIP", .title = NULL, .description = NULL, .flags = 0, },
- [SIGNAL] = { .name = "SIGNAL", .title = NULL, .description = NULL, .flags = 0, },
- [BLOCKED] = { .name = "BLOCKED", .title = NULL, .description = NULL, .flags = 0, },
- [SSIGIGNORE] = { .name = "SIGIGNORE", .title = NULL, .description = NULL, .flags = 0, },
- [SIGCATCH] = { .name = "SIGCATCH", .title = NULL, .description = NULL, .flags = 0, },
- [WCHAN] = { .name = "WCHAN", .title = NULL, .description = NULL, .flags = 0, },
- [NSWAP] = { .name = "NSWAP", .title = NULL, .description = NULL, .flags = 0, },
- [CNSWAP] = { .name = "CNSWAP", .title = NULL, .description = NULL, .flags = 0, },
- [EXIT_SIGNAL] = { .name = "EXIT_SIGNAL", .title = NULL, .description = NULL, .flags = 0, },
[PROCESSOR] = { .name = "PROCESSOR", .title = "CPU ", .description = "Id of the CPU the process last executed on", .flags = 0, },
[M_VIRT] = { .name = "M_VIRT", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, },
[M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, },
@@ -83,10 +66,10 @@ ProcessFieldData Process_fields[] = {
[USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
[TIME] = { .name = "TIME", .title = " TIME+ ", .description = "Total time the process has spent in user and system time", .flags = 0, },
[NLWP] = { .name = "NLWP", .title = "NLWP ", .description = "Number of threads in the process", .flags = 0, },
- [TGID] = { .name = "TGID", .title = " TGID ", .description = "Thread group ID (i.e. process ID)", .flags = 0, },
+ [TGID] = { .name = "TGID", .title = "TGID", .description = "Thread group ID (i.e. process ID)", .flags = 0, .pidColumn = true, },
#ifdef HAVE_OPENVZ
[CTID] = { .name = "CTID", .title = " CTID ", .description = "OpenVZ container ID (a.k.a. virtual environment ID)", .flags = PROCESS_FLAG_LINUX_OPENVZ, },
- [VPID] = { .name = "VPID", .title = " VPID ", .description = "OpenVZ process ID", .flags = PROCESS_FLAG_LINUX_OPENVZ, },
+ [VPID] = { .name = "VPID", .title = "VPID", .description = "OpenVZ process ID", .flags = PROCESS_FLAG_LINUX_OPENVZ, .pidColumn = true, },
#endif
#ifdef HAVE_VSERVER
[VXID] = { .name = "VXID", .title = " VXID ", .description = "VServer process ID", .flags = PROCESS_FLAG_LINUX_VSERVER, },
@@ -105,9 +88,9 @@ ProcessFieldData Process_fields[] = {
[OOM] = { .name = "OOM", .title = " OOM ", .description = "OOM (Out-of-Memory) killer score", .flags = PROCESS_FLAG_LINUX_OOM, },
[IO_PRIORITY] = { .name = "IO_PRIORITY", .title = "IO ", .description = "I/O priority", .flags = PROCESS_FLAG_LINUX_IOPRIO, },
#ifdef HAVE_DELAYACCT
- [PERCENT_CPU_DELAY] = { .name = "PERCENT_CPU_DELAY", .title = "CPUD% ", .description = "CPU delay %", .flags = 0, },
- [PERCENT_IO_DELAY] = { .name = "PERCENT_IO_DELAY", .title = "IOD% ", .description = "Block I/O delay %", .flags = 0, },
- [PERCENT_SWAP_DELAY] = { .name = "PERCENT_SWAP_DELAY", .title = "SWAPD% ", .description = "Swapin delay %", .flags = 0, },
+ [PERCENT_CPU_DELAY] = { .name = "PERCENT_CPU_DELAY", .title = "CPUD% ", .description = "CPU delay %", .flags = PROCESS_FLAG_LINUX_DELAYACCT, },
+ [PERCENT_IO_DELAY] = { .name = "PERCENT_IO_DELAY", .title = "IOD% ", .description = "Block I/O delay %", .flags = PROCESS_FLAG_LINUX_DELAYACCT, },
+ [PERCENT_SWAP_DELAY] = { .name = "PERCENT_SWAP_DELAY", .title = "SWAPD% ", .description = "Swapin delay %", .flags = PROCESS_FLAG_LINUX_DELAYACCT, },
#endif
[M_PSS] = { .name = "M_PSS", .title = " PSS ", .description = "proportional set size, same as M_RESIDENT but each page is divided by the number of processes sharing it.", .flags = PROCESS_FLAG_LINUX_SMAPS, },
[M_SWAP] = { .name = "M_SWAP", .title = " SWAP ", .description = "Size of the process's swapped pages", .flags = PROCESS_FLAG_LINUX_SMAPS, },
@@ -117,20 +100,6 @@ ProcessFieldData Process_fields[] = {
[PROC_COMM] = { .name = "COMM", .title = "COMM ", .description = "comm string of the process from /proc/[pid]/comm", .flags = 0, },
[PROC_EXE] = { .name = "EXE", .title = "EXE ", .description = "Basename of exe of the process from /proc/[pid]/exe", .flags = 0, },
[CWD] = { .name ="CWD", .title = "CWD ", .description = "The current working directory of the process", .flags = PROCESS_FLAG_LINUX_CWD, },
- [LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
-};
-
-ProcessPidColumn Process_pidColumns[] = {
- { .id = PID, .label = "PID" },
- { .id = PPID, .label = "PPID" },
- #ifdef HAVE_OPENVZ
- { .id = VPID, .label = "VPID" },
- #endif
- { .id = TPGID, .label = "TPGID" },
- { .id = TGID, .label = "TGID" },
- { .id = PGRP, .label = "PGRP" },
- { .id = SESSION, .label = "SID" },
- { .id = 0, .label = NULL },
};
/* This function returns the string displayed in Command column, so that sorting
@@ -183,6 +152,11 @@ static int LinuxProcess_effectiveIOPriority(const LinuxProcess* this) {
return this->ioPriority;
}
+#ifdef __ANDROID__
+#define SYS_ioprio_get __NR_ioprio_get
+#define SYS_ioprio_set __NR_ioprio_set
+#endif
+
IOPriority LinuxProcess_updateIOPriority(LinuxProcess* this) {
IOPriority ioprio = 0;
// Other OSes masquerading as Linux (NetBSD?) don't have this syscall
@@ -224,12 +198,11 @@ static bool findCommInCmdline(const char *comm, const char *cmdline, int cmdline
/* Try to find procComm in tokenized cmdline - this might in rare cases
* mis-identify a string or fail, if comm or cmdline had been unsuitably
* modified by the process */
- const char *token;
const char *tokenBase;
size_t tokenLen;
const size_t commLen = strlen(comm);
- for (token = cmdline + cmdlineBasenameOffset; *token; ) {
+ for (const char *token = cmdline + cmdlineBasenameOffset; *token; ) {
for (tokenBase = token; *token && *token != '\n'; ++token) {
if (*token == '/') {
tokenBase = token + 1;
@@ -394,6 +367,16 @@ void LinuxProcess_makeCommandStr(Process* this) {
char *str = strStart;
int cmdlineBasenameOffset = lp->procCmdlineBasenameOffset;
+ int cmdlineBasenameEnd = lp->procCmdlineBasenameEnd;
+
+ if (!cmdline) {
+ cmdlineBasenameOffset = 0;
+ cmdlineBasenameEnd = 0;
+ cmdline = "(zombie)";
+ }
+
+ assert(cmdlineBasenameOffset >= 0);
+ assert(cmdlineBasenameOffset <= (int)strlen(cmdline));
if (!showMergedCommand || !procExe || !procComm) { /* fall back to cmdline */
if (showMergedCommand && !procExe && procComm && strlen(procComm)) { /* Prefix column with comm */
@@ -411,11 +394,11 @@ void LinuxProcess_makeCommandStr(Process* this) {
if (showProgramPath) {
(void) stpcpyWithNewlineConversion(str, cmdline);
mc->baseStart = cmdlineBasenameOffset;
- mc->baseEnd = lp->procCmdlineBasenameEnd;
+ mc->baseEnd = cmdlineBasenameEnd;
} else {
(void) stpcpyWithNewlineConversion(str, cmdline + cmdlineBasenameOffset);
mc->baseStart = 0;
- mc->baseEnd = lp->procCmdlineBasenameEnd - cmdlineBasenameOffset;
+ mc->baseEnd = cmdlineBasenameEnd - cmdlineBasenameOffset;
}
if (mc->sep1) {
@@ -430,6 +413,9 @@ void LinuxProcess_makeCommandStr(Process* this) {
int exeBasenameOffset = lp->procExeBasenameOffset;
int exeBasenameLen = exeLen - exeBasenameOffset;
+ assert(exeBasenameOffset >= 0);
+ assert(exeBasenameOffset <= (int)strlen(procExe));
+
/* Start with copying exe */
if (showProgramPath) {
str = stpcpy(str, procExe);
@@ -536,36 +522,36 @@ static void LinuxProcess_writeCommand(const Process* this, int attr, int baseAtt
if(lp->procExeDeleted)
baseAttr = CRT_colors[FAILED_READ];
- RichString_append(str, attr, lp->mergedCommand.str);
+ RichString_appendWide(str, attr, lp->mergedCommand.str);
if (lp->mergedCommand.commEnd) {
if (!lp->mergedCommand.separateComm && commStart == baseStart && highlightBaseName) {
/* If it was matched with procExe's basename, make it bold if needed */
if (commEnd > baseEnd) {
- RichString_setAttrn(str, A_BOLD | baseAttr, baseStart, baseEnd - 1);
- RichString_setAttrn(str, A_BOLD | commAttr, baseEnd, commEnd - 1);
+ RichString_setAttrn(str, A_BOLD | baseAttr, baseStart, baseEnd - baseStart);
+ RichString_setAttrn(str, A_BOLD | commAttr, baseEnd, commEnd - baseEnd);
} else if (commEnd < baseEnd) {
- RichString_setAttrn(str, A_BOLD | commAttr, commStart, commEnd - 1);
- RichString_setAttrn(str, A_BOLD | baseAttr, commEnd, baseEnd - 1);
+ RichString_setAttrn(str, A_BOLD | commAttr, commStart, commEnd - commStart);
+ RichString_setAttrn(str, A_BOLD | baseAttr, commEnd, baseEnd - commEnd);
} else {
// Actually should be highlighted commAttr, but marked baseAttr to reduce visual noise
- RichString_setAttrn(str, A_BOLD | baseAttr, commStart, commEnd - 1);
+ RichString_setAttrn(str, A_BOLD | baseAttr, commStart, commEnd - commStart);
}
baseStart = baseEnd;
} else {
- RichString_setAttrn(str, commAttr, commStart, commEnd - 1);
+ RichString_setAttrn(str, commAttr, commStart, commEnd - commStart);
}
}
if (baseStart < baseEnd && highlightBaseName) {
- RichString_setAttrn(str, baseAttr, baseStart, baseEnd - 1);
+ RichString_setAttrn(str, baseAttr, baseStart, baseEnd - baseStart);
}
if (mc->sep1)
- RichString_setAttrn(str, CRT_colors[FAILED_READ], strStart + mc->sep1, strStart + mc->sep1);
+ RichString_setAttrn(str, CRT_colors[FAILED_READ], strStart + mc->sep1, 1);
if (mc->sep2)
- RichString_setAttrn(str, CRT_colors[FAILED_READ], strStart + mc->sep2, strStart + mc->sep2);
+ RichString_setAttrn(str, CRT_colors[FAILED_READ], strStart + mc->sep2, 1);
}
static void LinuxProcess_writeCommandField(const Process *this, RichString *str, char *buffer, int n, int attr) {
@@ -605,10 +591,11 @@ static void LinuxProcess_writeCommandField(const Process *this, RichString *str,
buf = stpcpy(buf, " ");
}
}
+
n -= (buf - buffer);
- const char* draw = CRT_treeStr[lastItem ? (this->settings->direction == 1 ? TREE_STR_BEND : TREE_STR_TEND) : TREE_STR_RTEE];
+ const char* draw = CRT_treeStr[lastItem ? TREE_STR_BEND : TREE_STR_RTEE];
xSnprintf(buf, n, "%s%s ", draw, this->showChildren ? CRT_treeStr[TREE_STR_SHUT] : CRT_treeStr[TREE_STR_OPEN] );
- RichString_append(str, CRT_colors[PROCESS_TREE], buffer);
+ RichString_appendWide(str, CRT_colors[PROCESS_TREE], buffer);
LinuxProcess_writeCommand(this, attr, baseattr, str);
}
}
@@ -619,7 +606,7 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces
char buffer[256]; buffer[255] = '\0';
int attr = CRT_colors[DEFAULT_COLOR];
size_t n = sizeof(buffer) - 1;
- switch ((int)field) {
+ switch (field) {
case TTY_NR: {
if (lp->ttyDevice) {
xSnprintf(buffer, n, "%-9s", lp->ttyDevice + 5 /* skip "/dev/" */);
@@ -631,19 +618,19 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces
}
case CMINFLT: Process_colorNumber(str, lp->cminflt, coloring); return;
case CMAJFLT: Process_colorNumber(str, lp->cmajflt, coloring); return;
- case M_DRS: Process_humanNumber(str, lp->m_drs * CRT_pageSizeKB, coloring); return;
- case M_DT: Process_humanNumber(str, lp->m_dt * CRT_pageSizeKB, coloring); return;
+ case M_DRS: Process_humanNumber(str, lp->m_drs * pageSizeKB, coloring); return;
+ case M_DT: Process_humanNumber(str, lp->m_dt * pageSizeKB, coloring); return;
case M_LRS:
if (lp->m_lrs) {
- Process_humanNumber(str, lp->m_lrs * CRT_pageSizeKB, coloring);
+ Process_humanNumber(str, lp->m_lrs * pageSizeKB, coloring);
return;
}
attr = CRT_colors[PROCESS_SHADOW];
xSnprintf(buffer, n, " N/A ");
break;
- case M_TRS: Process_humanNumber(str, lp->m_trs * CRT_pageSizeKB, coloring); return;
- case M_SHARE: Process_humanNumber(str, lp->m_share * CRT_pageSizeKB, coloring); return;
+ case M_TRS: Process_humanNumber(str, lp->m_trs * pageSizeKB, coloring); return;
+ case M_SHARE: Process_humanNumber(str, lp->m_share * pageSizeKB, coloring); return;
case M_PSS: Process_humanNumber(str, lp->m_pss, coloring); return;
case M_SWAP: Process_humanNumber(str, lp->m_swap, coloring); return;
case M_PSSWP: Process_humanNumber(str, lp->m_psswp, coloring); return;
@@ -674,7 +661,7 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces
}
#ifdef HAVE_OPENVZ
case CTID: xSnprintf(buffer, n, "%-8s ", lp->ctid ? lp->ctid : ""); break;
- case VPID: xSnprintf(buffer, n, Process_pidFormat, lp->vpid); break;
+ case VPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, lp->vpid); break;
#endif
#ifdef HAVE_VSERVER
case VXID: xSnprintf(buffer, n, "%5u ", lp->vxid); break;
@@ -720,59 +707,58 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces
return;
}
case PROC_COMM: {
+ const char* procComm;
if (lp->procComm) {
attr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_COMM : PROCESS_COMM];
- /* 15 being (TASK_COMM_LEN - 1) */
- xSnprintf(buffer, n, "%-15.15s ", lp->procComm);
+ procComm = lp->procComm;
} else {
attr = CRT_colors[PROCESS_SHADOW];
- xSnprintf(buffer, n, "%-15.15s ", Process_isKernelThread(lp) ? kthreadID : "N/A");
+ procComm = Process_isKernelThread(lp) ? kthreadID : "N/A";
}
- break;
+ /* 15 being (TASK_COMM_LEN - 1) */
+ Process_printLeftAlignedField(str, attr, procComm, 15);
+ return;
}
case PROC_EXE: {
+ const char* procExe;
if (lp->procExe) {
attr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_BASENAME : PROCESS_BASENAME];
if (lp->procExeDeleted)
attr = CRT_colors[FAILED_READ];
- xSnprintf(buffer, n, "%-15.15s ", lp->procExe + lp->procExeBasenameOffset);
+ procExe = lp->procExe + lp->procExeBasenameOffset;
} else {
attr = CRT_colors[PROCESS_SHADOW];
- xSnprintf(buffer, n, "%-15.15s ", Process_isKernelThread(lp) ? kthreadID : "N/A");
+ procExe = Process_isKernelThread(lp) ? kthreadID : "N/A";
}
- break;
+ Process_printLeftAlignedField(str, attr, procExe, 15);
+ return;
}
- case CWD:
+ case CWD: {
+ const char* cwd;
if (!lp->cwd) {
- xSnprintf(buffer, n, "%-25s ", "N/A");
attr = CRT_colors[PROCESS_SHADOW];
+ cwd = "N/A";
} else if (String_startsWith(lp->cwd, "/proc/") && strstr(lp->cwd, " (deleted)") != NULL) {
- xSnprintf(buffer, n, "%-25s ", "main thread terminated");
attr = CRT_colors[PROCESS_SHADOW];
+ cwd = "main thread terminated";
} else {
- xSnprintf(buffer, n, "%-25.25s ", lp->cwd);
+ cwd = lp->cwd;
}
- break;
+ Process_printLeftAlignedField(str, attr, cwd, 25);
+ return;
+ }
default:
Process_writeField(this, str, field);
return;
}
- RichString_append(str, attr, buffer);
+ RichString_appendWide(str, attr, buffer);
}
-static long LinuxProcess_compare(const void* v1, const void* v2) {
- const LinuxProcess *p1, *p2;
- const Settings *settings = ((const Process*)v1)->settings;
-
- if (settings->direction == 1) {
- p1 = (const LinuxProcess*)v1;
- p2 = (const LinuxProcess*)v2;
- } else {
- p2 = (const LinuxProcess*)v1;
- p1 = (const LinuxProcess*)v2;
- }
+static int LinuxProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
+ const LinuxProcess* p1 = (const LinuxProcess*)v1;
+ const LinuxProcess* p2 = (const LinuxProcess*)v2;
- switch ((int)settings->sortKey) {
+ switch (key) {
case M_DRS:
return SPACESHIP_NUMBER(p2->m_drs, p1->m_drs);
case M_DT:
@@ -858,7 +844,7 @@ static long LinuxProcess_compare(const void* v1, const void* v2) {
case CWD:
return SPACESHIP_NULLSTR(p1->cwd, p2->cwd);
default:
- return Process_compare(v1, v2);
+ return Process_compareByKey_Base(v1, v2, key);
}
}
@@ -871,8 +857,9 @@ const ProcessClass LinuxProcess_class = {
.extends = Class(Process),
.display = Process_display,
.delete = Process_delete,
- .compare = LinuxProcess_compare
+ .compare = Process_compare
},
.writeField = LinuxProcess_writeField,
- .getCommandStr = LinuxProcess_getCommandStr
+ .getCommandStr = LinuxProcess_getCommandStr,
+ .compareByKey = LinuxProcess_compareByKey
};
diff --git a/linux/LinuxProcess.h b/linux/LinuxProcess.h
index ad396fb..2e9a9d1 100644
--- a/linux/LinuxProcess.h
+++ b/linux/LinuxProcess.h
@@ -18,85 +18,18 @@ in the source distribution for its full text.
#include "Settings.h"
-#define PROCESS_FLAG_LINUX_IOPRIO 0x00000100
-#define PROCESS_FLAG_LINUX_OPENVZ 0x00000200
-#define PROCESS_FLAG_LINUX_VSERVER 0x00000400
-#define PROCESS_FLAG_LINUX_CGROUP 0x00000800
-#define PROCESS_FLAG_LINUX_OOM 0x00001000
-#define PROCESS_FLAG_LINUX_SMAPS 0x00002000
-#define PROCESS_FLAG_LINUX_CTXT 0x00004000
-#define PROCESS_FLAG_LINUX_SECATTR 0x00008000
-#define PROCESS_FLAG_LINUX_LRS_FIX 0x00010000
-#define PROCESS_FLAG_LINUX_CWD 0x00020000
-
-typedef enum UnsupportedProcessFields {
- FLAGS = 9,
- ITREALVALUE = 20,
- VSIZE = 22,
- RSS = 23,
- RLIM = 24,
- STARTCODE = 25,
- ENDCODE = 26,
- STARTSTACK = 27,
- KSTKESP = 28,
- KSTKEIP = 29,
- SIGNAL = 30,
- BLOCKED = 31,
- SSIGIGNORE = 32,
- SIGCATCH = 33,
- WCHAN = 34,
- NSWAP = 35,
- CNSWAP = 36,
- EXIT_SIGNAL = 37,
-} UnsupportedProcessField;
-
-typedef enum LinuxProcessFields {
- CMINFLT = 11,
- CMAJFLT = 13,
- UTIME = 14,
- STIME = 15,
- CUTIME = 16,
- CSTIME = 17,
- M_SHARE = 41,
- M_TRS = 42,
- M_DRS = 43,
- M_LRS = 44,
- M_DT = 45,
- #ifdef HAVE_OPENVZ
- CTID = 100,
- VPID = 101,
- #endif
- #ifdef HAVE_VSERVER
- VXID = 102,
- #endif
- RCHAR = 103,
- WCHAR = 104,
- SYSCR = 105,
- SYSCW = 106,
- RBYTES = 107,
- WBYTES = 108,
- CNCLWB = 109,
- IO_READ_RATE = 110,
- IO_WRITE_RATE = 111,
- IO_RATE = 112,
- CGROUP = 113,
- OOM = 114,
- IO_PRIORITY = 115,
- #ifdef HAVE_DELAYACCT
- PERCENT_CPU_DELAY = 116,
- PERCENT_IO_DELAY = 117,
- PERCENT_SWAP_DELAY = 118,
- #endif
- M_PSS = 119,
- M_SWAP = 120,
- M_PSSWP = 121,
- CTXT = 122,
- SECATTR = 123,
- PROC_COMM = 124,
- PROC_EXE = 125,
- CWD = 126,
- LAST_PROCESSFIELD = 127,
-} LinuxProcessField;
+#define PROCESS_FLAG_LINUX_IOPRIO 0x00000100
+#define PROCESS_FLAG_LINUX_OPENVZ 0x00000200
+#define PROCESS_FLAG_LINUX_VSERVER 0x00000400
+#define PROCESS_FLAG_LINUX_CGROUP 0x00000800
+#define PROCESS_FLAG_LINUX_OOM 0x00001000
+#define PROCESS_FLAG_LINUX_SMAPS 0x00002000
+#define PROCESS_FLAG_LINUX_CTXT 0x00004000
+#define PROCESS_FLAG_LINUX_SECATTR 0x00008000
+#define PROCESS_FLAG_LINUX_LRS_FIX 0x00010000
+#define PROCESS_FLAG_LINUX_CWD 0x00020000
+#define PROCESS_FLAG_LINUX_DELAYACCT 0x00040000
+
/* LinuxProcessMergedCommand is populated by LinuxProcess_makeCommandStr: It
* contains the merged Command string, and the information needed by
@@ -191,11 +124,11 @@ static inline bool Process_isUserlandThread(const Process* this) {
return this->pid != this->tgid;
}
-extern long long btime;
+extern int pageSize;
-extern ProcessFieldData Process_fields[];
+extern int pageSizeKB;
-extern ProcessPidColumn Process_pidColumns[];
+extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
extern const ProcessClass LinuxProcess_class;
diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c
index b9ba247..434d070 100644
--- a/linux/LinuxProcessList.c
+++ b/linux/LinuxProcessList.c
@@ -57,6 +57,16 @@ in the source distribution for its full text.
#endif
+// CentOS 6's kernel doesn't provide a definition of O_PATH
+// based on definition taken from uapi/asm-generic/fcnth.h in Linux kernel tree
+#ifndef O_PATH
+# define O_PATH 010000000
+#endif
+
+static long long btime;
+
+static long jiffy;
+
static FILE* fopenat(openat_arg_t openatArg, const char* pathname, const char* mode) {
assert(String_eq(mode, "r")); /* only currently supported mode */
@@ -92,7 +102,7 @@ static void LinuxProcessList_initTtyDrivers(LinuxProcessList* this) {
int numDrivers = 0;
int allocd = 10;
- ttyDrivers = xMalloc(sizeof(TtyDriver) * allocd);
+ ttyDrivers = xMallocArray(allocd, sizeof(TtyDriver));
char* at = buf;
while (*at != '\0') {
at = strchr(at, ' '); // skip first token
@@ -126,7 +136,7 @@ static void LinuxProcessList_initTtyDrivers(LinuxProcessList* this) {
numDrivers++;
if (numDrivers == allocd) {
allocd += 10;
- ttyDrivers = xRealloc(ttyDrivers, sizeof(TtyDriver) * allocd);
+ ttyDrivers = xReallocArray(ttyDrivers, allocd, sizeof(TtyDriver));
}
}
numDrivers++;
@@ -198,39 +208,39 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
ProcessList_init(pl, Class(LinuxProcess), usersTable, pidMatchList, userId);
LinuxProcessList_initTtyDrivers(this);
- #ifdef HAVE_DELAYACCT
- LinuxProcessList_initNetlinkSocket(this);
- #endif
+ // Initialize page size
+ pageSize = sysconf(_SC_PAGESIZE);
+ if (pageSize == -1)
+ CRT_fatalError("Cannot get pagesize by sysconf(_SC_PAGESIZE)");
+ pageSizeKB = pageSize / ONE_K;
- // Check for /proc/*/smaps_rollup availability (improves smaps parsing speed, Linux 4.14+)
- FILE* file = fopen(PROCDIR "/self/smaps_rollup", "r");
- if (file != NULL) {
- this->haveSmapsRollup = true;
- fclose(file);
- } else {
- this->haveSmapsRollup = false;
- }
+ // Initialize clock ticks
+ jiffy = sysconf(_SC_CLK_TCK);
+ if (jiffy == -1)
+ CRT_fatalError("Cannot get clock ticks by sysconf(_SC_CLK_TCK)");
+
+ // Test /proc/PID/smaps_rollup availability (faster to parse, Linux 4.14+)
+ this->haveSmapsRollup = (access(PROCDIR "/self/smaps_rollup", R_OK) == 0);
- // Read btime
+ // Read btime (the kernel boot time, as number of seconds since the epoch)
{
FILE* statfile = fopen(PROCSTATFILE, "r");
- if (statfile == NULL) {
+ if (statfile == NULL)
CRT_fatalError("Cannot open " PROCSTATFILE);
- }
-
while (true) {
char buffer[PROC_LINE_LENGTH + 1];
- if (fgets(buffer, sizeof(buffer), statfile) == NULL) {
- CRT_fatalError("No btime in " PROCSTATFILE);
- } else if (String_startsWith(buffer, "btime ")) {
- if (sscanf(buffer, "btime %lld\n", &btime) != 1) {
- CRT_fatalError("Failed to parse btime from " PROCSTATFILE);
- }
+ if (fgets(buffer, sizeof(buffer), statfile) == NULL)
break;
- }
+ if (String_startsWith(buffer, "btime ") == false)
+ continue;
+ if (sscanf(buffer, "btime %lld\n", &btime) == 1)
+ break;
+ CRT_fatalError("Failed to parse btime from " PROCSTATFILE);
}
-
fclose(statfile);
+
+ if (!btime)
+ CRT_fatalError("No btime in " PROCSTATFILE);
}
// Initialize CPU count
@@ -267,16 +277,7 @@ void ProcessList_delete(ProcessList* pl) {
free(this);
}
-static inline unsigned long long LinuxProcess_adjustTime(unsigned long long t) {
- static long jiffy = -1;
- if (jiffy == -1) {
- errno = 0;
- jiffy = sysconf(_SC_CLK_TCK);
- if (errno || -1 == jiffy) {
- jiffy = -1;
- return t; // Assume 100Hz clock
- }
- }
+static inline unsigned long long LinuxProcessList_adjustTime(unsigned long long t) {
return t * 100 / jiffy;
}
@@ -329,13 +330,13 @@ static bool LinuxProcessList_readStatFile(Process* process, openat_arg_t procFd,
location += 1;
lp->cmajflt = strtoull(location, &location, 10);
location += 1;
- lp->utime = LinuxProcess_adjustTime(strtoull(location, &location, 10));
+ lp->utime = LinuxProcessList_adjustTime(strtoull(location, &location, 10));
location += 1;
- lp->stime = LinuxProcess_adjustTime(strtoull(location, &location, 10));
+ lp->stime = LinuxProcessList_adjustTime(strtoull(location, &location, 10));
location += 1;
- lp->cutime = LinuxProcess_adjustTime(strtoull(location, &location, 10));
+ lp->cutime = LinuxProcessList_adjustTime(strtoull(location, &location, 10));
location += 1;
- lp->cstime = LinuxProcess_adjustTime(strtoull(location, &location, 10));
+ lp->cstime = LinuxProcessList_adjustTime(strtoull(location, &location, 10));
location += 1;
process->priority = strtol(location, &location, 10);
location += 1;
@@ -345,7 +346,7 @@ static bool LinuxProcessList_readStatFile(Process* process, openat_arg_t procFd,
location += 1;
location = strchr(location, ' ') + 1;
if (process->starttime_ctime == 0) {
- process->starttime_ctime = btime + LinuxProcess_adjustTime(strtoll(location, &location, 10)) / 100;
+ process->starttime_ctime = btime + LinuxProcessList_adjustTime(strtoll(location, &location, 10)) / 100;
} else {
location = strchr(location, ' ') + 1;
}
@@ -483,7 +484,7 @@ static inline uint64_t fast_strtoull_hex(char **str, int maxlen) {
return result;
}
-static void LinuxProcessList_calcLibSize_helper(ATTR_UNUSED hkey_t key, void* value, void* data) {
+static void LinuxProcessList_calcLibSize_helper(ATTR_UNUSED ht_key_t key, void* value, void* data) {
if (!data)
return;
@@ -573,7 +574,7 @@ static uint64_t LinuxProcessList_calcLibSize(openat_arg_t procFd) {
Hashtable_delete(ht);
- return total_size / CRT_pageSize;
+ return total_size / pageSize;
}
static bool LinuxProcessList_readStatmFile(LinuxProcess* process, openat_arg_t procFd, bool performLookup, unsigned long long now) {
@@ -593,6 +594,9 @@ static bool LinuxProcessList_readStatmFile(LinuxProcess* process, openat_arg_t p
fclose(statmfile);
if (r == 7) {
+ process->super.m_virt *= pageSizeKB;
+ process->super.m_resident *= pageSizeKB;
+
if (tmp_m_lrs) {
process->m_lrs = tmp_m_lrs;
} else if (performLookup) {
@@ -947,12 +951,19 @@ static int handleNetlinkMsg(struct nl_msg* nlmsg, void* linuxProcess) {
static void LinuxProcessList_readDelayAcctData(LinuxProcessList* this, LinuxProcess* process) {
struct nl_msg* msg;
+ if (!this->netlink_socket) {
+ LinuxProcessList_initNetlinkSocket(this);
+ if (!this->netlink_socket) {
+ goto delayacct_failure;
+ }
+ }
+
if (nl_socket_modify_cb(this->netlink_socket, NL_CB_VALID, NL_CB_CUSTOM, handleNetlinkMsg, process) < 0) {
- return;
+ goto delayacct_failure;
}
if (! (msg = nlmsg_alloc())) {
- return;
+ goto delayacct_failure;
}
if (! genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, this->netlink_family, 0, NLM_F_REQUEST, TASKSTATS_CMD_GET, TASKSTATS_VERSION)) {
@@ -964,15 +975,19 @@ static void LinuxProcessList_readDelayAcctData(LinuxProcessList* this, LinuxProc
}
if (nl_send_sync(this->netlink_socket, msg) < 0) {
- process->swapin_delay_percent = NAN;
- process->blkio_delay_percent = NAN;
- process->cpu_delay_percent = NAN;
- return;
+ goto delayacct_failure;
}
if (nl_recvmsgs_default(this->netlink_socket) < 0) {
- return;
+ goto delayacct_failure;
}
+
+ return;
+
+delayacct_failure:
+ process->swapin_delay_percent = NAN;
+ process->blkio_delay_percent = NAN;
+ process->cpu_delay_percent = NAN;
}
#endif
@@ -1363,9 +1378,9 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
}
/* period might be 0 after system sleep */
- float percent_cpu = (period < 1e-6) ? 0.0f : ((lp->utime + lp->stime - lasttimes) / period * 100.0);
- proc->percent_cpu = CLAMP(percent_cpu, 0.0f, cpus * 100.0f);
- proc->percent_mem = (proc->m_resident * CRT_pageSizeKB) / (double)(pl->totalMem) * 100.0;
+ float percent_cpu = (period < 1E-6) ? 0.0F : ((lp->utime + lp->stime - lasttimes) / period * 100.0);
+ proc->percent_cpu = CLAMP(percent_cpu, 0.0F, cpus * 100.0F);
+ proc->percent_mem = proc->m_resident / (double)(pl->totalMem) * 100.0;
if (!preExisting) {
@@ -1411,7 +1426,9 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
}
#ifdef HAVE_DELAYACCT
- LinuxProcessList_readDelayAcctData(this, lp);
+ if (settings->flags & PROCESS_FLAG_LINUX_DELAYACCT) {
+ LinuxProcessList_readDelayAcctData(this, lp);
+ }
#endif
if (settings->flags & PROCESS_FLAG_LINUX_CGROUP) {
@@ -1785,7 +1802,9 @@ static void scanCPUFreqencyFromCPUinfo(LinuxProcessList* this) {
continue;
} else if (
(sscanf(buffer, "cpu MHz : %lf", &frequency) == 1) ||
- (sscanf(buffer, "cpu MHz: %lf", &frequency) == 1)
+ (sscanf(buffer, "cpu MHz: %lf", &frequency) == 1) ||
+ (sscanf(buffer, "clock : %lfMHz", &frequency) == 1) ||
+ (sscanf(buffer, "clock: %lfMHz", &frequency) == 1)
) {
if (cpuid < 0 || cpuid > (cpus - 1)) {
continue;
@@ -1824,41 +1843,6 @@ static void LinuxProcessList_scanCPUFrequency(LinuxProcessList* this) {
scanCPUFreqencyFromCPUinfo(this);
}
-#ifdef HAVE_SENSORS_SENSORS_H
-static void LinuxProcessList_scanCPUTemperature(LinuxProcessList* this) {
- const int cpuCount = this->super.cpuCount;
-
- for (int i = 0; i <= cpuCount; i++) {
- this->cpus[i].temperature = NAN;
- }
-
- int r = LibSensors_getCPUTemperatures(this->cpus, cpuCount);
-
- /* No temperature - nothing to do */
- if (r <= 0)
- return;
-
- /* Only package temperature - copy to all cpus */
- if (r == 1 && !isnan(this->cpus[0].temperature)) {
- double packageTemp = this->cpus[0].temperature;
- for (int i = 1; i <= cpuCount; i++) {
- this->cpus[i].temperature = packageTemp;
- }
-
- return;
- }
-
- /* Half the temperatures, probably HT/SMT - copy to second half */
- if (r >= 2 && (r - 1) == (cpuCount / 2)) {
- for (int i = cpuCount / 2 + 1; i <= cpuCount; i++) {
- this->cpus[i].temperature = this->cpus[i/2].temperature;
- }
-
- return;
- }
-}
-#endif
-
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
LinuxProcessList* this = (LinuxProcessList*) super;
const Settings* settings = super->settings;
@@ -1876,7 +1860,7 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
#ifdef HAVE_SENSORS_SENSORS_H
if (settings->showCPUTemperature)
- LinuxProcessList_scanCPUTemperature(this);
+ LibSensors_getCPUTemperatures(this->cpus, this->super.cpuCount);
#endif
// in pause mode only gather global data for meters (CPU/memory/...)
diff --git a/linux/Platform.c b/linux/Platform.c
index 590fc7a..dd80ded 100644
--- a/linux/Platform.c
+++ b/linux/Platform.c
@@ -65,9 +65,7 @@ in the source distribution for its full text.
#endif
-ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, (int)M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
-
-int Platform_numberOfFields = LAST_PROCESSFIELD;
+const ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
const SignalItem Platform_signals[] = {
{ .name = " 0 Cancel", .number = 0 },
diff --git a/linux/Platform.h b/linux/Platform.h
index 280b997..fe81448 100644
--- a/linux/Platform.h
+++ b/linux/Platform.h
@@ -18,9 +18,7 @@ in the source distribution for its full text.
#include "ProcessLocksScreen.h"
#include "SignalsPanel.h"
-extern ProcessField Platform_defaultFields[];
-
-extern int Platform_numberOfFields;
+extern const ProcessField Platform_defaultFields[];
extern const SignalItem Platform_signals[];
diff --git a/linux/PressureStallMeter.c b/linux/PressureStallMeter.c
index 745068c..7486968 100644
--- a/linux/PressureStallMeter.c
+++ b/linux/PressureStallMeter.c
@@ -43,18 +43,22 @@ static void PressureStallMeter_updateValues(Meter* this, char* buffer, size_t le
}
Platform_getPressureStall(file, some, &this->values[0], &this->values[1], &this->values[2]);
- xSnprintf(buffer, len, "%s %s %.2lf%% %.2lf%% %.2lf%%", some ? "some" : "full", file, this->values[0], this->values[1], this->values[2]);
+
+ /* only print bar for ten (not sixty and threehundred), cause the sum is meaningless */
+ this->curItems = 1;
+
+ xSnprintf(buffer, len, "%s %s %5.2lf%% %5.2lf%% %5.2lf%%", some ? "some" : "full", file, this->values[0], this->values[1], this->values[2]);
}
static void PressureStallMeter_display(const Object* cast, RichString* out) {
const Meter* this = (const Meter*)cast;
char buffer[20];
- xSnprintf(buffer, sizeof(buffer), "%.2lf%% ", this->values[0]);
- RichString_write(out, CRT_colors[PRESSURE_STALL_TEN], buffer);
- xSnprintf(buffer, sizeof(buffer), "%.2lf%% ", this->values[1]);
- RichString_append(out, CRT_colors[PRESSURE_STALL_SIXTY], buffer);
- xSnprintf(buffer, sizeof(buffer), "%.2lf%% ", this->values[2]);
- RichString_append(out, CRT_colors[PRESSURE_STALL_THREEHUNDRED], buffer);
+ xSnprintf(buffer, sizeof(buffer), "%5.2lf%% ", this->values[0]);
+ RichString_writeAscii(out, CRT_colors[PRESSURE_STALL_TEN], buffer);
+ xSnprintf(buffer, sizeof(buffer), "%5.2lf%% ", this->values[1]);
+ RichString_appendAscii(out, CRT_colors[PRESSURE_STALL_SIXTY], buffer);
+ xSnprintf(buffer, sizeof(buffer), "%5.2lf%% ", this->values[2]);
+ RichString_appendAscii(out, CRT_colors[PRESSURE_STALL_THREEHUNDRED], buffer);
}
const MeterClass PressureStallCPUSomeMeter_class = {
diff --git a/linux/ProcessField.h b/linux/ProcessField.h
new file mode 100644
index 0000000..6e2eff3
--- /dev/null
+++ b/linux/ProcessField.h
@@ -0,0 +1,53 @@
+#ifndef HEADER_LinuxProcessField
+#define HEADER_LinuxProcessField
+/*
+htop - linux/ProcessField.h
+(C) 2020 htop dev team
+Released under the GNU GPLv2, see the COPYING file
+in the source distribution for its full text.
+*/
+
+
+#define PLATFORM_PROCESS_FIELDS \
+ CMINFLT = 11, \
+ CMAJFLT = 13, \
+ UTIME = 14, \
+ STIME = 15, \
+ CUTIME = 16, \
+ CSTIME = 17, \
+ M_SHARE = 41, \
+ M_TRS = 42, \
+ M_DRS = 43, \
+ M_LRS = 44, \
+ M_DT = 45, \
+ CTID = 100, \
+ VPID = 101, \
+ VXID = 102, \
+ RCHAR = 103, \
+ WCHAR = 104, \
+ SYSCR = 105, \
+ SYSCW = 106, \
+ RBYTES = 107, \
+ WBYTES = 108, \
+ CNCLWB = 109, \
+ IO_READ_RATE = 110, \
+ IO_WRITE_RATE = 111, \
+ IO_RATE = 112, \
+ CGROUP = 113, \
+ OOM = 114, \
+ IO_PRIORITY = 115, \
+ PERCENT_CPU_DELAY = 116, \
+ PERCENT_IO_DELAY = 117, \
+ PERCENT_SWAP_DELAY = 118, \
+ M_PSS = 119, \
+ M_SWAP = 120, \
+ M_PSSWP = 121, \
+ CTXT = 122, \
+ SECATTR = 123, \
+ PROC_COMM = 124, \
+ PROC_EXE = 125, \
+ CWD = 126, \
+ // End of list
+
+
+#endif /* HEADER_LinuxProcessField */
diff --git a/linux/SELinuxMeter.c b/linux/SELinuxMeter.c
index 64a3f2a..892f1e8 100644
--- a/linux/SELinuxMeter.c
+++ b/linux/SELinuxMeter.c
@@ -35,7 +35,7 @@ static bool hasSELinuxMount(void) {
return false;
}
- if (sfbuf.f_type != SELINUX_MAGIC) {
+ if ((uint32_t)sfbuf.f_type != (uint32_t)SELINUX_MAGIC) {
return false;
}
diff --git a/linux/SystemdMeter.c b/linux/SystemdMeter.c
index 4350d26..61bb59b 100644
--- a/linux/SystemdMeter.c
+++ b/linux/SystemdMeter.c
@@ -267,9 +267,9 @@ static void SystemdMeter_display(ATTR_UNUSED const Object* cast, RichString* out
char buffer[16];
int color = (systemState && 0 == strcmp(systemState, "running")) ? METER_VALUE_OK : METER_VALUE_ERROR;
- RichString_write(out, CRT_colors[color], systemState ? systemState : "???");
+ RichString_writeAscii(out, CRT_colors[color], systemState ? systemState : "N/A");
- RichString_append(out, CRT_colors[METER_TEXT], " (");
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " (");
if (nFailedUnits == INVALID_VALUE) {
buffer[0] = '?';
@@ -277,9 +277,9 @@ static void SystemdMeter_display(ATTR_UNUSED const Object* cast, RichString* out
} else {
xSnprintf(buffer, sizeof(buffer), "%u", nFailedUnits);
}
- RichString_append(out, zeroDigitColor(nFailedUnits), buffer);
+ RichString_appendAscii(out, zeroDigitColor(nFailedUnits), buffer);
- RichString_append(out, CRT_colors[METER_TEXT], "/");
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], "/");
if (nNames == INVALID_VALUE) {
buffer[0] = '?';
@@ -287,9 +287,9 @@ static void SystemdMeter_display(ATTR_UNUSED const Object* cast, RichString* out
} else {
xSnprintf(buffer, sizeof(buffer), "%u", nNames);
}
- RichString_append(out, valueDigitColor(nNames), buffer);
+ RichString_appendAscii(out, valueDigitColor(nNames), buffer);
- RichString_append(out, CRT_colors[METER_TEXT], " failed) (");
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " failed) (");
if (nJobs == INVALID_VALUE) {
buffer[0] = '?';
@@ -297,9 +297,9 @@ static void SystemdMeter_display(ATTR_UNUSED const Object* cast, RichString* out
} else {
xSnprintf(buffer, sizeof(buffer), "%u", nJobs);
}
- RichString_append(out, zeroDigitColor(nJobs), buffer);
+ RichString_appendAscii(out, zeroDigitColor(nJobs), buffer);
- RichString_append(out, CRT_colors[METER_TEXT], "/");
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], "/");
if (nInstalledJobs == INVALID_VALUE) {
buffer[0] = '?';
@@ -307,9 +307,9 @@ static void SystemdMeter_display(ATTR_UNUSED const Object* cast, RichString* out
} else {
xSnprintf(buffer, sizeof(buffer), "%u", nInstalledJobs);
}
- RichString_append(out, valueDigitColor(nInstalledJobs), buffer);
+ RichString_appendAscii(out, valueDigitColor(nInstalledJobs), buffer);
- RichString_append(out, CRT_colors[METER_TEXT], " jobs)");
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " jobs)");
}
static const int SystemdMeter_attributes[] = {
diff --git a/linux/ZramMeter.c b/linux/ZramMeter.c
index e6b6937..723de0a 100644
--- a/linux/ZramMeter.c
+++ b/linux/ZramMeter.c
@@ -37,17 +37,19 @@ static void ZramMeter_updateValues(Meter* this, char* buffer, size_t size) {
static void ZramMeter_display(const Object* cast, RichString* out) {
char buffer[50];
const Meter* this = (const Meter*)cast;
- RichString_write(out, CRT_colors[METER_TEXT], ":");
+
+ RichString_writeAscii(out, CRT_colors[METER_TEXT], ":");
+
Meter_humanUnit(buffer, this->total, sizeof(buffer));
+ RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
- RichString_append(out, CRT_colors[METER_VALUE], buffer);
Meter_humanUnit(buffer, this->values[0], sizeof(buffer));
- RichString_append(out, CRT_colors[METER_TEXT], " used:");
- RichString_append(out, CRT_colors[METER_VALUE], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " used:");
+ RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
Meter_humanUnit(buffer, this->values[1], sizeof(buffer));
- RichString_append(out, CRT_colors[METER_TEXT], " uncompressed:");
- RichString_append(out, CRT_colors[METER_VALUE], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " uncompressed:");
+ RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
}
const MeterClass ZramMeter_class = {
diff --git a/openbsd/OpenBSDProcess.c b/openbsd/OpenBSDProcess.c
index df5002a..00aea63 100644
--- a/openbsd/OpenBSDProcess.c
+++ b/openbsd/OpenBSDProcess.c
@@ -16,7 +16,7 @@ in the source distribution for its full text.
#include "XUtils.h"
-ProcessFieldData Process_fields[] = {
+const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
[0] = {
.name = "",
.title = NULL,
@@ -25,9 +25,10 @@ ProcessFieldData Process_fields[] = {
},
[PID] = {
.name = "PID",
- .title = " PID ",
+ .title = "PID",
.description = "Process/thread ID",
.flags = 0,
+ .pidColumn = true,
},
[COMM] = {
.name = "Command",
@@ -43,21 +44,24 @@ ProcessFieldData Process_fields[] = {
},
[PPID] = {
.name = "PPID",
- .title = " PPID ",
+ .title = "PPID",
.description = "Parent process ID",
.flags = 0,
+ .pidColumn = true,
},
[PGRP] = {
.name = "PGRP",
- .title = " PGRP ",
+ .title = "PGRP",
.description = "Process group ID",
.flags = 0,
+ .pidColumn = true,
},
[SESSION] = {
.name = "SESSION",
- .title = " SESN ",
+ .title = "SESN",
.description = "Process's session ID",
.flags = 0,
+ .pidColumn = true,
},
[TTY_NR] = {
.name = "TTY_NR",
@@ -67,9 +71,10 @@ ProcessFieldData Process_fields[] = {
},
[TPGID] = {
.name = "TPGID",
- .title = " TPGID ",
+ .title = "TPGID",
.description = "Process ID of the fg process group of the controlling terminal",
.flags = 0,
+ .pidColumn = true,
},
[MINFLT] = {
.name = "MINFLT",
@@ -163,28 +168,13 @@ ProcessFieldData Process_fields[] = {
},
[TGID] = {
.name = "TGID",
- .title = " TGID ",
+ .title = "TGID",
.description = "Thread group ID (i.e. process ID)",
.flags = 0,
- },
- [LAST_PROCESSFIELD] = {
- .name = "*** report bug! ***",
- .title = NULL,
- .description = NULL,
- .flags = 0,
+ .pidColumn = true,
},
};
-ProcessPidColumn Process_pidColumns[] = {
- { .id = PID, .label = "PID" },
- { .id = PPID, .label = "PPID" },
- { .id = TPGID, .label = "TPGID" },
- { .id = TGID, .label = "TGID" },
- { .id = PGRP, .label = "PGRP" },
- { .id = SESSION, .label = "SESN" },
- { .id = 0, .label = NULL },
-};
-
Process* OpenBSDProcess_new(const Settings* settings) {
OpenBSDProcess* this = xCalloc(sizeof(OpenBSDProcess), 1);
Object_setClass(this, Class(OpenBSDProcess));
@@ -209,28 +199,20 @@ static void OpenBSDProcess_writeField(const Process* this, RichString* str, Proc
Process_writeField(this, str, field);
return;
}
- RichString_append(str, attr, buffer);
+ RichString_appendWide(str, attr, buffer);
}
-static long OpenBSDProcess_compare(const void* v1, const void* v2) {
- const OpenBSDProcess *p1, *p2;
- const Settings *settings = ((const Process*)v1)->settings;
-
- if (settings->direction == 1) {
- p1 = (const OpenBSDProcess*)v1;
- p2 = (const OpenBSDProcess*)v2;
- } else {
- p2 = (const OpenBSDProcess*)v1;
- p1 = (const OpenBSDProcess*)v2;
- }
+static int OpenBSDProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
+ const OpenBSDProcess* p1 = (const OpenBSDProcess*)v1;
+ const OpenBSDProcess* p2 = (const OpenBSDProcess*)v2;
// remove if actually used
(void)p1; (void)p2;
- switch (settings->sortKey) {
+ switch (key) {
// add OpenBSD-specific fields here
default:
- return Process_compare(v1, v2);
+ return Process_compareByKey_Base(v1, v2, key);
}
}
@@ -239,9 +221,10 @@ const ProcessClass OpenBSDProcess_class = {
.extends = Class(Process),
.display = Process_display,
.delete = Process_delete,
- .compare = OpenBSDProcess_compare
+ .compare = Process_compare
},
.writeField = OpenBSDProcess_writeField,
+ .compareByKey = OpenBSDProcess_compareByKey
};
bool Process_isThread(const Process* this) {
diff --git a/openbsd/OpenBSDProcess.h b/openbsd/OpenBSDProcess.h
index 2d01513..6aab29a 100644
--- a/openbsd/OpenBSDProcess.h
+++ b/openbsd/OpenBSDProcess.h
@@ -15,11 +15,6 @@ in the source distribution for its full text.
#include "Settings.h"
-typedef enum OpenBSDProcessFields_ {
- // Add platform-specific fields here, with ids >= 100
- LAST_PROCESSFIELD = 100,
-} OpenBSDProcessField;
-
typedef struct OpenBSDProcess_ {
Process super;
} OpenBSDProcess;
@@ -30,9 +25,7 @@ typedef struct OpenBSDProcess_ {
extern const ProcessClass OpenBSDProcess_class;
-extern ProcessFieldData Process_fields[];
-
-extern ProcessPidColumn Process_pidColumns[];
+extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
Process* OpenBSDProcess_new(const Settings* settings);
diff --git a/openbsd/OpenBSDProcessList.c b/openbsd/OpenBSDProcessList.c
index 5412030..ff5c927 100644
--- a/openbsd/OpenBSDProcessList.c
+++ b/openbsd/OpenBSDProcessList.c
@@ -8,7 +8,6 @@ in the source distribution for its full text.
#include "OpenBSDProcessList.h"
-#include <err.h>
#include <kvm.h>
#include <limits.h>
#include <stdlib.h>
@@ -34,6 +33,8 @@ in the source distribution for its full text.
static long fscale;
+static int pageSize;
+static int pageSizeKB;
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
const int mib[] = { CTL_HW, HW_NCPU };
@@ -55,9 +56,13 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
size = sizeof(fscale);
if (sysctl(fmib, 2, &fscale, &size, NULL, 0) < 0) {
- err(1, "fscale sysctl call failed");
+ CRT_fatalError("fscale sysctl call failed");
}
+ if ((pageSize = sysconf(_SC_PAGESIZE)) == -1)
+ CRT_fatalError("pagesize sysconf call failed");
+ pageSizeKB = pageSize / ONE_K;
+
for (int i = 0; i <= pl->cpuCount; i++) {
CPUData* d = opl->cpus + i;
d->totalTime = 1;
@@ -66,7 +71,7 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
opl->kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
if (opl->kd == NULL) {
- errx(1, "kvm_open: %s", errbuf);
+ CRT_fatalError("kvm_openfiles() failed");
}
return pl;
@@ -91,11 +96,11 @@ static void OpenBSDProcessList_scanMemoryInfo(ProcessList* pl) {
size_t size_uvmexp = sizeof(uvmexp);
if (sysctl(uvmexp_mib, 2, &uvmexp, &size_uvmexp, NULL, 0) < 0) {
- err(1, "uvmexp sysctl call failed");
+ CRT_fatalError("uvmexp sysctl call failed");
}
- pl->totalMem = uvmexp.npages * CRT_pageSizeKB;
- pl->usedMem = (uvmexp.npages - uvmexp.free - uvmexp.paging) * CRT_pageSizeKB;
+ pl->totalMem = uvmexp.npages * pageSizeKB;
+ pl->usedMem = (uvmexp.npages - uvmexp.free - uvmexp.paging) * pageSizeKB;
// Taken from OpenBSD systat/iostat.c, top/machine.c and uvm_sysctl(9)
const int bcache_mib[] = { CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT };
@@ -103,10 +108,10 @@ static void OpenBSDProcessList_scanMemoryInfo(ProcessList* pl) {
size_t size_bcstats = sizeof(bcstats);
if (sysctl(bcache_mib, 3, &bcstats, &size_bcstats, NULL, 0) < 0) {
- err(1, "cannot get vfs.bcachestat");
+ CRT_fatalError("cannot get vfs.bcachestat");
}
- pl->cachedMem = bcstats.numbufpages * CRT_pageSizeKB;
+ pl->cachedMem = bcstats.numbufpages * pageSizeKB;
/*
* Copyright (c) 1994 Thorsten Lockert <tholo@sigmasoft.com>
@@ -222,9 +227,9 @@ static void OpenBSDProcessList_scanProcs(OpenBSDProcessList* this) {
}
}
- proc->m_virt = kproc->p_vm_dsize;
- proc->m_resident = kproc->p_vm_rssize;
- proc->percent_mem = (proc->m_resident * CRT_pageSizeKB) / (double)(this->super.totalMem) * 100.0;
+ proc->m_virt = kproc->p_vm_dsize * pageSizeKB;
+ proc->m_resident = kproc->p_vm_rssize * pageSizeKB;
+ proc->percent_mem = proc->m_resident / (double)(this->super.totalMem) * 100.0;
proc->percent_cpu = CLAMP(getpcpu(kproc), 0.0, this->super.cpuCount * 100.0);
//proc->nlwp = kproc->p_numthreads;
proc->nice = kproc->p_nice - 20;
diff --git a/openbsd/Platform.c b/openbsd/Platform.c
index dae8072..8ee8141 100644
--- a/openbsd/Platform.c
+++ b/openbsd/Platform.c
@@ -42,9 +42,7 @@ in the source distribution for its full text.
#include "XUtils.h"
-ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
-
-int Platform_numberOfFields = LAST_PROCESSFIELD;
+const ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
/*
* See /usr/include/sys/signal.h
diff --git a/openbsd/Platform.h b/openbsd/Platform.h
index 0e2d435..e7a5966 100644
--- a/openbsd/Platform.h
+++ b/openbsd/Platform.h
@@ -20,11 +20,7 @@ in the source distribution for its full text.
#include "SignalsPanel.h"
-extern ProcessFieldData Process_fields[];
-
-extern ProcessField Platform_defaultFields[];
-
-extern int Platform_numberOfFields;
+extern const ProcessField Platform_defaultFields[];
/* see /usr/include/sys/signal.h */
extern const SignalItem Platform_signals[];
diff --git a/openbsd/ProcessField.h b/openbsd/ProcessField.h
new file mode 100644
index 0000000..be4e51e
--- /dev/null
+++ b/openbsd/ProcessField.h
@@ -0,0 +1,15 @@
+#ifndef HEADER_OpenBSDProcessField
+#define HEADER_OpenBSDProcessField
+/*
+htop - openbsd/ProcessField.h
+(C) 2020 htop dev team
+Released under the GNU GPLv2, see the COPYING file
+in the source distribution for its full text.
+*/
+
+
+#define PLATFORM_PROCESS_FIELDS \
+ // End of list
+
+
+#endif /* HEADER_OpenBSDProcessField */
diff --git a/solaris/Platform.c b/solaris/Platform.c
index 014eaf5..968e013 100644
--- a/solaris/Platform.c
+++ b/solaris/Platform.c
@@ -86,7 +86,7 @@ const SignalItem Platform_signals[] = {
const unsigned int Platform_numberOfSignals = ARRAYSIZE(Platform_signals);
-ProcessField Platform_defaultFields[] = { PID, LWPID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
+const ProcessField Platform_defaultFields[] = { PID, LWPID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
const MeterClass* const Platform_meterTypes[] = {
&CPUMeter_class,
@@ -119,10 +119,6 @@ const MeterClass* const Platform_meterTypes[] = {
NULL
};
-int Platform_numberOfFields = LAST_PROCESSFIELD;
-
-extern char Process_pidFormat[20];
-
void Platform_init(void) {
/* no platform-specific setup needed */
}
@@ -209,7 +205,7 @@ double Platform_setCPUValues(Meter* this, int cpu) {
percent = isnan(percent) ? 0.0 : CLAMP(percent, 0.0, 100.0);
- v[CPU_METER_FREQUENCY] = NAN;
+ v[CPU_METER_FREQUENCY] = cpuData->frequency;
v[CPU_METER_TEMPERATURE] = NAN;
return percent;
diff --git a/solaris/Platform.h b/solaris/Platform.h
index c338115..de2b2c9 100644
--- a/solaris/Platform.h
+++ b/solaris/Platform.h
@@ -25,7 +25,6 @@ in the source distribution for its full text.
#define kill(pid, signal) kill(pid / 1024, signal)
-extern ProcessFieldData Process_fields[];
typedef struct var kvar_t;
typedef struct envAccum_ {
@@ -41,14 +40,10 @@ extern const SignalItem Platform_signals[];
extern const unsigned int Platform_numberOfSignals;
-extern ProcessField Platform_defaultFields[];
+extern const ProcessField Platform_defaultFields[];
extern const MeterClass* const Platform_meterTypes[];
-extern int Platform_numberOfFields;
-
-extern char Process_pidFormat[20];
-
void Platform_init(void);
void Platform_done(void);
diff --git a/solaris/ProcessField.h b/solaris/ProcessField.h
new file mode 100644
index 0000000..eb9f157
--- /dev/null
+++ b/solaris/ProcessField.h
@@ -0,0 +1,22 @@
+#ifndef HEADER_SolarisProcessField
+#define HEADER_SolarisProcessField
+/*
+htop - solaris/ProcessField.h
+(C) 2020 htop dev team
+Released under the GNU GPLv2, see the COPYING file
+in the source distribution for its full text.
+*/
+
+
+#define PLATFORM_PROCESS_FIELDS \
+ ZONEID = 100, \
+ ZONE = 101, \
+ PROJID = 102, \
+ TASKID = 103, \
+ POOLID = 104, \
+ CONTID = 105, \
+ LWPID = 106, \
+ // End of list
+
+
+#endif /* HEADER_SolarisProcessField */
diff --git a/solaris/SolarisProcess.c b/solaris/SolarisProcess.c
index e0a3db2..d905f7a 100644
--- a/solaris/SolarisProcess.c
+++ b/solaris/SolarisProcess.c
@@ -18,26 +18,16 @@ in the source distribution for its full text.
#include <sys/syscall.h>
-const ProcessClass SolarisProcess_class = {
- .super = {
- .extends = Class(Process),
- .display = Process_display,
- .delete = Process_delete,
- .compare = SolarisProcess_compare
- },
- .writeField = SolarisProcess_writeField,
-};
-
-ProcessFieldData Process_fields[] = {
+const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
[0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
- [PID] = { .name = "PID", .title = " PID ", .description = "Process/thread ID", .flags = 0, },
+ [PID] = { .name = "PID", .title = "PID", .description = "Process/thread ID", .flags = 0, .pidColumn = true, },
[COMM] = { .name = "Command", .title = "Command ", .description = "Command line", .flags = 0, },
[STATE] = { .name = "STATE", .title = "S ", .description = "Process state (S sleeping, R running, O onproc, Z zombie, T stopped, W waiting)", .flags = 0, },
- [PPID] = { .name = "PPID", .title = " PPID ", .description = "Parent process ID", .flags = 0, },
- [PGRP] = { .name = "PGRP", .title = " PGRP ", .description = "Process group ID", .flags = 0, },
- [SESSION] = { .name = "SESSION", .title = " SID ", .description = "Process's session ID", .flags = 0, },
+ [PPID] = { .name = "PPID", .title = "PPID", .description = "Parent process ID", .flags = 0, .pidColumn = true, },
+ [PGRP] = { .name = "PGRP", .title = "PGRP", .description = "Process group ID", .flags = 0, .pidColumn = true, },
+ [SESSION] = { .name = "SESSION", .title = "SID", .description = "Process's session ID", .flags = 0, .pidColumn = true, },
[TTY_NR] = { .name = "TTY_NR", .title = " TTY ", .description = "Controlling terminal", .flags = 0, },
- [TPGID] = { .name = "TPGID", .title = " TPGID ", .description = "Process ID of the fg process group of the controlling terminal", .flags = 0, },
+ [TPGID] = { .name = "TPGID", .title = "TPGID", .description = "Process ID of the fg process group of the controlling terminal", .flags = 0, .pidColumn = true, },
[MINFLT] = { .name = "MINFLT", .title = " MINFLT ", .description = "Number of minor faults which have not required loading a memory page from disk", .flags = 0, },
[MAJFLT] = { .name = "MAJFLT", .title = " MAJFLT ", .description = "Number of major faults which have required loading a memory page from disk", .flags = 0, },
[PRIORITY] = { .name = "PRIORITY", .title = "PRI ", .description = "Kernel's internal priority for the process", .flags = 0, },
@@ -53,31 +43,14 @@ ProcessFieldData Process_fields[] = {
[USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
[TIME] = { .name = "TIME", .title = " TIME+ ", .description = "Total time the process has spent in user and system time", .flags = 0, },
[NLWP] = { .name = "NLWP", .title = "NLWP ", .description = "Number of threads in the process", .flags = 0, },
- [TGID] = { .name = "TGID", .title = " TGID ", .description = "Thread group ID (i.e. process ID)", .flags = 0, },
- [ZONEID] = { .name = "ZONEID", .title = " ZONEID ", .description = "Zone ID", .flags = 0, },
+ [TGID] = { .name = "TGID", .title = "TGID", .description = "Thread group ID (i.e. process ID)", .flags = 0, .pidColumn = true, },
+ [ZONEID] = { .name = "ZONEID", .title = "ZONEID", .description = "Zone ID", .flags = 0, .pidColumn = true, },
[ZONE] = { .name = "ZONE", .title = "ZONE ", .description = "Zone name", .flags = 0, },
- [PROJID] = { .name = "PROJID", .title = " PRJID ", .description = "Project ID", .flags = 0, },
- [TASKID] = { .name = "TASKID", .title = " TSKID ", .description = "Task ID", .flags = 0, },
- [POOLID] = { .name = "POOLID", .title = " POLID ", .description = "Pool ID", .flags = 0, },
- [CONTID] = { .name = "CONTID", .title = " CNTID ", .description = "Contract ID", .flags = 0, },
- [LWPID] = { .name = "LWPID", .title = " LWPID ", .description = "LWP ID", .flags = 0, },
- [LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
-};
-
-ProcessPidColumn Process_pidColumns[] = {
- { .id = ZONEID, .label = "ZONEID" },
- { .id = TASKID, .label = "TSKID" },
- { .id = PROJID, .label = "PRJID" },
- { .id = POOLID, .label = "POLID" },
- { .id = CONTID, .label = "CNTID" },
- { .id = PID, .label = "PID" },
- { .id = PPID, .label = "PPID" },
- { .id = LWPID, .label = "LWPID" },
- { .id = TPGID, .label = "TPGID" },
- { .id = TGID, .label = "TGID" },
- { .id = PGRP, .label = "PGRP" },
- { .id = SESSION, .label = "SID" },
- { .id = 0, .label = NULL },
+ [PROJID] = { .name = "PROJID", .title = "PRJID", .description = "Project ID", .flags = 0, .pidColumn = true, },
+ [TASKID] = { .name = "TASKID", .title = "TSKID", .description = "Task ID", .flags = 0, .pidColumn = true, },
+ [POOLID] = { .name = "POOLID", .title = "POLID", .description = "Pool ID", .flags = 0, .pidColumn = true, },
+ [CONTID] = { .name = "CONTID", .title = "CNTID", .description = "Contract ID", .flags = 0, .pidColumn = true, },
+ [LWPID] = { .name = "LWPID", .title = "LWPID", .description = "LWP ID", .flags = 0, .pidColumn = true, },
};
Process* SolarisProcess_new(const Settings* settings) {
@@ -94,42 +67,34 @@ void Process_delete(Object* cast) {
free(sp);
}
-void SolarisProcess_writeField(const Process* this, RichString* str, ProcessField field) {
+static void SolarisProcess_writeField(const Process* this, RichString* str, ProcessField field) {
const SolarisProcess* sp = (const SolarisProcess*) this;
char buffer[256]; buffer[255] = '\0';
int attr = CRT_colors[DEFAULT_COLOR];
int n = sizeof(buffer) - 1;
- switch ((int) field) {
+ switch (field) {
// add Solaris-specific fields here
- case ZONEID: xSnprintf(buffer, n, Process_pidFormat, sp->zoneid); break;
- case PROJID: xSnprintf(buffer, n, Process_pidFormat, sp->projid); break;
- case TASKID: xSnprintf(buffer, n, Process_pidFormat, sp->taskid); break;
- case POOLID: xSnprintf(buffer, n, Process_pidFormat, sp->poolid); break;
- case CONTID: xSnprintf(buffer, n, Process_pidFormat, sp->contid); break;
- case ZONE: xSnprintf(buffer, n, "%-*s ", ZONENAME_MAX/4, sp->zname); break;
- case PID: xSnprintf(buffer, n, Process_pidFormat, sp->realpid); break;
- case PPID: xSnprintf(buffer, n, Process_pidFormat, sp->realppid); break;
- case LWPID: xSnprintf(buffer, n, Process_pidFormat, sp->lwpid); break;
+ case ZONEID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->zoneid); break;
+ case PROJID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->projid); break;
+ case TASKID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->taskid); break;
+ case POOLID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->poolid); break;
+ case CONTID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->contid); break;
+ case ZONE: Process_printLeftAlignedField(str, attr, sp->zname ? sp->zname : "global", ZONENAME_MAX/4); return;
+ case PID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->realpid); break;
+ case PPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->realppid); break;
+ case LWPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->lwpid); break;
default:
Process_writeField(this, str, field);
return;
}
- RichString_append(str, attr, buffer);
+ RichString_appendWide(str, attr, buffer);
}
-long SolarisProcess_compare(const void* v1, const void* v2) {
- const SolarisProcess *p1, *p2;
- const Settings* settings = ((const Process*)v1)->settings;
+static int SolarisProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
+ const SolarisProcess* p1 = (const SolarisProcess*)v1;
+ const SolarisProcess* p2 = (const SolarisProcess*)v2;
- if (settings->direction == 1) {
- p1 = (const SolarisProcess*)v1;
- p2 = (const SolarisProcess*)v2;
- } else {
- p2 = (const SolarisProcess*)v1;
- p1 = (const SolarisProcess*)v2;
- }
-
- switch ((int) settings->sortKey) {
+ switch (key) {
case ZONEID:
return SPACESHIP_NUMBER(p1->zoneid, p2->zoneid);
case PROJID:
@@ -149,7 +114,7 @@ long SolarisProcess_compare(const void* v1, const void* v2) {
case LWPID:
return SPACESHIP_NUMBER(p1->lwpid, p2->lwpid);
default:
- return Process_compare(v1, v2);
+ return Process_compareByKey_Base(v1, v2, key);
}
}
@@ -164,3 +129,14 @@ bool Process_isThread(const Process* this) {
return 0;
}
}
+
+const ProcessClass SolarisProcess_class = {
+ .super = {
+ .extends = Class(Process),
+ .display = Process_display,
+ .delete = Process_delete,
+ .compare = Process_compare
+ },
+ .writeField = SolarisProcess_writeField,
+ .compareByKey = SolarisProcess_compareByKey
+};
diff --git a/solaris/SolarisProcess.h b/solaris/SolarisProcess.h
index 4756634..74cbb86 100644
--- a/solaris/SolarisProcess.h
+++ b/solaris/SolarisProcess.h
@@ -13,18 +13,6 @@ in the source distribution for its full text.
#include <sys/proc.h>
#include <libproc.h>
-typedef enum SolarisProcessField_ {
- // Add platform-specific fields here, with ids >= 100
- ZONEID = 100,
- ZONE = 101,
- PROJID = 102,
- TASKID = 103,
- POOLID = 104,
- CONTID = 105,
- LWPID = 106,
- LAST_PROCESSFIELD = 107,
-} SolarisProcessField;
-
typedef struct SolarisProcess_ {
Process super;
int kernel;
@@ -46,18 +34,12 @@ typedef struct SolarisProcess_ {
extern const ProcessClass SolarisProcess_class;
-extern ProcessFieldData Process_fields[];
-
-extern ProcessPidColumn Process_pidColumns[];
+extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
Process* SolarisProcess_new(const Settings* settings);
void Process_delete(Object* cast);
-void SolarisProcess_writeField(const Process* this, RichString* str, ProcessField field);
-
-long SolarisProcess_compare(const void* v1, const void* v2);
-
bool Process_isThread(const Process* this);
#endif
diff --git a/solaris/SolarisProcessList.c b/solaris/SolarisProcessList.c
index 4249fa6..2ba23ac 100644
--- a/solaris/SolarisProcessList.c
+++ b/solaris/SolarisProcessList.c
@@ -14,7 +14,6 @@ in the source distribution for its full text.
#include <stdlib.h>
#include <sys/types.h>
#include <sys/user.h>
-#include <err.h>
#include <limits.h>
#include <string.h>
#include <procfs.h>
@@ -25,9 +24,11 @@ in the source distribution for its full text.
#include "CRT.h"
-
#define MAXCMDLINE 255
+static int pageSize;
+static int pageSizeKB;
+
char* SolarisProcessList_readZoneName(kstat_ctl_t* kd, SolarisProcess* sproc) {
char* zname;
@@ -50,13 +51,18 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
spl->kd = kstat_open();
- pl->cpuCount = sysconf(_SC_NPROCESSORS_ONLN);
+ pageSize = sysconf(_SC_PAGESIZE);
+ if (pageSize == -1)
+ CRT_fatalError("Cannot get pagesize by sysconf(_SC_PAGESIZE)");
+ pageSizeKB = pageSize / 1024;
- if (pl->cpuCount == 1 ) {
+ pl->cpuCount = sysconf(_SC_NPROCESSORS_ONLN);
+ if (pl->cpuCount == -1)
+ CRT_fatalError("Cannot get CPU count by sysconf(_SC_NPROCESSORS_ONLN)");
+ else if (pl->cpuCount == 1)
spl->cpus = xRealloc(spl->cpus, sizeof(CPUData));
- } else {
+ else
spl->cpus = xRealloc(spl->cpus, (pl->cpuCount + 1) * sizeof(CPUData));
- }
return pl;
}
@@ -65,11 +71,11 @@ static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) {
const SolarisProcessList* spl = (SolarisProcessList*) pl;
int cpus = pl->cpuCount;
kstat_t* cpuinfo = NULL;
- int kchain = 0;
kstat_named_t* idletime = NULL;
kstat_named_t* intrtime = NULL;
kstat_named_t* krnltime = NULL;
kstat_named_t* usertime = NULL;
+ kstat_named_t* cpu_freq = NULL;
double idlebuf = 0;
double intrbuf = 0;
double krnlbuf = 0;
@@ -87,21 +93,31 @@ static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) {
// Calculate per-CPU statistics first
for (int i = 0; i < cpus; i++) {
if (spl->kd != NULL) {
- cpuinfo = kstat_lookup(spl->kd, "cpu", i, "sys");
- }
- if (cpuinfo != NULL) {
- kchain = kstat_read(spl->kd, cpuinfo, NULL);
- }
- if (kchain != -1 ) {
- idletime = kstat_data_lookup(cpuinfo, "cpu_nsec_idle");
- intrtime = kstat_data_lookup(cpuinfo, "cpu_nsec_intr");
- krnltime = kstat_data_lookup(cpuinfo, "cpu_nsec_kernel");
- usertime = kstat_data_lookup(cpuinfo, "cpu_nsec_user");
+ if ((cpuinfo = kstat_lookup(spl->kd, "cpu", i, "sys")) != NULL) {
+ if (kstat_read(spl->kd, cpuinfo, NULL) != -1) {
+ idletime = kstat_data_lookup(cpuinfo, "cpu_nsec_idle");
+ intrtime = kstat_data_lookup(cpuinfo, "cpu_nsec_intr");
+ krnltime = kstat_data_lookup(cpuinfo, "cpu_nsec_kernel");
+ usertime = kstat_data_lookup(cpuinfo, "cpu_nsec_user");
+ }
+ }
}
assert( (idletime != NULL) && (intrtime != NULL)
&& (krnltime != NULL) && (usertime != NULL) );
+ if (pl->settings->showCPUFrequency) {
+ if (spl->kd != NULL) {
+ if ((cpuinfo = kstat_lookup(spl->kd, "cpu_info", i, NULL)) != NULL) {
+ if (kstat_read(spl->kd, cpuinfo, NULL) != -1) {
+ cpu_freq = kstat_data_lookup(cpuinfo, "current_clock_Hz");
+ }
+ }
+ }
+
+ assert( cpu_freq != NULL );
+ }
+
CPUData* cpuData = &(spl->cpus[i + arrskip]);
uint64_t totaltime = (idletime->value.ui64 - cpuData->lidle)
@@ -121,6 +137,8 @@ static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) {
cpuData->lkrnl = krnltime->value.ui64;
cpuData->lintr = intrtime->value.ui64;
cpuData->lidle = idletime->value.ui64;
+ // Add frequency in MHz
+ cpuData->frequency = pl->settings->showCPUFrequency ? (double)cpu_freq->value.ui64 / 1E6 : NAN;
// Accumulate the current percentages into buffers for later average calculation
if (cpus > 1) {
userbuf += cpuData->userPercent;
@@ -158,8 +176,8 @@ static inline void SolarisProcessList_scanMemoryInfo(ProcessList* pl) {
// Part 1 - physical memory
if (spl->kd != NULL && meminfo == NULL) {
- // Look up the kstat chain just one, it never changes
- meminfo = kstat_lookup(spl->kd, "unix", 0, "system_pages");
+ // Look up the kstat chain just once, it never changes
+ meminfo = kstat_lookup(spl->kd, "unix", 0, "system_pages");
}
if (meminfo != NULL) {
ksrphyserr = kstat_read(spl->kd, meminfo, NULL);
@@ -169,9 +187,9 @@ static inline void SolarisProcessList_scanMemoryInfo(ProcessList* pl) {
freemem_pgs = kstat_data_lookup(meminfo, "freemem");
pages = kstat_data_lookup(meminfo, "pagestotal");
- pl->totalMem = totalmem_pgs->value.ui64 * CRT_pageSizeKB;
- if (pl->totalMem > freemem_pgs->value.ui64 * CRT_pageSizeKB) {
- pl->usedMem = pl->totalMem - freemem_pgs->value.ui64 * CRT_pageSizeKB;
+ pl->totalMem = totalmem_pgs->value.ui64 * pageSizeKB;
+ if (pl->totalMem > freemem_pgs->value.ui64 * pageSizeKB) {
+ pl->usedMem = pl->totalMem - freemem_pgs->value.ui64 * pageSizeKB;
} else {
pl->usedMem = 0; // This can happen in non-global zone (in theory)
}
@@ -179,13 +197,13 @@ static inline void SolarisProcessList_scanMemoryInfo(ProcessList* pl) {
pl->cachedMem = 0;
// Not really "buffers" but the best Solaris analogue that I can find to
// "memory in use but not by programs or the kernel itself"
- pl->buffersMem = (totalmem_pgs->value.ui64 - pages->value.ui64) * CRT_pageSizeKB;
+ pl->buffersMem = (totalmem_pgs->value.ui64 - pages->value.ui64) * pageSizeKB;
} else {
// Fall back to basic sysconf if kstat isn't working
- pl->totalMem = sysconf(_SC_PHYS_PAGES) * CRT_pageSize;
+ pl->totalMem = sysconf(_SC_PHYS_PAGES) * pageSize;
pl->buffersMem = 0;
pl->cachedMem = 0;
- pl->usedMem = pl->totalMem - (sysconf(_SC_AVPHYS_PAGES) * CRT_pageSize);
+ pl->usedMem = pl->totalMem - (sysconf(_SC_AVPHYS_PAGES) * pageSize);
}
// Part 2 - swap
@@ -215,8 +233,8 @@ static inline void SolarisProcessList_scanMemoryInfo(ProcessList* pl) {
}
free(spathbase);
free(sl);
- pl->totalSwap = totalswap * CRT_pageSizeKB;
- pl->usedSwap = pl->totalSwap - (totalfree * CRT_pageSizeKB);
+ pl->totalSwap = totalswap * pageSizeKB;
+ pl->usedSwap = pl->totalSwap - (totalfree * pageSizeKB);
}
static inline void SolarisProcessList_scanZfsArcstats(ProcessList* pl) {
@@ -323,8 +341,8 @@ int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo, void*
proc->pgrp = _psinfo->pr_pgid;
proc->nlwp = _psinfo->pr_nlwp;
proc->tty_nr = _psinfo->pr_ttydev;
- proc->m_resident = _psinfo->pr_rssize / CRT_pageSizeKB;
- proc->m_virt = _psinfo->pr_size / CRT_pageSizeKB;
+ proc->m_resident = _psinfo->pr_rssize; // KB
+ proc->m_virt = _psinfo->pr_size; // KB
if (!preExisting) {
sproc->realpid = _psinfo->pr_pid;
diff --git a/solaris/SolarisProcessList.h b/solaris/SolarisProcessList.h
index f800d9d..78362b6 100644
--- a/solaris/SolarisProcessList.h
+++ b/solaris/SolarisProcessList.h
@@ -33,6 +33,7 @@ typedef struct CPUData_ {
double irqPercent;
double idlePercent;
double systemAllPercent;
+ double frequency;
uint64_t luser;
uint64_t lkrnl;
uint64_t lintr;
diff --git a/unsupported/Platform.c b/unsupported/Platform.c
index 54fde50..94e1b7c 100644
--- a/unsupported/Platform.c
+++ b/unsupported/Platform.c
@@ -28,36 +28,7 @@ const SignalItem Platform_signals[] = {
const unsigned int Platform_numberOfSignals = ARRAYSIZE(Platform_signals);
-ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
-
-ProcessFieldData Process_fields[] = {
- [0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
- [PID] = { .name = "PID", .title = " PID ", .description = "Process/thread ID", .flags = 0, },
- [COMM] = { .name = "Command", .title = "Command ", .description = "Command line", .flags = 0, },
- [STATE] = { .name = "STATE", .title = "S ", .description = "Process state (S sleeping, R running, D disk, Z zombie, T traced, W paging)", .flags = 0, },
- [PPID] = { .name = "PPID", .title = " PPID ", .description = "Parent process ID", .flags = 0, },
- [PGRP] = { .name = "PGRP", .title = " PGRP ", .description = "Process group ID", .flags = 0, },
- [SESSION] = { .name = "SESSION", .title = " SID ", .description = "Process's session ID", .flags = 0, },
- [TTY_NR] = { .name = "TTY_NR", .title = " TTY ", .description = "Controlling terminal", .flags = 0, },
- [TPGID] = { .name = "TPGID", .title = " TPGID ", .description = "Process ID of the fg process group of the controlling terminal", .flags = 0, },
- [MINFLT] = { .name = "MINFLT", .title = " MINFLT ", .description = "Number of minor faults which have not required loading a memory page from disk", .flags = 0, },
- [MAJFLT] = { .name = "MAJFLT", .title = " MAJFLT ", .description = "Number of major faults which have required loading a memory page from disk", .flags = 0, },
- [PRIORITY] = { .name = "PRIORITY", .title = "PRI ", .description = "Kernel's internal priority for the process", .flags = 0, },
- [NICE] = { .name = "NICE", .title = " NI ", .description = "Nice value (the higher the value, the more it lets other processes take priority)", .flags = 0, },
- [STARTTIME] = { .name = "STARTTIME", .title = "START ", .description = "Time the process was started", .flags = 0, },
-
- [PROCESSOR] = { .name = "PROCESSOR", .title = "CPU ", .description = "Id of the CPU the process last executed on", .flags = 0, },
- [M_VIRT] = { .name = "M_VIRT", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, },
- [M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, },
- [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
- [PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, },
- [PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, },
- [USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
- [TIME] = { .name = "TIME", .title = " TIME+ ", .description = "Total time the process has spent in user and system time", .flags = 0, },
- [NLWP] = { .name = "NLWP", .title = "NLWP ", .description = "Number of threads in the process", .flags = 0, },
- [TGID] = { .name = "TGID", .title = " TGID ", .description = "Thread group ID (i.e. process ID)", .flags = 0, },
- [100] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
-};
+const ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
const MeterClass* const Platform_meterTypes[] = {
&CPUMeter_class,
@@ -88,12 +59,6 @@ const MeterClass* const Platform_meterTypes[] = {
NULL
};
-int Platform_numberOfFields = 100;
-
-ProcessPidColumn Process_pidColumns[] = {
- { .id = 0, .label = NULL },
-};
-
void Platform_init(void) {
/* no platform-specific setup needed */
}
diff --git a/unsupported/Platform.h b/unsupported/Platform.h
index d3f5d72..4254122 100644
--- a/unsupported/Platform.h
+++ b/unsupported/Platform.h
@@ -19,18 +19,10 @@ extern const SignalItem Platform_signals[];
extern const unsigned int Platform_numberOfSignals;
-extern ProcessField Platform_defaultFields[];
-
-extern ProcessFieldData Process_fields[];
+extern const ProcessField Platform_defaultFields[];
extern const MeterClass* const Platform_meterTypes[];
-extern int Platform_numberOfFields;
-
-extern char Process_pidFormat[20];
-
-extern ProcessPidColumn Process_pidColumns[];
-
void Platform_init(void);
void Platform_done(void);
diff --git a/unsupported/ProcessField.h b/unsupported/ProcessField.h
new file mode 100644
index 0000000..8c07107
--- /dev/null
+++ b/unsupported/ProcessField.h
@@ -0,0 +1,15 @@
+#ifndef HEADER_UnsupportedProcessField
+#define HEADER_UnsupportedProcessField
+/*
+htop - unsupported/ProcessField.h
+(C) 2020 htop dev team
+Released under the GNU GPLv2, see the COPYING file
+in the source distribution for its full text.
+*/
+
+
+#define PLATFORM_PROCESS_FIELDS \
+ // End of list
+
+
+#endif /* HEADER_UnsupportedProcessField */
diff --git a/unsupported/UnsupportedProcess.c b/unsupported/UnsupportedProcess.c
index 0827c60..eb52910 100644
--- a/unsupported/UnsupportedProcess.c
+++ b/unsupported/UnsupportedProcess.c
@@ -9,6 +9,33 @@ in the source distribution for its full text.
#include "UnsupportedProcess.h"
#include <stdlib.h>
+const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
+ [0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
+ [PID] = { .name = "PID", .title = "PID", .description = "Process/thread ID", .flags = 0, .pidColumn = true, },
+ [COMM] = { .name = "Command", .title = "Command ", .description = "Command line", .flags = 0, },
+ [STATE] = { .name = "STATE", .title = "S ", .description = "Process state (S sleeping, R running, D disk, Z zombie, T traced, W paging)", .flags = 0, },
+ [PPID] = { .name = "PPID", .title = "PPID", .description = "Parent process ID", .flags = 0, .pidColumn = true, },
+ [PGRP] = { .name = "PGRP", .title = "PGRP", .description = "Process group ID", .flags = 0, .pidColumn = true, },
+ [SESSION] = { .name = "SESSION", .title = "SID", .description = "Process's session ID", .flags = 0, .pidColumn = true, },
+ [TTY_NR] = { .name = "TTY_NR", .title = " TTY ", .description = "Controlling terminal", .flags = 0, },
+ [TPGID] = { .name = "TPGID", .title = "TPGID", .description = "Process ID of the fg process group of the controlling terminal", .flags = 0, .pidColumn = true, },
+ [MINFLT] = { .name = "MINFLT", .title = " MINFLT ", .description = "Number of minor faults which have not required loading a memory page from disk", .flags = 0, },
+ [MAJFLT] = { .name = "MAJFLT", .title = " MAJFLT ", .description = "Number of major faults which have required loading a memory page from disk", .flags = 0, },
+ [PRIORITY] = { .name = "PRIORITY", .title = "PRI ", .description = "Kernel's internal priority for the process", .flags = 0, },
+ [NICE] = { .name = "NICE", .title = " NI ", .description = "Nice value (the higher the value, the more it lets other processes take priority)", .flags = 0, },
+ [STARTTIME] = { .name = "STARTTIME", .title = "START ", .description = "Time the process was started", .flags = 0, },
+
+ [PROCESSOR] = { .name = "PROCESSOR", .title = "CPU ", .description = "Id of the CPU the process last executed on", .flags = 0, },
+ [M_VIRT] = { .name = "M_VIRT", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, },
+ [M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, },
+ [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
+ [PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, },
+ [PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, },
+ [USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
+ [TIME] = { .name = "TIME", .title = " TIME+ ", .description = "Total time the process has spent in user and system time", .flags = 0, },
+ [NLWP] = { .name = "NLWP", .title = "NLWP ", .description = "Number of threads in the process", .flags = 0, },
+ [TGID] = { .name = "TGID", .title = "TGID", .description = "Thread group ID (i.e. process ID)", .flags = 0, .pidColumn = true, },
+};
Process* UnsupportedProcess_new(Settings* settings) {
Process* this = xCalloc(1, sizeof(Process));
diff --git a/unsupported/UnsupportedProcess.h b/unsupported/UnsupportedProcess.h
index 11335cd..e1812f1 100644
--- a/unsupported/UnsupportedProcess.h
+++ b/unsupported/UnsupportedProcess.h
@@ -11,6 +11,8 @@ in the source distribution for its full text.
#define Process_delete UnsupportedProcess_delete
+extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
+
Process* UnsupportedProcess_new(Settings* settings);
void UnsupportedProcess_delete(Object* cast);
diff --git a/zfs/ZfsArcMeter.c b/zfs/ZfsArcMeter.c
index e844d77..91dfc71 100644
--- a/zfs/ZfsArcMeter.c
+++ b/zfs/ZfsArcMeter.c
@@ -50,29 +50,29 @@ static void ZfsArcMeter_display(const Object* cast, RichString* out) {
if (this->values[5] > 0) {
char buffer[50];
- Meter_humanUnit(buffer, this->total, 50);
- RichString_append(out, CRT_colors[METER_VALUE], buffer);
- Meter_humanUnit(buffer, this->values[5], 50);
- RichString_append(out, CRT_colors[METER_TEXT], " Used:");
- RichString_append(out, CRT_colors[METER_VALUE], buffer);
- Meter_humanUnit(buffer, this->values[0], 50);
- RichString_append(out, CRT_colors[METER_TEXT], " MFU:");
- RichString_append(out, CRT_colors[ZFS_MFU], buffer);
- Meter_humanUnit(buffer, this->values[1], 50);
- RichString_append(out, CRT_colors[METER_TEXT], " MRU:");
- RichString_append(out, CRT_colors[ZFS_MRU], buffer);
- Meter_humanUnit(buffer, this->values[2], 50);
- RichString_append(out, CRT_colors[METER_TEXT], " Anon:");
- RichString_append(out, CRT_colors[ZFS_ANON], buffer);
- Meter_humanUnit(buffer, this->values[3], 50);
- RichString_append(out, CRT_colors[METER_TEXT], " Hdr:");
- RichString_append(out, CRT_colors[ZFS_HEADER], buffer);
- Meter_humanUnit(buffer, this->values[4], 50);
- RichString_append(out, CRT_colors[METER_TEXT], " Oth:");
- RichString_append(out, CRT_colors[ZFS_OTHER], buffer);
+ Meter_humanUnit(buffer, this->total, sizeof(buffer));
+ RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
+ Meter_humanUnit(buffer, this->values[5], sizeof(buffer));
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " Used:");
+ RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
+ Meter_humanUnit(buffer, this->values[0], sizeof(buffer));
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " MFU:");
+ RichString_appendAscii(out, CRT_colors[ZFS_MFU], buffer);
+ Meter_humanUnit(buffer, this->values[1], sizeof(buffer));
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " MRU:");
+ RichString_appendAscii(out, CRT_colors[ZFS_MRU], buffer);
+ Meter_humanUnit(buffer, this->values[2], sizeof(buffer));
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " Anon:");
+ RichString_appendAscii(out, CRT_colors[ZFS_ANON], buffer);
+ Meter_humanUnit(buffer, this->values[3], sizeof(buffer));
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " Hdr:");
+ RichString_appendAscii(out, CRT_colors[ZFS_HEADER], buffer);
+ Meter_humanUnit(buffer, this->values[4], sizeof(buffer));
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " Oth:");
+ RichString_appendAscii(out, CRT_colors[ZFS_OTHER], buffer);
} else {
- RichString_write(out, CRT_colors[METER_TEXT], " ");
- RichString_append(out, CRT_colors[FAILED_SEARCH], "Unavailable");
+ RichString_writeAscii(out, CRT_colors[METER_TEXT], " ");
+ RichString_appendAscii(out, CRT_colors[FAILED_SEARCH], "Unavailable");
}
}
diff --git a/zfs/ZfsCompressedArcMeter.c b/zfs/ZfsCompressedArcMeter.c
index 8766f80..92d82e9 100644
--- a/zfs/ZfsCompressedArcMeter.c
+++ b/zfs/ZfsCompressedArcMeter.c
@@ -47,18 +47,18 @@ static void ZfsCompressedArcMeter_display(const Object* cast, RichString* out) {
if (this->values[0] > 0) {
char buffer[50];
- Meter_humanUnit(buffer, this->total, 50);
- RichString_append(out, CRT_colors[METER_VALUE], buffer);
- RichString_append(out, CRT_colors[METER_TEXT], " Uncompressed, ");
- Meter_humanUnit(buffer, this->values[0], 50);
- RichString_append(out, CRT_colors[METER_VALUE], buffer);
- RichString_append(out, CRT_colors[METER_TEXT], " Compressed, ");
- ZfsCompressedArcMeter_printRatioString(this, buffer, 50);
- RichString_append(out, CRT_colors[METER_VALUE], buffer);
- RichString_append(out, CRT_colors[METER_TEXT], " Ratio");
+ Meter_humanUnit(buffer, this->total, sizeof(buffer));
+ RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " Uncompressed, ");
+ Meter_humanUnit(buffer, this->values[0], sizeof(buffer));
+ RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " Compressed, ");
+ ZfsCompressedArcMeter_printRatioString(this, buffer, sizeof(buffer));
+ RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
+ RichString_appendAscii(out, CRT_colors[METER_TEXT], " Ratio");
} else {
- RichString_write(out, CRT_colors[METER_TEXT], " ");
- RichString_append(out, CRT_colors[FAILED_SEARCH], "Compression Unavailable");
+ RichString_writeAscii(out, CRT_colors[METER_TEXT], " ");
+ RichString_appendAscii(out, CRT_colors[FAILED_SEARCH], "Compression Unavailable");
}
}

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