mirror of
https://github.com/xzeldon/htop.git
synced 2025-07-15 21:44:36 +03:00
Compare commits
148 Commits
Author | SHA1 | Date | |
---|---|---|---|
ce6d60e7de | |||
5d92a9f20d | |||
b3500ac3b7 | |||
2ba8a81d47 | |||
f2f1c99ad9 | |||
1ffe5d79bd | |||
8502f4e64f | |||
a5db139a0a | |||
8a67d7f086 | |||
0b89c66f58 | |||
3bb731c645 | |||
fbaa0cd146 | |||
a076488809 | |||
6301d5c1da | |||
4979245aa5 | |||
0155980fd6 | |||
2af90b711f | |||
d55f394541 | |||
c7d93a8f30 | |||
2d2a2df6f2 | |||
de645ea16c | |||
6ae56f2578 | |||
bfcb8ca019 | |||
d800d7a3ce | |||
27db9297b7 | |||
330d4fe22f | |||
8e10cde800 | |||
ca2c01bd16 | |||
7043a93eba | |||
8fe04b7494 | |||
43d5c61884 | |||
e103ec0317 | |||
7ff654f2df | |||
7386c6fed0 | |||
ce9e7fd14f | |||
badeaf9e82 | |||
a3cced9fb6 | |||
24c5ca9ddf | |||
eb6f8d569d | |||
8c8149d146 | |||
a150a81669 | |||
90ea3ac3c9 | |||
293c16e22d | |||
f6aa5d29bb | |||
2c06566405 | |||
d609c04fe4 | |||
ca9d7cd708 | |||
debeac49cd | |||
a0b899f29d | |||
8b83a9f055 | |||
495f2292dc | |||
1cc3f8074f | |||
aa08279964 | |||
5359eae28b | |||
f1463fdd64 | |||
3edb6e1ea3 | |||
71ddc6a6a1 | |||
b9336af76f | |||
f46ddd3230 | |||
94d7f0b585 | |||
86d2931255 | |||
0672be7db1 | |||
0b989ee38c | |||
3fb0024fd3 | |||
dfb9b82607 | |||
fc7aead36b | |||
737cd6167a | |||
6502b02666 | |||
cdfd407e2e | |||
64c05a1ed5 | |||
a7612b0b7d | |||
3ec8f67ab2 | |||
10c6810bff | |||
068561351f | |||
9b8b380c32 | |||
a09ad6b8b4 | |||
9a86577cf2 | |||
8db8b9edac | |||
4a73e80338 | |||
5fa1c7040d | |||
3f9c63d5c0 | |||
358d20687f | |||
e3862aa67e | |||
7e7a53c415 | |||
6b100b0cf4 | |||
6e46fd6f1f | |||
22da57d621 | |||
c5e31ba4aa | |||
f878f302ca | |||
67ccd6b909 | |||
f614b8a19f | |||
c150e4bde9 | |||
9f68c8d341 | |||
89473cc9ae | |||
d872e36308 | |||
77db240b48 | |||
2327260ee8 | |||
e8c6994f40 | |||
3d1703f16f | |||
52fa4e7ee4 | |||
27b8d81ed2 | |||
26993d2d2b | |||
0401df8cbd | |||
0cb257586a | |||
1193c6e349 | |||
edd6130be7 | |||
107e3c8aa5 | |||
4eeeb63647 | |||
eb36385a6b | |||
79970f05f3 | |||
61b8e31b41 | |||
c9583c692d | |||
4507911cc3 | |||
b7836515e8 | |||
a3db2da4a7 | |||
cf982f2928 | |||
8d69a9a53e | |||
366b78edd9 | |||
f8a610e6e1 | |||
4b1a4a4ebd | |||
3655b6ca0b | |||
1506283aff | |||
4b877eb16a | |||
f32f0188cd | |||
e65cdf947c | |||
ab60f59ed8 | |||
8149823d56 | |||
12421f460a | |||
880eecabf5 | |||
738d31b903 | |||
28bc087d8a | |||
2700d99069 | |||
75e9f9a8d9 | |||
db5687a355 | |||
7b739b6292 | |||
ded9c5d363 | |||
2d231d77ca | |||
f6613db5cd | |||
4c44a70f96 | |||
157086e750 | |||
5506925b34 | |||
c6d9fa279b | |||
dcf7ad386c | |||
30bf212185 | |||
05969998c1 | |||
ead978bce6 | |||
4f88d38256 | |||
f03f48a0fb |
26
.github/workflows/ci.yml
vendored
26
.github/workflows/ci.yml
vendored
@ -2,6 +2,11 @@ name: CI
|
|||||||
|
|
||||||
on: [ push, pull_request ]
|
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:
|
jobs:
|
||||||
build-ubuntu-latest-minimal-gcc:
|
build-ubuntu-latest-minimal-gcc:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -47,6 +52,10 @@ jobs:
|
|||||||
|
|
||||||
build-ubuntu-latest-full-featured-gcc:
|
build-ubuntu-latest-full-featured-gcc:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
# Enable LTO, might trigger additional warnings on advanced inlining
|
||||||
|
env:
|
||||||
|
CFLAGS: -O3 -g -flto
|
||||||
|
LDFLAGS: -O3 -g -flto
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
@ -102,6 +111,23 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: scan-build-11 -analyze-headers --status-bugs make -j"$(nproc)"
|
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:
|
whitespace_check:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
11
.travis.yml
11
.travis.yml
@ -6,17 +6,6 @@ compiler:
|
|||||||
|
|
||||||
os:
|
os:
|
||||||
- freebsd
|
- 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:
|
script:
|
||||||
- ./autogen.sh
|
- ./autogen.sh
|
||||||
|
158
Action.c
158
Action.c
@ -104,7 +104,7 @@ static bool changePriority(MainPanel* panel, int delta) {
|
|||||||
return anyTagged;
|
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;
|
const char* user = userCast;
|
||||||
Panel* panel = panelCast;
|
Panel* panel = panelCast;
|
||||||
Panel_add(panel, (Object*) ListItem_new(user, key));
|
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) {
|
Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey) {
|
||||||
settings->sortKey = sortKey;
|
Settings_setSortKey(settings, sortKey);
|
||||||
settings->direction = 1;
|
|
||||||
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_UPDATE_PANELHDR | HTOP_KEEP_FOLLOWING;
|
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;
|
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");
|
Panel_setHeader(sortPanel, "Sort by");
|
||||||
ProcessField* fields = st->settings->fields;
|
ProcessField* fields = st->settings->fields;
|
||||||
for (int i = 0; fields[i]; i++) {
|
for (int i = 0; fields[i]; i++) {
|
||||||
char* name = String_trim(Process_fields[fields[i]].name);
|
char* name = String_trim(Process_fields[fields[i]].name);
|
||||||
Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i]));
|
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);
|
Panel_setSelected(sortPanel, i);
|
||||||
|
|
||||||
free(name);
|
free(name);
|
||||||
@ -188,12 +189,8 @@ static Htop_Reaction sortBy(State* st) {
|
|||||||
return reaction | HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
|
return reaction | HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------
|
static Htop_Reaction actionSortByPID(State* st) {
|
||||||
|
return Action_setSortKey(st->settings, PID);
|
||||||
static Htop_Reaction actionResize(State* st) {
|
|
||||||
clear();
|
|
||||||
Panel_resize(st->panel, COLS, LINES - (st->panel->y) - 1);
|
|
||||||
return HTOP_REDRAW_BAR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Htop_Reaction actionSortByMemory(State* st) {
|
static Htop_Reaction actionSortByMemory(State* st) {
|
||||||
@ -231,7 +228,7 @@ static Htop_Reaction actionToggleMergedCommand(State* st) {
|
|||||||
static Htop_Reaction actionToggleTreeView(State* st) {
|
static Htop_Reaction actionToggleTreeView(State* st) {
|
||||||
st->settings->treeView = !st->settings->treeView;
|
st->settings->treeView = !st->settings->treeView;
|
||||||
if (st->settings->treeView) {
|
if (st->settings->treeView) {
|
||||||
st->settings->direction = 1;
|
st->settings->treeDirection = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessList_expandTree(st->pl);
|
ProcessList_expandTree(st->pl);
|
||||||
@ -251,16 +248,6 @@ static Htop_Reaction actionIncSearch(State* st) {
|
|||||||
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
|
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) {
|
static Htop_Reaction actionHigherPriority(State* st) {
|
||||||
bool changed = changePriority((MainPanel*)st->panel, -1);
|
bool changed = changePriority((MainPanel*)st->panel, -1);
|
||||||
return changed ? HTOP_REFRESH : HTOP_OK;
|
return changed ? HTOP_REFRESH : HTOP_OK;
|
||||||
@ -273,13 +260,11 @@ static Htop_Reaction actionLowerPriority(State* st) {
|
|||||||
|
|
||||||
static Htop_Reaction actionInvertSortOrder(State* st) {
|
static Htop_Reaction actionInvertSortOrder(State* st) {
|
||||||
Settings_invertSortOrder(st->settings);
|
Settings_invertSortOrder(st->settings);
|
||||||
|
if (st->pauseProcessUpdate)
|
||||||
|
ProcessList_sort(st->pl);
|
||||||
return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
|
return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Htop_Reaction actionSetSortColumn(State* st) {
|
|
||||||
return sortBy(st);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Htop_Reaction actionExpandOrCollapse(State* st) {
|
static Htop_Reaction actionExpandOrCollapse(State* st) {
|
||||||
bool changed = expandCollapse(st->panel);
|
bool changed = expandCollapse(st->panel);
|
||||||
return changed ? HTOP_RECALCULATE : HTOP_OK;
|
return changed ? HTOP_RECALCULATE : HTOP_OK;
|
||||||
@ -340,7 +325,7 @@ static Htop_Reaction actionKill(State* st) {
|
|||||||
if (sgn) {
|
if (sgn) {
|
||||||
if (sgn->key != 0) {
|
if (sgn->key != 0) {
|
||||||
Panel_setHeader(st->panel, "Sending...");
|
Panel_setHeader(st->panel, "Sending...");
|
||||||
Panel_draw(st->panel, true, true);
|
Panel_draw(st->panel, false, true, true, State_hideFunctionBar(st));
|
||||||
refresh();
|
refresh();
|
||||||
MainPanel_foreachProcess((MainPanel*)st->panel, Process_sendSignal, (Arg) { .i = sgn->key }, NULL);
|
MainPanel_foreachProcess((MainPanel*)st->panel, Process_sendSignal, (Arg) { .i = sgn->key }, NULL);
|
||||||
napms(500);
|
napms(500);
|
||||||
@ -351,7 +336,7 @@ static Htop_Reaction actionKill(State* st) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Htop_Reaction actionFilterByUser(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:");
|
Panel_setHeader(usersPanel, "Show processes of:");
|
||||||
UsersTable_foreach(st->ut, addUserToVector, usersPanel);
|
UsersTable_foreach(st->ut, addUserToVector, usersPanel);
|
||||||
Vector_insertionSort(usersPanel->items);
|
Vector_insertionSort(usersPanel->items);
|
||||||
@ -371,7 +356,7 @@ static Htop_Reaction actionFilterByUser(State* st) {
|
|||||||
|
|
||||||
Htop_Reaction Action_follow(State* st) {
|
Htop_Reaction Action_follow(State* st) {
|
||||||
st->pl->following = MainPanel_selectedPid((MainPanel*)st->panel);
|
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;
|
return HTOP_KEEP_FOLLOWING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,8 +445,8 @@ static const struct {
|
|||||||
{ .key = " H: ", .info = "hide/show user process threads" },
|
{ .key = " H: ", .info = "hide/show user process threads" },
|
||||||
{ .key = " K: ", .info = "hide/show kernel threads" },
|
{ .key = " K: ", .info = "hide/show kernel threads" },
|
||||||
{ .key = " F: ", .info = "cursor follows process" },
|
{ .key = " F: ", .info = "cursor follows process" },
|
||||||
{ .key = " F6 + -: ", .info = "expand/collapse tree" },
|
{ .key = " + -: ", .info = "expand/collapse tree" },
|
||||||
{ .key = " P M T: ", .info = "sort by CPU%, MEM% or TIME" },
|
{ .key = "N P M T: ", .info = "sort by PID, CPU%, MEM% or TIME" },
|
||||||
{ .key = " I: ", .info = "invert sort order" },
|
{ .key = " I: ", .info = "invert sort order" },
|
||||||
{ .key = " F6 > .: ", .info = "select sort column" },
|
{ .key = " F6 > .: ", .info = "select sort column" },
|
||||||
{ .key = NULL, .info = NULL }
|
{ .key = NULL, .info = NULL }
|
||||||
@ -562,24 +547,24 @@ static Htop_Reaction actionHelp(State* st) {
|
|||||||
int item;
|
int item;
|
||||||
for (item = 0; helpLeft[item].key; item++) {
|
for (item = 0; helpLeft[item].key; item++) {
|
||||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||||
mvaddstr(line + item, 9, helpLeft[item].info);
|
mvaddstr(line + item, 10, helpLeft[item].info);
|
||||||
attrset(CRT_colors[HELP_BOLD]);
|
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: ")) {
|
if (String_eq(helpLeft[item].key, " H: ")) {
|
||||||
attrset(CRT_colors[PROCESS_THREAD]);
|
attrset(CRT_colors[PROCESS_THREAD]);
|
||||||
mvaddstr(line + item, 32, "threads");
|
mvaddstr(line + item, 33, "threads");
|
||||||
} else if (String_eq(helpLeft[item].key, " K: ")) {
|
} else if (String_eq(helpLeft[item].key, " K: ")) {
|
||||||
attrset(CRT_colors[PROCESS_THREAD]);
|
attrset(CRT_colors[PROCESS_THREAD]);
|
||||||
mvaddstr(line + item, 26, "threads");
|
mvaddstr(line + item, 27, "threads");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int leftHelpItems = item;
|
int leftHelpItems = item;
|
||||||
|
|
||||||
for (item = 0; helpRight[item].key; item++) {
|
for (item = 0; helpRight[item].key; item++) {
|
||||||
attrset(CRT_colors[HELP_BOLD]);
|
attrset(CRT_colors[HELP_BOLD]);
|
||||||
mvaddstr(line + item, 40, helpRight[item].key);
|
mvaddstr(line + item, 41, helpRight[item].key);
|
||||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||||
mvaddstr(line + item, 49, helpRight[item].info);
|
mvaddstr(line + item, 50, helpRight[item].info);
|
||||||
}
|
}
|
||||||
line += MAXIMUM(leftHelpItems, item);
|
line += MAXIMUM(leftHelpItems, item);
|
||||||
line++;
|
line++;
|
||||||
@ -638,60 +623,57 @@ static Htop_Reaction actionShowCommandScreen(State* st) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Action_setBindings(Htop_Action* keys) {
|
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[','] = actionSetSortColumn;
|
|
||||||
keys['>'] = actionSetSortColumn;
|
|
||||||
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['='] = actionExpandOrCollapse;
|
|
||||||
keys['-'] = actionExpandOrCollapse;
|
|
||||||
keys['\177'] = actionCollapseIntoParent;
|
|
||||||
keys['u'] = actionFilterByUser;
|
|
||||||
keys['F'] = Action_follow;
|
|
||||||
keys['S'] = actionSetup;
|
|
||||||
keys['C'] = actionSetup;
|
|
||||||
keys[KEY_F(2)] = actionSetup;
|
|
||||||
keys['x'] = actionShowLocks;
|
|
||||||
keys['l'] = actionLsof;
|
|
||||||
keys['s'] = actionStrace;
|
|
||||||
keys[' '] = actionTag;
|
keys[' '] = actionTag;
|
||||||
keys['\014'] = actionRedraw; // Ctrl+L
|
keys['+'] = actionExpandOrCollapse;
|
||||||
keys[KEY_F(1)] = actionHelp;
|
keys[','] = actionSetSortColumn;
|
||||||
keys['h'] = actionHelp;
|
keys['-'] = actionExpandOrCollapse;
|
||||||
|
keys['.'] = actionSetSortColumn;
|
||||||
|
keys['/'] = actionIncSearch;
|
||||||
|
keys['<'] = actionSetSortColumn;
|
||||||
|
keys['='] = actionExpandOrCollapse;
|
||||||
|
keys['>'] = actionSetSortColumn;
|
||||||
keys['?'] = actionHelp;
|
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['T'] = actionSortByTime;
|
||||||
keys['U'] = actionUntagAll;
|
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['c'] = actionTagAllChildren;
|
||||||
keys['e'] = actionShowEnvScreen;
|
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['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;
|
||||||
}
|
}
|
||||||
|
4
Action.h
4
Action.h
@ -41,6 +41,10 @@ typedef struct State_ {
|
|||||||
bool hideProcessSelection;
|
bool hideProcessSelection;
|
||||||
} State;
|
} 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);
|
typedef Htop_Reaction (*Htop_Action)(State* st);
|
||||||
|
|
||||||
Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess);
|
Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess);
|
||||||
|
@ -59,25 +59,25 @@ static void MaskItem_delete(Object* cast) {
|
|||||||
static void MaskItem_display(const Object* cast, RichString* out) {
|
static void MaskItem_display(const Object* cast, RichString* out) {
|
||||||
const MaskItem* this = (const MaskItem*)cast;
|
const MaskItem* this = (const MaskItem*)cast;
|
||||||
assert (this != NULL);
|
assert (this != NULL);
|
||||||
RichString_append(out, CRT_colors[CHECK_BOX], "[");
|
RichString_appendAscii(out, CRT_colors[CHECK_BOX], "[");
|
||||||
if (this->value == 2) {
|
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) {
|
} else if (this->value == 1) {
|
||||||
RichString_append(out, CRT_colors[CHECK_MARK], "o");
|
RichString_appendAscii(out, CRT_colors[CHECK_MARK], "o");
|
||||||
} else {
|
} else {
|
||||||
RichString_append(out, CRT_colors[CHECK_MARK], " ");
|
RichString_appendAscii(out, CRT_colors[CHECK_MARK], " ");
|
||||||
}
|
}
|
||||||
RichString_append(out, CRT_colors[CHECK_BOX], "]");
|
RichString_appendAscii(out, CRT_colors[CHECK_BOX], "]");
|
||||||
RichString_append(out, CRT_colors[CHECK_TEXT], " ");
|
RichString_appendAscii(out, CRT_colors[CHECK_TEXT], " ");
|
||||||
if (this->indent) {
|
if (this->indent) {
|
||||||
RichString_append(out, CRT_colors[PROCESS_TREE], this->indent);
|
RichString_appendWide(out, CRT_colors[PROCESS_TREE], this->indent);
|
||||||
RichString_append(out, CRT_colors[PROCESS_TREE],
|
RichString_appendWide(out, CRT_colors[PROCESS_TREE],
|
||||||
this->sub_tree == 2
|
this->sub_tree == 2
|
||||||
? CRT_treeStr[TREE_STR_OPEN]
|
? CRT_treeStr[TREE_STR_OPEN]
|
||||||
: CRT_treeStr[TREE_STR_SHUT]);
|
: CRT_treeStr[TREE_STR_SHUT]);
|
||||||
RichString_append(out, CRT_colors[CHECK_TEXT], " ");
|
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 = {
|
static const ObjectClass MaskItem_class = {
|
||||||
@ -173,7 +173,6 @@ static void AffinityPanel_update(AffinityPanel* this, bool keepSelected) {
|
|||||||
Panel* super = (Panel*) this;
|
Panel* super = (Panel*) this;
|
||||||
|
|
||||||
FunctionBar_setLabel(super->currentBar, KEY_F(3), this->topoView ? "Collapse/Expand" : "");
|
FunctionBar_setLabel(super->currentBar, KEY_F(3), this->topoView ? "Collapse/Expand" : "");
|
||||||
FunctionBar_draw(super->currentBar);
|
|
||||||
|
|
||||||
int oldSelected = Panel_getSelectedIndex(super);
|
int oldSelected = Panel_getSelectedIndex(super);
|
||||||
Panel_prune(super);
|
Panel_prune(super);
|
||||||
@ -281,7 +280,7 @@ static MaskItem* AffinityPanel_addObject(AffinityPanel* this, hwloc_obj_t obj, u
|
|||||||
indent_buf[0] = '\0';
|
indent_buf[0] = '\0';
|
||||||
if (depth > 0) {
|
if (depth > 0) {
|
||||||
for (unsigned i = 1; i < depth; i++) {
|
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]);
|
size_t len = strlen(&indent_buf[off]);
|
||||||
off += len;
|
off += len;
|
||||||
left -= 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) {
|
static MaskItem* AffinityPanel_buildTopology(AffinityPanel* this, hwloc_obj_t obj, unsigned indent, MaskItem* parent) {
|
||||||
MaskItem* item = AffinityPanel_addObject(this, obj, indent, parent);
|
MaskItem* item = AffinityPanel_addObject(this, obj, indent, parent);
|
||||||
if (obj->next_sibling) {
|
if (obj->next_sibling) {
|
||||||
indent |= (1u << obj->depth);
|
indent |= (1U << obj->depth);
|
||||||
} else {
|
} else {
|
||||||
indent &= ~(1u << obj->depth);
|
indent &= ~(1U << obj->depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < obj->arity; i++) {
|
for (unsigned i = 0; i < obj->arity; i++) {
|
||||||
|
@ -77,7 +77,7 @@ AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns) {
|
|||||||
|
|
||||||
Panel_setHeader(super, "Available 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) {
|
if (i != COMM && Process_fields[i].description) {
|
||||||
char description[256];
|
char description[256];
|
||||||
xSnprintf(description, sizeof(description), "%s - %s", Process_fields[i].name, Process_fields[i].description);
|
xSnprintf(description, sizeof(description), "%s - %s", Process_fields[i].name, Process_fields[i].description);
|
||||||
|
@ -35,7 +35,6 @@ static inline void AvailableMetersPanel_addMeter(Header* header, Panel* panel, c
|
|||||||
Panel_add(panel, (Object*) Meter_toListItem(meter, false));
|
Panel_add(panel, (Object*) Meter_toListItem(meter, false));
|
||||||
Panel_setSelected(panel, Panel_size(panel) - 1);
|
Panel_setSelected(panel, Panel_size(panel) - 1);
|
||||||
MetersPanel_setMoving((MetersPanel*)panel, true);
|
MetersPanel_setMoving((MetersPanel*)panel, true);
|
||||||
FunctionBar_draw(panel->currentBar);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
|
static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
|
||||||
|
@ -35,24 +35,21 @@ static void BatteryMeter_updateValues(Meter* this, char* buffer, size_t len) {
|
|||||||
|
|
||||||
this->values[0] = percent;
|
this->values[0] = percent;
|
||||||
|
|
||||||
const char *onAcText, *onBatteryText, *unknownText;
|
const char* text;
|
||||||
|
switch (isOnAC) {
|
||||||
unknownText = "%.1f%%";
|
case AC_PRESENT:
|
||||||
if (this->mode == TEXT_METERMODE) {
|
text = this->mode == TEXT_METERMODE ? " (Running on A/C)" : "(A/C)";
|
||||||
onAcText = "%.1f%% (Running on A/C)";
|
break;
|
||||||
onBatteryText = "%.1f%% (Running on battery)";
|
case AC_ABSENT:
|
||||||
} else {
|
text = this->mode == TEXT_METERMODE ? " (Running on battery)" : "(bat)";
|
||||||
onAcText = "%.1f%%(A/C)";
|
break;
|
||||||
onBatteryText = "%.1f%%(bat)";
|
case AC_ERROR:
|
||||||
|
default:
|
||||||
|
text = "";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOnAC == AC_PRESENT) {
|
xSnprintf(buffer, len, "%.1f%%%s", percent, text);
|
||||||
xSnprintf(buffer, len, onAcText, percent);
|
|
||||||
} else if (isOnAC == AC_ABSENT) {
|
|
||||||
xSnprintf(buffer, len, onBatteryText, percent);
|
|
||||||
} else {
|
|
||||||
xSnprintf(buffer, len, unknownText, percent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const MeterClass BatteryMeter_class = {
|
const MeterClass BatteryMeter_class = {
|
||||||
|
52
CPUMeter.c
52
CPUMeter.c
@ -67,7 +67,7 @@ static void CPUMeter_updateValues(Meter* this, char* buffer, size_t size) {
|
|||||||
double percent = Platform_setCPUValues(this, cpu);
|
double percent = Platform_setCPUValues(this, cpu);
|
||||||
|
|
||||||
if (this->pl->settings->showCPUUsage) {
|
if (this->pl->settings->showCPUUsage) {
|
||||||
xSnprintf(cpuUsageBuffer, sizeof(cpuUsageBuffer), "%5.1f%%", percent);
|
xSnprintf(cpuUsageBuffer, sizeof(cpuUsageBuffer), "%.1f%%", percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->pl->settings->showCPUFrequency) {
|
if (this->pl->settings->showCPUFrequency) {
|
||||||
@ -104,49 +104,49 @@ static void CPUMeter_display(const Object* cast, RichString* out) {
|
|||||||
const Meter* this = (const Meter*)cast;
|
const Meter* this = (const Meter*)cast;
|
||||||
RichString_prune(out);
|
RichString_prune(out);
|
||||||
if (this->param > this->pl->cpuCount) {
|
if (this->param > this->pl->cpuCount) {
|
||||||
RichString_append(out, CRT_colors[METER_TEXT], "absent");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], "absent");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NORMAL]);
|
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NORMAL]);
|
||||||
RichString_append(out, CRT_colors[METER_TEXT], ":");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], ":");
|
||||||
RichString_append(out, CRT_colors[CPU_NORMAL], buffer);
|
RichString_appendAscii(out, CRT_colors[CPU_NORMAL], buffer);
|
||||||
if (this->pl->settings->detailedCPUTime) {
|
if (this->pl->settings->detailedCPUTime) {
|
||||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
|
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
|
||||||
RichString_append(out, CRT_colors[METER_TEXT], "sy:");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], "sy:");
|
||||||
RichString_append(out, CRT_colors[CPU_SYSTEM], buffer);
|
RichString_appendAscii(out, CRT_colors[CPU_SYSTEM], buffer);
|
||||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
|
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
|
||||||
RichString_append(out, CRT_colors[METER_TEXT], "ni:");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], "ni:");
|
||||||
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer);
|
RichString_appendAscii(out, CRT_colors[CPU_NICE_TEXT], buffer);
|
||||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]);
|
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]);
|
||||||
RichString_append(out, CRT_colors[METER_TEXT], "hi:");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], "hi:");
|
||||||
RichString_append(out, CRT_colors[CPU_IRQ], buffer);
|
RichString_appendAscii(out, CRT_colors[CPU_IRQ], buffer);
|
||||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_SOFTIRQ]);
|
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_SOFTIRQ]);
|
||||||
RichString_append(out, CRT_colors[METER_TEXT], "si:");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], "si:");
|
||||||
RichString_append(out, CRT_colors[CPU_SOFTIRQ], buffer);
|
RichString_appendAscii(out, CRT_colors[CPU_SOFTIRQ], buffer);
|
||||||
if (!isnan(this->values[CPU_METER_STEAL])) {
|
if (!isnan(this->values[CPU_METER_STEAL])) {
|
||||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", 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_appendAscii(out, CRT_colors[METER_TEXT], "st:");
|
||||||
RichString_append(out, CRT_colors[CPU_STEAL], buffer);
|
RichString_appendAscii(out, CRT_colors[CPU_STEAL], buffer);
|
||||||
}
|
}
|
||||||
if (!isnan(this->values[CPU_METER_GUEST])) {
|
if (!isnan(this->values[CPU_METER_GUEST])) {
|
||||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", 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_appendAscii(out, CRT_colors[METER_TEXT], "gu:");
|
||||||
RichString_append(out, CRT_colors[CPU_GUEST], buffer);
|
RichString_appendAscii(out, CRT_colors[CPU_GUEST], buffer);
|
||||||
}
|
}
|
||||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IOWAIT]);
|
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IOWAIT]);
|
||||||
RichString_append(out, CRT_colors[METER_TEXT], "wa:");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], "wa:");
|
||||||
RichString_append(out, CRT_colors[CPU_IOWAIT], buffer);
|
RichString_appendAscii(out, CRT_colors[CPU_IOWAIT], buffer);
|
||||||
} else {
|
} else {
|
||||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
|
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
|
||||||
RichString_append(out, CRT_colors[METER_TEXT], "sys:");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], "sys:");
|
||||||
RichString_append(out, CRT_colors[CPU_SYSTEM], buffer);
|
RichString_appendAscii(out, CRT_colors[CPU_SYSTEM], buffer);
|
||||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
|
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
|
||||||
RichString_append(out, CRT_colors[METER_TEXT], "low:");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], "low:");
|
||||||
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer);
|
RichString_appendAscii(out, CRT_colors[CPU_NICE_TEXT], buffer);
|
||||||
if (!isnan(this->values[CPU_METER_IRQ])) {
|
if (!isnan(this->values[CPU_METER_IRQ])) {
|
||||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", 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_appendAscii(out, CRT_colors[METER_TEXT], "vir:");
|
||||||
RichString_append(out, CRT_colors[CPU_GUEST], buffer);
|
RichString_appendAscii(out, CRT_colors[CPU_GUEST], buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,8 +161,8 @@ static void CPUMeter_display(const Object* cast, RichString* out) {
|
|||||||
} else {
|
} else {
|
||||||
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sC", cpuTemperature, CRT_degreeSign);
|
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sC", cpuTemperature, CRT_degreeSign);
|
||||||
}
|
}
|
||||||
RichString_append(out, CRT_colors[METER_TEXT], "temp:");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], "temp:");
|
||||||
RichString_append(out, CRT_colors[METER_VALUE], cpuTemperatureBuffer);
|
RichString_appendWide(out, CRT_colors[METER_VALUE], cpuTemperatureBuffer);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
138
CRT.c
138
CRT.c
@ -41,28 +41,33 @@ in the source distribution for its full text.
|
|||||||
#define ColorPairGrayBlack ColorPair(Magenta,Magenta)
|
#define ColorPairGrayBlack ColorPair(Magenta,Magenta)
|
||||||
#define ColorIndexGrayBlack ColorIndex(Magenta,Magenta)
|
#define ColorIndexGrayBlack ColorIndex(Magenta,Magenta)
|
||||||
|
|
||||||
static const char* const CRT_treeStrAscii[TREE_STR_COUNT] = {
|
#define ColorPairWhiteDefault ColorPair(Red, Red)
|
||||||
"-", // TREE_STR_HORZ
|
#define ColorIndexWhiteDefault ColorIndex(Red, Red)
|
||||||
"|", // TREE_STR_VERT
|
|
||||||
"`", // TREE_STR_RTEE
|
static const char* const CRT_treeStrAscii[LAST_TREE_STR] = {
|
||||||
"`", // TREE_STR_BEND
|
[TREE_STR_VERT] = "|",
|
||||||
",", // TREE_STR_TEND
|
[TREE_STR_RTEE] = "`",
|
||||||
"+", // TREE_STR_OPEN
|
[TREE_STR_BEND] = "`",
|
||||||
"-", // TREE_STR_SHUT
|
[TREE_STR_TEND] = ",",
|
||||||
|
[TREE_STR_OPEN] = "+",
|
||||||
|
[TREE_STR_SHUT] = "-",
|
||||||
|
[TREE_STR_ASC] = "+",
|
||||||
|
[TREE_STR_DESC] = "-",
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef HAVE_LIBNCURSESW
|
#ifdef HAVE_LIBNCURSESW
|
||||||
|
|
||||||
static const char* const CRT_treeStrUtf8[TREE_STR_COUNT] = {
|
static const char* const CRT_treeStrUtf8[LAST_TREE_STR] = {
|
||||||
"\xe2\x94\x80", // TREE_STR_HORZ ─
|
[TREE_STR_VERT] = "\xe2\x94\x82", // │
|
||||||
"\xe2\x94\x82", // TREE_STR_VERT │
|
[TREE_STR_RTEE] = "\xe2\x94\x9c", // ├
|
||||||
"\xe2\x94\x9c", // TREE_STR_RTEE ├
|
[TREE_STR_BEND] = "\xe2\x94\x94", // └
|
||||||
"\xe2\x94\x94", // TREE_STR_BEND └
|
[TREE_STR_TEND] = "\xe2\x94\x8c", // ┌
|
||||||
"\xe2\x94\x8c", // TREE_STR_TEND ┌
|
[TREE_STR_OPEN] = "+", // +, TODO use 🮯 'BOX DRAWINGS LIGHT HORIZONTAL
|
||||||
"+", // TREE_STR_OPEN +, TODO use 🮯 'BOX DRAWINGS LIGHT HORIZONTAL
|
// WITH VERTICAL STROKE' (U+1FBAF, "\xf0\x9f\xae\xaf") when
|
||||||
// WITH VERTICAL STROKE' (U+1FBAF, "\xf0\x9f\xae\xaf") when
|
// Unicode 13 is common
|
||||||
// Unicode 13 is common
|
[TREE_STR_SHUT] = "\xe2\x94\x80", // ─
|
||||||
"\xe2\x94\x80", // TREE_STR_SHUT ─
|
[TREE_STR_ASC] = "\xe2\x96\xb3", // △
|
||||||
|
[TREE_STR_DESC] = "\xe2\x96\xbd", // ▽
|
||||||
};
|
};
|
||||||
|
|
||||||
bool CRT_utf8 = false;
|
bool CRT_utf8 = false;
|
||||||
@ -92,7 +97,7 @@ static const char* initDegreeSign(void) {
|
|||||||
|
|
||||||
const int* CRT_colors;
|
const int* CRT_colors;
|
||||||
|
|
||||||
int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
|
static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
|
||||||
[COLORSCHEME_DEFAULT] = {
|
[COLORSCHEME_DEFAULT] = {
|
||||||
[RESET_COLOR] = ColorPair(White, Black),
|
[RESET_COLOR] = ColorPair(White, Black),
|
||||||
[DEFAULT_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_IOWRITE] = ColorPair(Blue, Black),
|
||||||
[METER_VALUE_NOTICE] = A_BOLD | ColorPair(White, Black),
|
[METER_VALUE_NOTICE] = A_BOLD | ColorPair(White, Black),
|
||||||
[METER_VALUE_OK] = ColorPair(Green, Black),
|
[METER_VALUE_OK] = ColorPair(Green, Black),
|
||||||
|
[METER_VALUE_WARN] = A_BOLD | ColorPair(Yellow, Black),
|
||||||
[LED_COLOR] = ColorPair(Green, Black),
|
[LED_COLOR] = ColorPair(Green, Black),
|
||||||
[TASKS_RUNNING] = A_BOLD | ColorPair(Green, Black),
|
[TASKS_RUNNING] = A_BOLD | ColorPair(Green, Black),
|
||||||
[PROCESS] = A_NORMAL,
|
[PROCESS] = A_NORMAL,
|
||||||
@ -200,6 +206,7 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
|
|||||||
[METER_VALUE_IOWRITE] = A_NORMAL,
|
[METER_VALUE_IOWRITE] = A_NORMAL,
|
||||||
[METER_VALUE_NOTICE] = A_BOLD,
|
[METER_VALUE_NOTICE] = A_BOLD,
|
||||||
[METER_VALUE_OK] = A_NORMAL,
|
[METER_VALUE_OK] = A_NORMAL,
|
||||||
|
[METER_VALUE_WARN] = A_BOLD,
|
||||||
[LED_COLOR] = A_NORMAL,
|
[LED_COLOR] = A_NORMAL,
|
||||||
[TASKS_RUNNING] = A_BOLD,
|
[TASKS_RUNNING] = A_BOLD,
|
||||||
[PROCESS] = A_NORMAL,
|
[PROCESS] = A_NORMAL,
|
||||||
@ -284,6 +291,7 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
|
|||||||
[METER_VALUE_IOWRITE] = ColorPair(Yellow, White),
|
[METER_VALUE_IOWRITE] = ColorPair(Yellow, White),
|
||||||
[METER_VALUE_NOTICE] = A_BOLD | ColorPair(Yellow, White),
|
[METER_VALUE_NOTICE] = A_BOLD | ColorPair(Yellow, White),
|
||||||
[METER_VALUE_OK] = ColorPair(Green, White),
|
[METER_VALUE_OK] = ColorPair(Green, White),
|
||||||
|
[METER_VALUE_WARN] = A_BOLD | ColorPair(Yellow, White),
|
||||||
[LED_COLOR] = ColorPair(Green, White),
|
[LED_COLOR] = ColorPair(Green, White),
|
||||||
[TASKS_RUNNING] = ColorPair(Green, White),
|
[TASKS_RUNNING] = ColorPair(Green, White),
|
||||||
[PROCESS] = ColorPair(Black, White),
|
[PROCESS] = ColorPair(Black, White),
|
||||||
@ -346,10 +354,10 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
|
|||||||
[ZRAM] = ColorPair(Yellow, White)
|
[ZRAM] = ColorPair(Yellow, White)
|
||||||
},
|
},
|
||||||
[COLORSCHEME_LIGHTTERMINAL] = {
|
[COLORSCHEME_LIGHTTERMINAL] = {
|
||||||
[RESET_COLOR] = ColorPair(Blue, Black),
|
[RESET_COLOR] = ColorPair(Black, Black),
|
||||||
[DEFAULT_COLOR] = ColorPair(Blue, Black),
|
[DEFAULT_COLOR] = ColorPair(Black, Black),
|
||||||
[FUNCTION_BAR] = ColorPair(Black, Cyan),
|
[FUNCTION_BAR] = ColorPair(Black, Cyan),
|
||||||
[FUNCTION_KEY] = ColorPair(Blue, Black),
|
[FUNCTION_KEY] = ColorPair(Black, Black),
|
||||||
[PANEL_HEADER_FOCUS] = ColorPair(Black, Green),
|
[PANEL_HEADER_FOCUS] = ColorPair(Black, Green),
|
||||||
[PANEL_HEADER_UNFOCUS] = ColorPair(Black, Green),
|
[PANEL_HEADER_UNFOCUS] = ColorPair(Black, Green),
|
||||||
[PANEL_SELECTION_FOCUS] = ColorPair(Black, Cyan),
|
[PANEL_SELECTION_FOCUS] = ColorPair(Black, Cyan),
|
||||||
@ -362,17 +370,18 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
|
|||||||
[BATTERY] = ColorPair(Yellow, Black),
|
[BATTERY] = ColorPair(Yellow, Black),
|
||||||
[LARGE_NUMBER] = ColorPair(Red, Black),
|
[LARGE_NUMBER] = ColorPair(Red, Black),
|
||||||
[METER_TEXT] = ColorPair(Blue, 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_ERROR] = A_BOLD | ColorPair(Red, Black),
|
||||||
[METER_VALUE_IOREAD] = ColorPair(Green, Black),
|
[METER_VALUE_IOREAD] = ColorPair(Green, Black),
|
||||||
[METER_VALUE_IOWRITE] = ColorPair(Yellow, 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_OK] = ColorPair(Green, Black),
|
||||||
|
[METER_VALUE_WARN] = A_BOLD | ColorPair(Yellow, Black),
|
||||||
[LED_COLOR] = ColorPair(Green, Black),
|
[LED_COLOR] = ColorPair(Green, Black),
|
||||||
[TASKS_RUNNING] = ColorPair(Green, Black),
|
[TASKS_RUNNING] = ColorPair(Green, Black),
|
||||||
[PROCESS] = ColorPair(Blue, Black),
|
[PROCESS] = ColorPair(Black, Black),
|
||||||
[PROCESS_SHADOW] = A_BOLD | ColorPairGrayBlack,
|
[PROCESS_SHADOW] = A_BOLD | ColorPairGrayBlack,
|
||||||
[PROCESS_TAG] = ColorPair(Yellow, Blue),
|
[PROCESS_TAG] = ColorPair(White, Blue),
|
||||||
[PROCESS_MEGABYTES] = ColorPair(Blue, Black),
|
[PROCESS_MEGABYTES] = ColorPair(Blue, Black),
|
||||||
[PROCESS_GIGABYTES] = ColorPair(Green, Black),
|
[PROCESS_GIGABYTES] = ColorPair(Green, Black),
|
||||||
[PROCESS_BASENAME] = 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] = ColorPair(Cyan, Black),
|
||||||
[MEMORY_BUFFERS_TEXT] = ColorPair(Cyan, Black),
|
[MEMORY_BUFFERS_TEXT] = ColorPair(Cyan, Black),
|
||||||
[MEMORY_CACHE] = ColorPair(Yellow, Black),
|
[MEMORY_CACHE] = ColorPair(Yellow, Black),
|
||||||
[LOAD_AVERAGE_FIFTEEN] = ColorPair(Blue, Black),
|
[LOAD_AVERAGE_FIFTEEN] = ColorPair(Black, Black),
|
||||||
[LOAD_AVERAGE_FIVE] = ColorPair(Blue, Black),
|
[LOAD_AVERAGE_FIVE] = ColorPair(Black, Black),
|
||||||
[LOAD_AVERAGE_ONE] = ColorPair(Yellow, Black),
|
[LOAD_AVERAGE_ONE] = ColorPair(Black, Black),
|
||||||
[LOAD] = ColorPair(Yellow, Black),
|
[LOAD] = ColorPairWhiteDefault,
|
||||||
[HELP_BOLD] = ColorPair(Blue, Black),
|
[HELP_BOLD] = ColorPair(Blue, Black),
|
||||||
[CLOCK] = ColorPair(Yellow, Black),
|
[CLOCK] = ColorPairWhiteDefault,
|
||||||
[DATE] = ColorPair(White, Black),
|
[DATE] = ColorPairWhiteDefault,
|
||||||
[DATETIME] = ColorPair(White, Black),
|
[DATETIME] = ColorPairWhiteDefault,
|
||||||
[CHECK_BOX] = ColorPair(Blue, Black),
|
[CHECK_BOX] = ColorPair(Blue, Black),
|
||||||
[CHECK_MARK] = ColorPair(Blue, Black),
|
[CHECK_MARK] = ColorPair(Black, Black),
|
||||||
[CHECK_TEXT] = ColorPair(Blue, Black),
|
[CHECK_TEXT] = ColorPair(Black, Black),
|
||||||
[HOSTNAME] = ColorPair(Yellow, Black),
|
[HOSTNAME] = ColorPairWhiteDefault,
|
||||||
[CPU_NICE] = ColorPair(Cyan, Black),
|
[CPU_NICE] = ColorPair(Cyan, Black),
|
||||||
[CPU_NICE_TEXT] = ColorPair(Cyan, Black),
|
[CPU_NICE_TEXT] = ColorPair(Cyan, Black),
|
||||||
[CPU_NORMAL] = ColorPair(Green, Black),
|
[CPU_NORMAL] = ColorPair(Green, Black),
|
||||||
[CPU_SYSTEM] = ColorPair(Red, 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_IRQ] = A_BOLD | ColorPair(Blue, Black),
|
||||||
[CPU_SOFTIRQ] = ColorPair(Blue, Black),
|
[CPU_SOFTIRQ] = ColorPair(Blue, Black),
|
||||||
[CPU_STEAL] = ColorPair(Blue, Black),
|
[CPU_STEAL] = ColorPair(Black, Black),
|
||||||
[CPU_GUEST] = ColorPair(Blue, Black),
|
[CPU_GUEST] = ColorPair(Black, Black),
|
||||||
[PRESSURE_STALL_THREEHUNDRED] = ColorPair(Blue, Black),
|
[PRESSURE_STALL_THREEHUNDRED] = ColorPair(Black, Black),
|
||||||
[PRESSURE_STALL_SIXTY] = ColorPair(Blue, Black),
|
[PRESSURE_STALL_SIXTY] = ColorPair(Black, Black),
|
||||||
[PRESSURE_STALL_TEN] = ColorPair(Blue, Black),
|
[PRESSURE_STALL_TEN] = ColorPair(Black, Black),
|
||||||
[ZFS_MFU] = ColorPair(Cyan, Black),
|
[ZFS_MFU] = ColorPair(Cyan, Black),
|
||||||
[ZFS_MRU] = ColorPair(Yellow, Black),
|
[ZFS_MRU] = ColorPair(Yellow, Black),
|
||||||
[ZFS_ANON] = A_BOLD | ColorPair(Magenta, 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_OTHER] = A_BOLD | ColorPair(Magenta, Black),
|
||||||
[ZFS_COMPRESSED] = ColorPair(Cyan, Black),
|
[ZFS_COMPRESSED] = ColorPair(Cyan, Black),
|
||||||
[ZFS_RATIO] = A_BOLD | ColorPair(Magenta, 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_IOWRITE] = ColorPair(Black, Blue),
|
||||||
[METER_VALUE_NOTICE] = A_BOLD | ColorPair(White, Blue),
|
[METER_VALUE_NOTICE] = A_BOLD | ColorPair(White, Blue),
|
||||||
[METER_VALUE_OK] = ColorPair(Green, Blue),
|
[METER_VALUE_OK] = ColorPair(Green, Blue),
|
||||||
|
[METER_VALUE_WARN] = A_BOLD | ColorPair(Yellow, Black),
|
||||||
[LED_COLOR] = ColorPair(Green, Blue),
|
[LED_COLOR] = ColorPair(Green, Blue),
|
||||||
[TASKS_RUNNING] = A_BOLD | ColorPair(Green, Blue),
|
[TASKS_RUNNING] = A_BOLD | ColorPair(Green, Blue),
|
||||||
[PROCESS] = ColorPair(White, 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_ERROR] = A_BOLD | ColorPair(Red, Black),
|
||||||
[METER_VALUE_IOREAD] = ColorPair(Green, Black),
|
[METER_VALUE_IOREAD] = ColorPair(Green, Black),
|
||||||
[METER_VALUE_IOWRITE] = ColorPair(Blue, 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_OK] = ColorPair(Green, Black),
|
||||||
|
[METER_VALUE_WARN] = A_BOLD | ColorPair(Yellow, Black),
|
||||||
[LED_COLOR] = ColorPair(Green, Black),
|
[LED_COLOR] = ColorPair(Green, Black),
|
||||||
[TASKS_RUNNING] = A_BOLD | ColorPair(Green, Black),
|
[TASKS_RUNNING] = A_BOLD | ColorPair(Green, Black),
|
||||||
[PROCESS] = ColorPair(Cyan, Black),
|
[PROCESS] = ColorPair(Cyan, Black),
|
||||||
@ -604,12 +615,7 @@ int CRT_scrollHAmount = 5;
|
|||||||
|
|
||||||
int CRT_scrollWheelVAmount = 10;
|
int CRT_scrollWheelVAmount = 10;
|
||||||
|
|
||||||
const char* CRT_termType;
|
ColorScheme CRT_colorScheme = COLORSCHEME_DEFAULT;
|
||||||
|
|
||||||
int CRT_colorScheme = 0;
|
|
||||||
|
|
||||||
long CRT_pageSize = -1;
|
|
||||||
long CRT_pageSizeKB = -1;
|
|
||||||
|
|
||||||
ATTR_NORETURN
|
ATTR_NORETURN
|
||||||
static void CRT_handleSIGTERM(int sgn) {
|
static void CRT_handleSIGTERM(int sgn) {
|
||||||
@ -676,14 +682,14 @@ void CRT_init(const int* delay, int colorScheme, bool allowUnicode) {
|
|||||||
start_color();
|
start_color();
|
||||||
}
|
}
|
||||||
|
|
||||||
CRT_termType = getenv("TERM");
|
const char* termType = getenv("TERM");
|
||||||
if (String_eq(CRT_termType, "linux")) {
|
if (termType && String_eq(termType, "linux")) {
|
||||||
CRT_scrollHAmount = 20;
|
CRT_scrollHAmount = 20;
|
||||||
} else {
|
} else {
|
||||||
CRT_scrollHAmount = 5;
|
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[H", KEY_HOME);
|
||||||
define_key("\033[F", KEY_END);
|
define_key("\033[F", KEY_END);
|
||||||
define_key("\033[7~", KEY_HOME);
|
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[12~", KEY_F(2));
|
||||||
define_key("\033[13~", KEY_F(3));
|
define_key("\033[13~", KEY_F(3));
|
||||||
define_key("\033[14~", KEY_F(4));
|
define_key("\033[14~", KEY_F(4));
|
||||||
|
define_key("\033[14;2~", KEY_F(15));
|
||||||
define_key("\033[17;2~", KEY_F(18));
|
define_key("\033[17;2~", KEY_F(18));
|
||||||
char sequence[3] = "\033a";
|
char sequence[3] = "\033a";
|
||||||
for (char c = 'a'; c <= 'z'; c++) {
|
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);
|
mousemask(BUTTON1_RELEASED, NULL);
|
||||||
#endif
|
#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();
|
CRT_degreeSign = initDegreeSign();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -760,7 +762,7 @@ void CRT_done() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CRT_fatalError(const char* note) {
|
void CRT_fatalError(const char* note) {
|
||||||
char* sysMsg = strerror(errno);
|
const char* sysMsg = strerror(errno);
|
||||||
CRT_done();
|
CRT_done();
|
||||||
fprintf(stderr, "%s: %s\n", note, sysMsg);
|
fprintf(stderr, "%s: %s\n", note, sysMsg);
|
||||||
exit(2);
|
exit(2);
|
||||||
@ -790,7 +792,7 @@ void CRT_setColors(int colorScheme) {
|
|||||||
|
|
||||||
for (short int i = 0; i < 8; i++) {
|
for (short int i = 0; i < 8; i++) {
|
||||||
for (short int j = 0; j < 8; j++) {
|
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)
|
short int bg = (colorScheme != COLORSCHEME_BLACKNIGHT)
|
||||||
? (j == 0 ? -1 : j)
|
? (j == 0 ? -1 : j)
|
||||||
: j;
|
: j;
|
||||||
@ -803,6 +805,8 @@ void CRT_setColors(int colorScheme) {
|
|||||||
short int grayBlackBg = (colorScheme != COLORSCHEME_BLACKNIGHT) ? -1 : 0;
|
short int grayBlackBg = (colorScheme != COLORSCHEME_BLACKNIGHT) ? -1 : 0;
|
||||||
init_pair(ColorIndexGrayBlack, grayBlackFg, grayBlackBg);
|
init_pair(ColorIndexGrayBlack, grayBlackFg, grayBlackBg);
|
||||||
|
|
||||||
|
init_pair(ColorIndexWhiteDefault, White, -1);
|
||||||
|
|
||||||
CRT_colors = CRT_colorSchemes[colorScheme];
|
CRT_colors = CRT_colorSchemes[colorScheme];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -819,9 +823,13 @@ void CRT_handleSIGSEGV(int signal) {
|
|||||||
"- Your OS and kernel version (uname -a)\n"
|
"- Your OS and kernel version (uname -a)\n"
|
||||||
"- Your distribution and release (lsb_release -a)\n"
|
"- Your distribution and release (lsb_release -a)\n"
|
||||||
"- Likely steps to reproduce (How did it happened?)\n"
|
"- Likely steps to reproduce (How did it happened?)\n"
|
||||||
|
);
|
||||||
|
|
||||||
#ifdef HAVE_EXECINFO_H
|
#ifdef HAVE_EXECINFO_H
|
||||||
"- Backtrace of the issue (see below)\n"
|
fprintf(stderr, "- Backtrace of the issue (see below)\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
"\n"
|
"\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -856,11 +864,15 @@ void CRT_handleSIGSEGV(int signal) {
|
|||||||
"you should provide a disassembly of your binary.\n"
|
"you should provide a disassembly of your binary.\n"
|
||||||
"This can usually be done by running the following command:\n"
|
"This can usually be done by running the following command:\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
);
|
||||||
|
|
||||||
#ifdef HTOP_DARWIN
|
#ifdef HTOP_DARWIN
|
||||||
" otool -tvV `which htop` > ~/htop.otool\n"
|
fprintf(stderr, " otool -tvV `which htop` > ~/htop.otool\n");
|
||||||
#else
|
#else
|
||||||
" objdump -d -S -w `which htop` > ~/htop.objdump\n"
|
fprintf(stderr, " objdump -d -S -w `which htop` > ~/htop.objdump\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
"\n"
|
"\n"
|
||||||
"Please include the generated file in your report.\n"
|
"Please include the generated file in your report.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
23
CRT.h
23
CRT.h
@ -16,26 +16,27 @@ in the source distribution for its full text.
|
|||||||
|
|
||||||
|
|
||||||
typedef enum TreeStr_ {
|
typedef enum TreeStr_ {
|
||||||
TREE_STR_HORZ,
|
|
||||||
TREE_STR_VERT,
|
TREE_STR_VERT,
|
||||||
TREE_STR_RTEE,
|
TREE_STR_RTEE,
|
||||||
TREE_STR_BEND,
|
TREE_STR_BEND,
|
||||||
TREE_STR_TEND,
|
TREE_STR_TEND,
|
||||||
TREE_STR_OPEN,
|
TREE_STR_OPEN,
|
||||||
TREE_STR_SHUT,
|
TREE_STR_SHUT,
|
||||||
TREE_STR_COUNT
|
TREE_STR_ASC,
|
||||||
|
TREE_STR_DESC,
|
||||||
|
LAST_TREE_STR
|
||||||
} TreeStr;
|
} TreeStr;
|
||||||
|
|
||||||
typedef enum ColorSchemes_ {
|
typedef enum ColorScheme_ {
|
||||||
COLORSCHEME_DEFAULT = 0,
|
COLORSCHEME_DEFAULT,
|
||||||
COLORSCHEME_MONOCHROME,
|
COLORSCHEME_MONOCHROME,
|
||||||
COLORSCHEME_BLACKONWHITE,
|
COLORSCHEME_BLACKONWHITE,
|
||||||
COLORSCHEME_LIGHTTERMINAL,
|
COLORSCHEME_LIGHTTERMINAL,
|
||||||
COLORSCHEME_MIDNIGHT,
|
COLORSCHEME_MIDNIGHT,
|
||||||
COLORSCHEME_BLACKNIGHT,
|
COLORSCHEME_BLACKNIGHT,
|
||||||
COLORSCHEME_BROKENGRAY,
|
COLORSCHEME_BROKENGRAY,
|
||||||
LAST_COLORSCHEME,
|
LAST_COLORSCHEME
|
||||||
} ColorSchemes;
|
} ColorScheme;
|
||||||
|
|
||||||
typedef enum ColorElements_ {
|
typedef enum ColorElements_ {
|
||||||
RESET_COLOR,
|
RESET_COLOR,
|
||||||
@ -58,6 +59,7 @@ typedef enum ColorElements_ {
|
|||||||
METER_VALUE_IOWRITE,
|
METER_VALUE_IOWRITE,
|
||||||
METER_VALUE_NOTICE,
|
METER_VALUE_NOTICE,
|
||||||
METER_VALUE_OK,
|
METER_VALUE_OK,
|
||||||
|
METER_VALUE_WARN,
|
||||||
LED_COLOR,
|
LED_COLOR,
|
||||||
UPTIME,
|
UPTIME,
|
||||||
BATTERY,
|
BATTERY,
|
||||||
@ -144,20 +146,13 @@ extern const char* const* CRT_treeStr;
|
|||||||
|
|
||||||
extern const int* CRT_colors;
|
extern const int* CRT_colors;
|
||||||
|
|
||||||
extern int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT];
|
|
||||||
|
|
||||||
extern int CRT_cursorX;
|
extern int CRT_cursorX;
|
||||||
|
|
||||||
extern int CRT_scrollHAmount;
|
extern int CRT_scrollHAmount;
|
||||||
|
|
||||||
extern int CRT_scrollWheelVAmount;
|
extern int CRT_scrollWheelVAmount;
|
||||||
|
|
||||||
extern const char* CRT_termType;
|
extern ColorScheme CRT_colorScheme;
|
||||||
|
|
||||||
extern int CRT_colorScheme;
|
|
||||||
|
|
||||||
extern long CRT_pageSize;
|
|
||||||
extern long CRT_pageSizeKB;
|
|
||||||
|
|
||||||
#ifdef HAVE_SETUID_ENABLED
|
#ifdef HAVE_SETUID_ENABLED
|
||||||
|
|
||||||
|
56
ChangeLog
56
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
|
What's new in version 3.0.3
|
||||||
|
|
||||||
* Process sorting in 'tree' mode
|
* Process sorting in 'tree' mode
|
||||||
|
@ -60,26 +60,21 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
|
|||||||
case KEY_MOUSE:
|
case KEY_MOUSE:
|
||||||
case KEY_RECLICK:
|
case KEY_RECLICK:
|
||||||
case ' ':
|
case ' ':
|
||||||
|
assert(mark >= 0);
|
||||||
|
assert(mark < LAST_COLORSCHEME);
|
||||||
for (int i = 0; ColorSchemeNames[i] != NULL; i++)
|
for (int i = 0; ColorSchemeNames[i] != NULL; i++)
|
||||||
CheckItem_set((CheckItem*)Panel_get(super, i), false);
|
CheckItem_set((CheckItem*)Panel_get(super, i), false);
|
||||||
CheckItem_set((CheckItem*)Panel_get(super, mark), true);
|
CheckItem_set((CheckItem*)Panel_get(super, mark), true);
|
||||||
|
|
||||||
this->settings->colorScheme = mark;
|
this->settings->colorScheme = mark;
|
||||||
result = HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == HANDLED) {
|
|
||||||
this->settings->changed = true;
|
this->settings->changed = true;
|
||||||
const Header* header = this->scr->header;
|
|
||||||
CRT_setColors(mark);
|
CRT_setColors(mark);
|
||||||
clear();
|
clear();
|
||||||
Panel* menu = (Panel*) Vector_get(this->scr->panels, 0);
|
|
||||||
Header_draw(header);
|
result = HANDLED | REDRAW;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,6 +95,8 @@ ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr) {
|
|||||||
this->settings = settings;
|
this->settings = settings;
|
||||||
this->scr = scr;
|
this->scr = scr;
|
||||||
|
|
||||||
|
assert(ARRAYSIZE(ColorSchemeNames) == LAST_COLORSCHEME + 1);
|
||||||
|
|
||||||
Panel_setHeader(super, "Colors");
|
Panel_setHeader(super, "Colors");
|
||||||
for (int i = 0; ColorSchemeNames[i] != NULL; i++) {
|
for (int i = 0; ColorSchemeNames[i] != NULL; i++) {
|
||||||
Panel_add(super, (Object*) CheckItem_newByVal(ColorSchemeNames[i], false));
|
Panel_add(super, (Object*) CheckItem_newByVal(ColorSchemeNames[i], false));
|
||||||
|
@ -44,7 +44,7 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
|
|||||||
{
|
{
|
||||||
if (selected < size - 1) {
|
if (selected < size - 1) {
|
||||||
this->moving = !(this->moving);
|
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);
|
ListItem* selectedItem = (ListItem*) Panel_getSelected(super);
|
||||||
if (selectedItem)
|
if (selectedItem)
|
||||||
selectedItem->moving = this->moving;
|
selectedItem->moving = this->moving;
|
||||||
|
@ -17,9 +17,10 @@ static void CommandScreen_scan(InfoScreen* this) {
|
|||||||
Panel_prune(panel);
|
Panel_prune(panel);
|
||||||
|
|
||||||
const char* p = Process_getCommand(this->process);
|
const char* p = Process_getCommand(this->process);
|
||||||
char* line = xMalloc(COLS + 1);
|
char line[COLS + 1];
|
||||||
int line_offset = 0, last_spc = -1, len;
|
int line_offset = 0, last_spc = -1, len;
|
||||||
for (; *p != '\0'; p++, line_offset++) {
|
for (; *p != '\0'; p++, line_offset++) {
|
||||||
|
assert(line_offset >= 0 && (size_t)line_offset < sizeof(line));
|
||||||
line[line_offset] = *p;
|
line[line_offset] = *p;
|
||||||
if (*p == ' ') {
|
if (*p == ' ') {
|
||||||
last_spc = line_offset;
|
last_spc = line_offset;
|
||||||
@ -41,7 +42,6 @@ static void CommandScreen_scan(InfoScreen* this) {
|
|||||||
InfoScreen_addLine(this, line);
|
InfoScreen_addLine(this, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(line);
|
|
||||||
Panel_setSelected(panel, idx);
|
Panel_setSelected(panel, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ const InfoScreenClass CommandScreen_class = {
|
|||||||
|
|
||||||
CommandScreen* CommandScreen_new(Process* process) {
|
CommandScreen* CommandScreen_new(Process* process) {
|
||||||
CommandScreen* this = AllocThis(CommandScreen);
|
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) {
|
void CommandScreen_delete(Object* this) {
|
||||||
|
34
Compat.c
34
Compat.c
@ -11,12 +11,18 @@ in the source distribution for its full text.
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h> // IWYU pragma: keep
|
#include <fcntl.h> // IWYU pragma: keep
|
||||||
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h> // IWYU pragma: keep
|
#include <sys/types.h> // IWYU pragma: keep
|
||||||
|
|
||||||
#include "XUtils.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,
|
int Compat_faccessat(int dirfd,
|
||||||
const char* pathname,
|
const char* pathname,
|
||||||
@ -117,3 +123,31 @@ ssize_t Compat_readlinkat(int dirfd,
|
|||||||
|
|
||||||
#endif
|
#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
|
||||||
|
|
||||||
|
}
|
||||||
|
2
Compat.h
2
Compat.h
@ -56,4 +56,6 @@ ssize_t Compat_readlinkat(int dirfd,
|
|||||||
char* buf,
|
char* buf,
|
||||||
size_t bufsize);
|
size_t bufsize);
|
||||||
|
|
||||||
|
int Compat_clock_monotonic_gettime(struct timespec *tp);
|
||||||
|
|
||||||
#endif /* HEADER_Compat */
|
#endif /* HEADER_Compat */
|
||||||
|
@ -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) {
|
static void DIskIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
|
||||||
if (!hasData) {
|
if (!hasData) {
|
||||||
RichString_write(out, CRT_colors[METER_VALUE_ERROR], "no data");
|
RichString_writeAscii(out, CRT_colors[METER_VALUE_ERROR], "no data");
|
||||||
return;
|
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;
|
int color = cached_utilisation_diff > 40.0 ? METER_VALUE_NOTICE : METER_VALUE;
|
||||||
xSnprintf(buffer, sizeof(buffer), "%.1f%%", cached_utilisation_diff);
|
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));
|
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));
|
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 = {
|
const MeterClass DiskIOMeter_class = {
|
||||||
|
@ -97,6 +97,7 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
|
|||||||
|
|
||||||
Panel_setHeader(super, "Display options");
|
Panel_setHeader(super, "Display options");
|
||||||
Panel_add(super, (Object*) CheckItem_newByRef("Tree view", &(settings->treeView)));
|
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("Shadow other users' processes", &(settings->shadowOtherUsers)));
|
||||||
Panel_add(super, (Object*) CheckItem_newByRef("Hide kernel threads", &(settings->hideKernelThreads)));
|
Panel_add(super, (Object*) CheckItem_newByRef("Hide kernel threads", &(settings->hideKernelThreads)));
|
||||||
Panel_add(super, (Object*) CheckItem_newByRef("Hide userland process threads", &(settings->hideUserlandThreads)));
|
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*) 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*) 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("- 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
|
#ifdef HAVE_LIBHWLOC
|
||||||
Panel_add(super, (Object*) CheckItem_newByRef("Show topology when selecting affinity by default", &(settings->topologyAffinity)));
|
Panel_add(super, (Object*) CheckItem_newByRef("Show topology when selecting affinity by default", &(settings->topologyAffinity)));
|
||||||
#endif
|
#endif
|
||||||
|
24
EnvScreen.c
24
EnvScreen.c
@ -14,30 +14,21 @@
|
|||||||
#include "XUtils.h"
|
#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* EnvScreen_new(Process* process) {
|
||||||
EnvScreen* this = xMalloc(sizeof(EnvScreen));
|
EnvScreen* this = xMalloc(sizeof(EnvScreen));
|
||||||
Object_setClass(this, Class(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) {
|
void EnvScreen_delete(Object* this) {
|
||||||
free(InfoScreen_done((InfoScreen*)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));
|
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;
|
Panel* panel = this->display;
|
||||||
int idx = MAXIMUM(Panel_getSelectedIndex(panel), 0);
|
int idx = MAXIMUM(Panel_getSelectedIndex(panel), 0);
|
||||||
|
|
||||||
@ -59,3 +50,12 @@ void EnvScreen_scan(InfoScreen* this) {
|
|||||||
Vector_insertionSort(panel->items);
|
Vector_insertionSort(panel->items);
|
||||||
Panel_setSelected(panel, idx);
|
Panel_setSelected(panel, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const InfoScreenClass EnvScreen_class = {
|
||||||
|
.super = {
|
||||||
|
.extends = Class(Object),
|
||||||
|
.delete = EnvScreen_delete
|
||||||
|
},
|
||||||
|
.scan = EnvScreen_scan,
|
||||||
|
.draw = EnvScreen_draw
|
||||||
|
};
|
||||||
|
@ -15,8 +15,4 @@ EnvScreen* EnvScreen_new(Process* process);
|
|||||||
|
|
||||||
void EnvScreen_delete(Object* this);
|
void EnvScreen_delete(Object* this);
|
||||||
|
|
||||||
void EnvScreen_draw(InfoScreen* this);
|
|
||||||
|
|
||||||
void EnvScreen_scan(InfoScreen* this);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -112,10 +112,11 @@ void FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr
|
|||||||
attrset(attr);
|
attrset(attr);
|
||||||
}
|
}
|
||||||
mvaddstr(LINES - 1, x, buffer);
|
mvaddstr(LINES - 1, x, buffer);
|
||||||
attrset(CRT_colors[RESET_COLOR]);
|
|
||||||
x += strlen(buffer);
|
x += strlen(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attrset(CRT_colors[RESET_COLOR]);
|
||||||
|
|
||||||
if (setCursor) {
|
if (setCursor) {
|
||||||
CRT_cursorX = x;
|
CRT_cursorX = x;
|
||||||
curs_set(1);
|
curs_set(1);
|
||||||
@ -132,10 +133,10 @@ void FunctionBar_append(const char* buffer, int attr) {
|
|||||||
} else {
|
} else {
|
||||||
attrset(attr);
|
attrset(attr);
|
||||||
}
|
}
|
||||||
mvaddstr(LINES - 1, currentLen, buffer);
|
mvaddstr(LINES - 1, currentLen + 1, buffer);
|
||||||
attrset(CRT_colors[RESET_COLOR]);
|
attrset(CRT_colors[RESET_COLOR]);
|
||||||
|
|
||||||
currentLen += strlen(buffer);
|
currentLen += strlen(buffer) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos) {
|
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos) {
|
||||||
|
90
Hashtable.c
90
Hashtable.c
@ -15,22 +15,37 @@ in the source distribution for its full text.
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "CRT.h"
|
||||||
#include "Macros.h"
|
#include "Macros.h"
|
||||||
#include "XUtils.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
|
#ifndef NDEBUG
|
||||||
|
|
||||||
static void Hashtable_dump(const Hashtable* this) {
|
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,
|
(const void*)this,
|
||||||
this->size,
|
this->size,
|
||||||
this->items,
|
this->items,
|
||||||
this->owner ? "yes" : "no");
|
this->owner ? "yes" : "no");
|
||||||
|
|
||||||
unsigned int items = 0;
|
size_t items = 0;
|
||||||
for (unsigned int i = 0; i < this->size; i++) {
|
for (size_t i = 0; i < this->size; i++) {
|
||||||
fprintf(stderr, " item %5u: key = %5u probe = %2u value = %p\n",
|
fprintf(stderr, " item %5zu: key = %5u probe = %2zu value = %p\n",
|
||||||
i,
|
i,
|
||||||
this->buckets[i].key,
|
this->buckets[i].key,
|
||||||
this->buckets[i].probe,
|
this->buckets[i].probe,
|
||||||
@ -40,15 +55,15 @@ static void Hashtable_dump(const Hashtable* this) {
|
|||||||
items++;
|
items++;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "Hashtable %p: items=%u counted=%u\n",
|
fprintf(stderr, "Hashtable %p: items=%zu counted=%zu\n",
|
||||||
(const void*)this,
|
(const void*)this,
|
||||||
this->items,
|
this->items,
|
||||||
items);
|
items);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Hashtable_isConsistent(const Hashtable* this) {
|
static bool Hashtable_isConsistent(const Hashtable* this) {
|
||||||
unsigned int items = 0;
|
size_t items = 0;
|
||||||
for (unsigned int i = 0; i < this->size; i++) {
|
for (size_t i = 0; i < this->size; i++) {
|
||||||
if (this->buckets[i].value)
|
if (this->buckets[i].value)
|
||||||
items++;
|
items++;
|
||||||
}
|
}
|
||||||
@ -58,9 +73,9 @@ static bool Hashtable_isConsistent(const Hashtable* this) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Hashtable_count(const Hashtable* this) {
|
size_t Hashtable_count(const Hashtable* this) {
|
||||||
unsigned int items = 0;
|
size_t items = 0;
|
||||||
for (unsigned int i = 0; i < this->size; i++) {
|
for (size_t i = 0; i < this->size; i++) {
|
||||||
if (this->buckets[i].value)
|
if (this->buckets[i].value)
|
||||||
items++;
|
items++;
|
||||||
}
|
}
|
||||||
@ -80,18 +95,17 @@ static const uint64_t OEISprimes[] = {
|
|||||||
34359738337, 68719476731, 137438953447
|
34359738337, 68719476731, 137438953447
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint64_t nextPrime(unsigned int n) {
|
static uint64_t nextPrime(size_t n) {
|
||||||
assert(n <= OEISprimes[ARRAYSIZE(OEISprimes) - 1]);
|
/* 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++) {
|
||||||
for (unsigned int i = 0; i < ARRAYSIZE(OEISprimes); i++) {
|
|
||||||
if (n <= OEISprimes[i])
|
if (n <= OEISprimes[i])
|
||||||
return 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;
|
Hashtable* this;
|
||||||
|
|
||||||
this = xMalloc(sizeof(Hashtable));
|
this = xMalloc(sizeof(Hashtable));
|
||||||
@ -115,7 +129,7 @@ void Hashtable_clear(Hashtable* this) {
|
|||||||
assert(Hashtable_isConsistent(this));
|
assert(Hashtable_isConsistent(this));
|
||||||
|
|
||||||
if (this->owner)
|
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);
|
free(this->buckets[i].value);
|
||||||
|
|
||||||
memset(this->buckets, 0, this->size * sizeof(HashtableItem));
|
memset(this->buckets, 0, this->size * sizeof(HashtableItem));
|
||||||
@ -124,11 +138,11 @@ void Hashtable_clear(Hashtable* this) {
|
|||||||
assert(Hashtable_isConsistent(this));
|
assert(Hashtable_isConsistent(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void insert(Hashtable* this, hkey_t key, void* value) {
|
static void insert(Hashtable* this, ht_key_t key, void* value) {
|
||||||
unsigned int index = key % this->size;
|
size_t index = key % this->size;
|
||||||
unsigned int probe = 0;
|
size_t probe = 0;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
unsigned int origIndex = index;
|
size_t origIndex = index;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (;;) {
|
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));
|
assert(Hashtable_isConsistent(this));
|
||||||
|
|
||||||
@ -175,14 +189,14 @@ void Hashtable_setSize(Hashtable* this, unsigned int size) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
HashtableItem* oldBuckets = this->buckets;
|
HashtableItem* oldBuckets = this->buckets;
|
||||||
unsigned int oldSize = this->size;
|
size_t oldSize = this->size;
|
||||||
|
|
||||||
this->size = nextPrime(size);
|
this->size = nextPrime(size);
|
||||||
this->buckets = (HashtableItem*) xCalloc(this->size, sizeof(HashtableItem));
|
this->buckets = (HashtableItem*) xCalloc(this->size, sizeof(HashtableItem));
|
||||||
this->items = 0;
|
this->items = 0;
|
||||||
|
|
||||||
/* rehash */
|
/* rehash */
|
||||||
for (unsigned int i = 0; i < oldSize; i++) {
|
for (size_t i = 0; i < oldSize; i++) {
|
||||||
if (!oldBuckets[i].value)
|
if (!oldBuckets[i].value)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -194,15 +208,19 @@ void Hashtable_setSize(Hashtable* this, unsigned int size) {
|
|||||||
assert(Hashtable_isConsistent(this));
|
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(Hashtable_isConsistent(this));
|
||||||
assert(this->size > 0);
|
assert(this->size > 0);
|
||||||
assert(value);
|
assert(value);
|
||||||
|
|
||||||
/* grow on load-factor > 0.7 */
|
/* 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);
|
Hashtable_setSize(this, 2 * this->size);
|
||||||
|
}
|
||||||
|
|
||||||
insert(this, key, value);
|
insert(this, key, value);
|
||||||
|
|
||||||
@ -211,11 +229,11 @@ void Hashtable_put(Hashtable* this, hkey_t key, void* value) {
|
|||||||
assert(this->size > this->items);
|
assert(this->size > this->items);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* Hashtable_remove(Hashtable* this, hkey_t key) {
|
void* Hashtable_remove(Hashtable* this, ht_key_t key) {
|
||||||
unsigned int index = key % this->size;
|
size_t index = key % this->size;
|
||||||
unsigned int probe = 0;
|
size_t probe = 0;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
unsigned int origIndex = index;
|
size_t origIndex = index;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
assert(Hashtable_isConsistent(this));
|
assert(Hashtable_isConsistent(this));
|
||||||
@ -230,7 +248,7 @@ void* Hashtable_remove(Hashtable* this, hkey_t key) {
|
|||||||
res = this->buckets[index].value;
|
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) {
|
while (this->buckets[next].value && this->buckets[next].probe > 0) {
|
||||||
this->buckets[index] = this->buckets[next];
|
this->buckets[index] = this->buckets[next];
|
||||||
@ -266,12 +284,12 @@ void* Hashtable_remove(Hashtable* this, hkey_t key) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* Hashtable_get(Hashtable* this, hkey_t key) {
|
void* Hashtable_get(Hashtable* this, ht_key_t key) {
|
||||||
unsigned int index = key % this->size;
|
size_t index = key % this->size;
|
||||||
unsigned int probe = 0;
|
size_t probe = 0;
|
||||||
void* res = NULL;
|
void* res = NULL;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
unsigned int origIndex = index;
|
size_t origIndex = index;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
assert(Hashtable_isConsistent(this));
|
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) {
|
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData) {
|
||||||
assert(Hashtable_isConsistent(this));
|
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];
|
HashtableItem* walk = &this->buckets[i];
|
||||||
if (walk->value)
|
if (walk->value)
|
||||||
f(walk->key, walk->value, userData);
|
f(walk->key, walk->value, userData);
|
||||||
|
30
Hashtable.h
30
Hashtable.h
@ -8,44 +8,34 @@ in the source distribution for its full text.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdbool.h>
|
#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_ {
|
typedef struct Hashtable_ Hashtable;
|
||||||
hkey_t key;
|
|
||||||
unsigned int probe;
|
|
||||||
void* value;
|
|
||||||
} HashtableItem;
|
|
||||||
|
|
||||||
typedef struct Hashtable_ {
|
|
||||||
unsigned int size;
|
|
||||||
HashtableItem* buckets;
|
|
||||||
unsigned int items;
|
|
||||||
bool owner;
|
|
||||||
} Hashtable;
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|
||||||
unsigned int Hashtable_count(const Hashtable* this);
|
size_t Hashtable_count(const Hashtable* this);
|
||||||
|
|
||||||
#endif /* NDEBUG */
|
#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_delete(Hashtable* this);
|
||||||
|
|
||||||
void Hashtable_clear(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);
|
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData);
|
||||||
|
|
||||||
|
43
IncSet.c
43
IncSet.c
@ -29,9 +29,9 @@ void IncSet_reset(IncSet* this, IncType type) {
|
|||||||
IncMode_reset(&this->modes[type]);
|
IncMode_reset(&this->modes[type]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* const searchFunctions[] = {"Next ", "Cancel ", " Search: ", NULL};
|
static const char* const searchFunctions[] = {"Next ", "Prev ", "Cancel ", " Search: ", NULL};
|
||||||
static const char* const searchKeys[] = {"F3", "Esc", " "};
|
static const char* const searchKeys[] = {"F3", "S-F3", "Esc", " "};
|
||||||
static int searchEvents[] = {KEY_F(3), 27, ERR};
|
static const int searchEvents[] = {KEY_F(3), KEY_F(15), 27, ERR};
|
||||||
|
|
||||||
static inline void IncMode_initSearch(IncMode* search) {
|
static inline void IncMode_initSearch(IncMode* search) {
|
||||||
memset(search, 0, sizeof(IncMode));
|
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 filterFunctions[] = {"Done ", "Clear ", " Filter: ", NULL};
|
||||||
static const char* const filterKeys[] = {"Enter", "Esc", " "};
|
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) {
|
static inline void IncMode_initFilter(IncMode* filter) {
|
||||||
memset(filter, 0, sizeof(IncMode));
|
memset(filter, 0, sizeof(IncMode));
|
||||||
@ -54,12 +54,13 @@ static inline void IncMode_done(IncMode* mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IncSet* IncSet_new(FunctionBar* bar) {
|
IncSet* IncSet_new(FunctionBar* bar) {
|
||||||
IncSet* this = xCalloc(1, sizeof(IncSet));
|
IncSet* this = xMalloc(sizeof(IncSet));
|
||||||
IncMode_initSearch(&(this->modes[INC_SEARCH]));
|
IncMode_initSearch(&(this->modes[INC_SEARCH]));
|
||||||
IncMode_initFilter(&(this->modes[INC_FILTER]));
|
IncMode_initFilter(&(this->modes[INC_FILTER]));
|
||||||
this->active = NULL;
|
this->active = NULL;
|
||||||
this->filtering = false;
|
|
||||||
this->defaultBar = bar;
|
this->defaultBar = bar;
|
||||||
|
this->filtering = false;
|
||||||
|
this->found = false;
|
||||||
return this;
|
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) {
|
static bool search(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelValue) {
|
||||||
int size = Panel_size(panel);
|
int size = Panel_size(panel);
|
||||||
bool found = false;
|
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
if (String_contains_i(getPanelValue(panel, i), mode->buffer)) {
|
if (String_contains_i(getPanelValue(panel, i), mode->buffer)) {
|
||||||
Panel_setSelected(panel, i);
|
Panel_setSelected(panel, i);
|
||||||
found = true;
|
return true;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionBar_drawExtra(mode->bar,
|
return false;
|
||||||
mode->buffer,
|
|
||||||
found ? -1 : CRT_colors[FAILED_SEARCH],
|
|
||||||
true);
|
|
||||||
return found;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IncMode_find(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelValue, int step) {
|
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) {
|
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines) {
|
||||||
if (ch == ERR)
|
if (ch == ERR)
|
||||||
return true;
|
return true;
|
||||||
@ -154,11 +141,11 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
|
|||||||
int size = Panel_size(panel);
|
int size = Panel_size(panel);
|
||||||
bool filterChanged = false;
|
bool filterChanged = false;
|
||||||
bool doSearch = true;
|
bool doSearch = true;
|
||||||
if (ch == KEY_F(3)) {
|
if (ch == KEY_F(3) || ch == KEY_F(15)) {
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
IncMode_find(mode, panel, getPanelValue, 1);
|
IncMode_find(mode, panel, getPanelValue, ch == KEY_F(3) ? 1 : -1);
|
||||||
doSearch = false;
|
doSearch = false;
|
||||||
} else if (0 < ch && ch < 255 && isprint((unsigned char)ch)) {
|
} else if (0 < ch && ch < 255 && isprint((unsigned char)ch)) {
|
||||||
if (mode->index < INCMODE_MAX) {
|
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) {
|
if (mode->index > 0) {
|
||||||
mode->index--;
|
mode->index--;
|
||||||
mode->buffer[mode->index] = 0;
|
mode->buffer[mode->index] = 0;
|
||||||
@ -187,7 +174,7 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
|
|||||||
doSearch = false;
|
doSearch = false;
|
||||||
}
|
}
|
||||||
} else if (ch == KEY_RESIZE) {
|
} else if (ch == KEY_RESIZE) {
|
||||||
Panel_resize(panel, COLS, LINES - panel->y - 1);
|
doSearch = (mode->index > 0);
|
||||||
} else {
|
} else {
|
||||||
if (mode->isFilter) {
|
if (mode->isFilter) {
|
||||||
filterChanged = true;
|
filterChanged = true;
|
||||||
@ -202,7 +189,6 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
|
|||||||
}
|
}
|
||||||
this->active = NULL;
|
this->active = NULL;
|
||||||
Panel_setDefaultBar(panel);
|
Panel_setDefaultBar(panel);
|
||||||
FunctionBar_draw(this->defaultBar);
|
|
||||||
doSearch = false;
|
doSearch = false;
|
||||||
}
|
}
|
||||||
if (doSearch) {
|
if (doSearch) {
|
||||||
@ -221,13 +207,12 @@ const char* IncSet_getListItemValue(Panel* panel, int i) {
|
|||||||
|
|
||||||
void IncSet_activate(IncSet* this, IncType type, Panel* panel) {
|
void IncSet_activate(IncSet* this, IncType type, Panel* panel) {
|
||||||
this->active = &(this->modes[type]);
|
this->active = &(this->modes[type]);
|
||||||
FunctionBar_drawExtra(this->active->bar, this->active->buffer, -1, true);
|
|
||||||
panel->currentBar = this->active->bar;
|
panel->currentBar = this->active->bar;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IncSet_drawBar(const IncSet* this) {
|
void IncSet_drawBar(const IncSet* this) {
|
||||||
if (this->active) {
|
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 {
|
} else {
|
||||||
FunctionBar_draw(this->defaultBar);
|
FunctionBar_draw(this->defaultBar);
|
||||||
}
|
}
|
||||||
|
4
IncSet.h
4
IncSet.h
@ -48,10 +48,6 @@ IncSet* IncSet_new(FunctionBar* bar);
|
|||||||
|
|
||||||
void IncSet_delete(IncSet* this);
|
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);
|
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines);
|
||||||
|
|
||||||
const char* IncSet_getListItemValue(Panel* panel, int i);
|
const char* IncSet_getListItemValue(Panel* panel, int i);
|
||||||
|
21
InfoScreen.c
21
InfoScreen.c
@ -19,14 +19,14 @@ static const char* const InfoScreenFunctions[] = {"Search ", "Filter ", "Refresh
|
|||||||
|
|
||||||
static const char* const InfoScreenKeys[] = {"F3", "F4", "F5", "Esc"};
|
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) {
|
InfoScreen* InfoScreen_init(InfoScreen* this, const Process* process, FunctionBar* bar, int height, const char* panelHeader) {
|
||||||
this->process = process;
|
this->process = process;
|
||||||
if (!bar) {
|
if (!bar) {
|
||||||
bar = FunctionBar_new(InfoScreenFunctions, InfoScreenKeys, InfoScreenEvents);
|
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->inc = IncSet_new(bar);
|
||||||
this->lines = Vector_new(this->display->items->type, true, DEFAULT_SIZE);
|
this->lines = Vector_new(this->display->items->type, true, DEFAULT_SIZE);
|
||||||
Panel_setHeader(this->display, panelHeader);
|
Panel_setHeader(this->display, panelHeader);
|
||||||
@ -44,21 +44,21 @@ void InfoScreen_drawTitled(InfoScreen* this, const char* fmt, ...) {
|
|||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
|
|
||||||
char* title = xMalloc(COLS + 1);
|
char title[COLS + 1];
|
||||||
int len = vsnprintf(title, COLS + 1, fmt, ap);
|
int len = vsnprintf(title, sizeof(title), fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
if (len > COLS) {
|
if (len > COLS) {
|
||||||
memset(&title[COLS - 3], '.', 3);
|
memset(&title[COLS - 3], '.', 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
attrset(CRT_colors[METER_TEXT]);
|
attrset(CRT_colors[METER_TEXT]);
|
||||||
mvhline(0, 0, ' ', COLS);
|
mvhline(0, 0, ' ', COLS);
|
||||||
mvwprintw(stdscr, 0, 0, title);
|
mvaddstr(0, 0, title);
|
||||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||||
this->display->needsRedraw = true;
|
Panel_draw(this->display, true, true, true, false);
|
||||||
Panel_draw(this->display, true, true);
|
|
||||||
IncSet_drawBar(this->inc);
|
IncSet_drawBar(this->inc);
|
||||||
free(title);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InfoScreen_addLine(InfoScreen* this, const char* line) {
|
void InfoScreen_addLine(InfoScreen* this, const char* line) {
|
||||||
@ -89,7 +89,8 @@ void InfoScreen_run(InfoScreen* this) {
|
|||||||
bool looping = true;
|
bool looping = true;
|
||||||
while (looping) {
|
while (looping) {
|
||||||
|
|
||||||
Panel_draw(panel, true, true);
|
Panel_draw(panel, false, true, true, false);
|
||||||
|
IncSet_drawBar(this->inc);
|
||||||
|
|
||||||
if (this->inc->active) {
|
if (this->inc->active) {
|
||||||
(void) move(LINES - 1, CRT_cursorX);
|
(void) move(LINES - 1, CRT_cursorX);
|
||||||
|
@ -16,7 +16,6 @@ typedef struct InfoScreen_ {
|
|||||||
Object super;
|
Object super;
|
||||||
const Process* process;
|
const Process* process;
|
||||||
Panel* display;
|
Panel* display;
|
||||||
FunctionBar* bar;
|
|
||||||
IncSet* inc;
|
IncSet* inc;
|
||||||
Vector* lines;
|
Vector* lines;
|
||||||
} InfoScreen;
|
} InfoScreen;
|
||||||
|
@ -29,7 +29,7 @@ static void ListItem_display(const Object* cast, RichString* out) {
|
|||||||
assert (this != NULL);
|
assert (this != NULL);
|
||||||
|
|
||||||
if (this->moving) {
|
if (this->moving) {
|
||||||
RichString_write(out, CRT_colors[DEFAULT_COLOR],
|
RichString_writeWide(out, CRT_colors[DEFAULT_COLOR],
|
||||||
#ifdef HAVE_LIBNCURSESW
|
#ifdef HAVE_LIBNCURSESW
|
||||||
CRT_utf8 ? "↕ " :
|
CRT_utf8 ? "↕ " :
|
||||||
#endif
|
#endif
|
||||||
@ -37,7 +37,7 @@ static void ListItem_display(const Object* cast, RichString* out) {
|
|||||||
} else {
|
} else {
|
||||||
RichString_prune(out);
|
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) {
|
ListItem* ListItem_new(const char* value, int key) {
|
||||||
@ -57,7 +57,7 @@ void ListItem_append(ListItem* this, const char* text) {
|
|||||||
this->value[newLen] = '\0';
|
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* obj1 = (const ListItem*) cast1;
|
||||||
const ListItem* obj2 = (const ListItem*) cast2;
|
const ListItem* obj2 = (const ListItem*) cast2;
|
||||||
return strcmp(obj1->value, obj2->value);
|
return strcmp(obj1->value, obj2->value);
|
||||||
|
@ -24,8 +24,36 @@ static const int LoadMeter_attributes[] = {
|
|||||||
LOAD
|
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) {
|
static void LoadAverageMeter_updateValues(Meter* this, char* buffer, size_t size) {
|
||||||
Platform_getLoadAverage(&this->values[0], &this->values[1], &this->values[2]);
|
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]);
|
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;
|
const Meter* this = (const Meter*)cast;
|
||||||
char buffer[20];
|
char buffer[20];
|
||||||
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
|
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]);
|
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]);
|
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) {
|
static void LoadMeter_updateValues(Meter* this, char* buffer, size_t size) {
|
||||||
double five, fifteen;
|
double five, fifteen;
|
||||||
Platform_getLoadAverage(&this->values[0], &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]);
|
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;
|
const Meter* this = (const Meter*)cast;
|
||||||
char buffer[20];
|
char buffer[20];
|
||||||
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
|
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 = {
|
const MeterClass LoadAverageMeter_class = {
|
||||||
|
57
MainPanel.c
57
MainPanel.c
@ -25,7 +25,7 @@ static const char* const MainFunctions[] = {"Help ", "Setup ", "Search", "Filt
|
|||||||
|
|
||||||
void MainPanel_updateTreeFunctions(MainPanel* this, bool mode) {
|
void MainPanel_updateTreeFunctions(MainPanel* this, bool mode) {
|
||||||
FunctionBar* bar = MainPanel_getFunctionBar(this);
|
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) {
|
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) {
|
static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
|
||||||
MainPanel* this = (MainPanel*) super;
|
MainPanel* this = (MainPanel*) super;
|
||||||
|
|
||||||
@ -51,6 +56,11 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
|
|||||||
|
|
||||||
Htop_Reaction reaction = HTOP_OK;
|
Htop_Reaction reaction = HTOP_OK;
|
||||||
|
|
||||||
|
/* Let supervising ScreenManager handle resize */
|
||||||
|
if (ch == KEY_RESIZE)
|
||||||
|
return IGNORED;
|
||||||
|
|
||||||
|
/* reset on every normal key */
|
||||||
if (ch != ERR)
|
if (ch != ERR)
|
||||||
this->state->hideProcessSelection = false;
|
this->state->hideProcessSelection = false;
|
||||||
|
|
||||||
@ -60,7 +70,11 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
|
|||||||
Settings* settings = this->state->settings;
|
Settings* settings = this->state->settings;
|
||||||
int hx = super->scrollH + x + 1;
|
int hx = super->scrollH + x + 1;
|
||||||
ProcessField field = ProcessList_keyAt(pl, hx);
|
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);
|
Settings_invertSortOrder(settings);
|
||||||
} else {
|
} else {
|
||||||
reaction |= Action_setSortKey(settings, field);
|
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;
|
reaction |= HTOP_RECALCULATE | HTOP_REDRAW_BAR | HTOP_SAVE_SETTINGS;
|
||||||
result = HANDLED;
|
result = HANDLED;
|
||||||
} else if (ch != ERR && this->inc->active) {
|
} 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) {
|
if (filterChanged) {
|
||||||
this->state->pl->incFilter = IncSet_filter(this->inc);
|
this->state->pl->incFilter = IncSet_filter(this->inc);
|
||||||
reaction = HTOP_REFRESH | HTOP_REDRAW_BAR;
|
reaction = HTOP_REFRESH | HTOP_REDRAW_BAR;
|
||||||
@ -96,16 +110,12 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
|
|||||||
|
|
||||||
if (reaction & HTOP_REDRAW_BAR) {
|
if (reaction & HTOP_REDRAW_BAR) {
|
||||||
MainPanel_updateTreeFunctions(this, this->state->settings->treeView);
|
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) {
|
if (reaction & HTOP_UPDATE_PANELHDR) {
|
||||||
ProcessList_printHeader(this->state->pl, Panel_getHeader(super));
|
result |= REDRAW;
|
||||||
}
|
}
|
||||||
if (reaction & HTOP_REFRESH) {
|
if (reaction & HTOP_REFRESH) {
|
||||||
result |= REDRAW;
|
result |= REFRESH;
|
||||||
}
|
}
|
||||||
if (reaction & HTOP_RECALCULATE) {
|
if (reaction & HTOP_RECALCULATE) {
|
||||||
result |= RESCAN;
|
result |= RESCAN;
|
||||||
@ -118,7 +128,7 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
|
|||||||
}
|
}
|
||||||
if (!(reaction & HTOP_KEEP_FOLLOWING)) {
|
if (!(reaction & HTOP_KEEP_FOLLOWING)) {
|
||||||
this->state->pl->following = -1;
|
this->state->pl->following = -1;
|
||||||
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOCUS]);
|
Panel_setSelectionColor(super, PANEL_SELECTION_FOCUS);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -131,11 +141,6 @@ int MainPanel_selectedPid(MainPanel* this) {
|
|||||||
return -1;
|
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) {
|
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged) {
|
||||||
Panel* super = (Panel*) this;
|
Panel* super = (Panel*) this;
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
@ -160,12 +165,32 @@ bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Ar
|
|||||||
return ok;
|
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 = {
|
const PanelClass MainPanel_class = {
|
||||||
.super = {
|
.super = {
|
||||||
.extends = Class(Panel),
|
.extends = Class(Panel),
|
||||||
.delete = MainPanel_delete
|
.delete = MainPanel_delete
|
||||||
},
|
},
|
||||||
.eventHandler = MainPanel_eventHandler
|
.eventHandler = MainPanel_eventHandler,
|
||||||
|
.drawFunctionBar = MainPanel_drawFunctionBar,
|
||||||
|
.printHeader = MainPanel_printHeader
|
||||||
};
|
};
|
||||||
|
|
||||||
MainPanel* MainPanel_new() {
|
MainPanel* MainPanel_new() {
|
||||||
|
@ -38,8 +38,6 @@ void MainPanel_pidSearch(MainPanel* this, int ch);
|
|||||||
|
|
||||||
int MainPanel_selectedPid(MainPanel* this);
|
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);
|
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged);
|
||||||
|
|
||||||
extern const PanelClass MainPanel_class;
|
extern const PanelClass MainPanel_class;
|
||||||
|
26
Makefile.am
26
Makefile.am
@ -133,6 +133,7 @@ linux_platform_headers = \
|
|||||||
linux/LinuxProcessList.h \
|
linux/LinuxProcessList.h \
|
||||||
linux/Platform.h \
|
linux/Platform.h \
|
||||||
linux/PressureStallMeter.h \
|
linux/PressureStallMeter.h \
|
||||||
|
linux/ProcessField.h \
|
||||||
linux/SELinuxMeter.h \
|
linux/SELinuxMeter.h \
|
||||||
linux/SystemdMeter.h \
|
linux/SystemdMeter.h \
|
||||||
linux/ZramMeter.h \
|
linux/ZramMeter.h \
|
||||||
@ -164,9 +165,10 @@ endif
|
|||||||
# -------
|
# -------
|
||||||
|
|
||||||
freebsd_platform_headers = \
|
freebsd_platform_headers = \
|
||||||
freebsd/Platform.h \
|
|
||||||
freebsd/FreeBSDProcessList.h \
|
freebsd/FreeBSDProcessList.h \
|
||||||
freebsd/FreeBSDProcess.h \
|
freebsd/FreeBSDProcess.h \
|
||||||
|
freebsd/Platform.h \
|
||||||
|
freebsd/ProcessField.h \
|
||||||
zfs/ZfsArcMeter.h \
|
zfs/ZfsArcMeter.h \
|
||||||
zfs/ZfsCompressedArcMeter.h \
|
zfs/ZfsCompressedArcMeter.h \
|
||||||
zfs/ZfsArcStats.h \
|
zfs/ZfsArcStats.h \
|
||||||
@ -184,14 +186,16 @@ endif
|
|||||||
# ------------
|
# ------------
|
||||||
|
|
||||||
dragonflybsd_platform_headers = \
|
dragonflybsd_platform_headers = \
|
||||||
dragonflybsd/Platform.h \
|
|
||||||
dragonflybsd/DragonFlyBSDProcessList.h \
|
dragonflybsd/DragonFlyBSDProcessList.h \
|
||||||
dragonflybsd/DragonFlyBSDProcess.h
|
dragonflybsd/DragonFlyBSDProcess.h \
|
||||||
|
dragonflybsd/Platform.h \
|
||||||
|
dragonflybsd/ProcessField.h
|
||||||
|
|
||||||
if HTOP_DRAGONFLYBSD
|
if HTOP_DRAGONFLYBSD
|
||||||
AM_LDFLAGS += -lkvm -lkinfo
|
myhtopplatsources = \
|
||||||
myhtopplatsources = dragonflybsd/Platform.c dragonflybsd/DragonFlyBSDProcessList.c \
|
dragonflybsd/Platform.c \
|
||||||
dragonflybsd/DragonFlyBSDProcess.c
|
dragonflybsd/DragonFlyBSDProcessList.c \
|
||||||
|
dragonflybsd/DragonFlyBSDProcess.c
|
||||||
|
|
||||||
myhtopplatheaders = $(dragonflybsd_platform_headers)
|
myhtopplatheaders = $(dragonflybsd_platform_headers)
|
||||||
endif
|
endif
|
||||||
@ -200,9 +204,10 @@ endif
|
|||||||
# -------
|
# -------
|
||||||
|
|
||||||
openbsd_platform_headers = \
|
openbsd_platform_headers = \
|
||||||
openbsd/Platform.h \
|
|
||||||
openbsd/OpenBSDProcessList.h \
|
openbsd/OpenBSDProcessList.h \
|
||||||
openbsd/OpenBSDProcess.h
|
openbsd/OpenBSDProcess.h \
|
||||||
|
openbsd/Platform.h \
|
||||||
|
openbsd/ProcessField.h
|
||||||
|
|
||||||
if HTOP_OPENBSD
|
if HTOP_OPENBSD
|
||||||
myhtopplatsources = openbsd/Platform.c openbsd/OpenBSDProcessList.c \
|
myhtopplatsources = openbsd/Platform.c openbsd/OpenBSDProcessList.c \
|
||||||
@ -215,9 +220,10 @@ endif
|
|||||||
# ------
|
# ------
|
||||||
|
|
||||||
darwin_platform_headers = \
|
darwin_platform_headers = \
|
||||||
darwin/Platform.h \
|
|
||||||
darwin/DarwinProcess.h \
|
darwin/DarwinProcess.h \
|
||||||
darwin/DarwinProcessList.h \
|
darwin/DarwinProcessList.h \
|
||||||
|
darwin/Platform.h \
|
||||||
|
darwin/ProcessField.h \
|
||||||
zfs/ZfsArcMeter.h \
|
zfs/ZfsArcMeter.h \
|
||||||
zfs/ZfsCompressedArcMeter.h \
|
zfs/ZfsCompressedArcMeter.h \
|
||||||
zfs/ZfsArcStats.h \
|
zfs/ZfsArcStats.h \
|
||||||
@ -237,6 +243,7 @@ endif
|
|||||||
|
|
||||||
solaris_platform_headers = \
|
solaris_platform_headers = \
|
||||||
solaris/Platform.h \
|
solaris/Platform.h \
|
||||||
|
solaris/ProcessField.h \
|
||||||
solaris/SolarisProcess.h \
|
solaris/SolarisProcess.h \
|
||||||
solaris/SolarisProcessList.h \
|
solaris/SolarisProcessList.h \
|
||||||
zfs/ZfsArcMeter.h \
|
zfs/ZfsArcMeter.h \
|
||||||
@ -256,6 +263,7 @@ endif
|
|||||||
|
|
||||||
unsupported_platform_headers = \
|
unsupported_platform_headers = \
|
||||||
unsupported/Platform.h \
|
unsupported/Platform.h \
|
||||||
|
unsupported/ProcessField.h \
|
||||||
unsupported/UnsupportedProcess.h \
|
unsupported/UnsupportedProcess.h \
|
||||||
unsupported/UnsupportedProcessList.h
|
unsupported/UnsupportedProcessList.h
|
||||||
|
|
||||||
|
@ -34,18 +34,18 @@ static void MemoryMeter_updateValues(Meter* this, char* buffer, size_t size) {
|
|||||||
static void MemoryMeter_display(const Object* cast, RichString* out) {
|
static void MemoryMeter_display(const Object* cast, RichString* out) {
|
||||||
char buffer[50];
|
char buffer[50];
|
||||||
const Meter* this = (const Meter*)cast;
|
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, 50);
|
Meter_humanUnit(buffer, this->total, sizeof(buffer));
|
||||||
RichString_append(out, CRT_colors[METER_VALUE], buffer);
|
RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
|
||||||
Meter_humanUnit(buffer, this->values[0], 50);
|
Meter_humanUnit(buffer, this->values[0], sizeof(buffer));
|
||||||
RichString_append(out, CRT_colors[METER_TEXT], " used:");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], " used:");
|
||||||
RichString_append(out, CRT_colors[MEMORY_USED], buffer);
|
RichString_appendAscii(out, CRT_colors[MEMORY_USED], buffer);
|
||||||
Meter_humanUnit(buffer, this->values[1], 50);
|
Meter_humanUnit(buffer, this->values[1], sizeof(buffer));
|
||||||
RichString_append(out, CRT_colors[METER_TEXT], " buffers:");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], " buffers:");
|
||||||
RichString_append(out, CRT_colors[MEMORY_BUFFERS_TEXT], buffer);
|
RichString_appendAscii(out, CRT_colors[MEMORY_BUFFERS_TEXT], buffer);
|
||||||
Meter_humanUnit(buffer, this->values[2], 50);
|
Meter_humanUnit(buffer, this->values[2], sizeof(buffer));
|
||||||
RichString_append(out, CRT_colors[METER_TEXT], " cache:");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], " cache:");
|
||||||
RichString_append(out, CRT_colors[MEMORY_CACHE], buffer);
|
RichString_appendAscii(out, CRT_colors[MEMORY_CACHE], buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MeterClass MemoryMeter_class = {
|
const MeterClass MemoryMeter_class = {
|
||||||
|
66
Meter.c
66
Meter.c
@ -39,6 +39,7 @@ Meter* Meter_new(const struct ProcessList_* pl, int param, const MeterClass* typ
|
|||||||
this->param = param;
|
this->param = param;
|
||||||
this->pl = pl;
|
this->pl = pl;
|
||||||
this->curItems = type->maxItems;
|
this->curItems = type->maxItems;
|
||||||
|
this->curAttributes = NULL;
|
||||||
this->values = type->maxItems ? xCalloc(type->maxItems, sizeof(double)) : NULL;
|
this->values = type->maxItems ? xCalloc(type->maxItems, sizeof(double)) : NULL;
|
||||||
this->total = type->total;
|
this->total = type->total;
|
||||||
this->caption = xStrdup(type->caption);
|
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)) {
|
if (Object_displayFn(this)) {
|
||||||
Object_display(this, out);
|
Object_display(this, out);
|
||||||
} else {
|
} 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) {
|
static void TextMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||||
char buffer[METER_BUFFER_LEN];
|
char buffer[METER_BUFFER_LEN];
|
||||||
Meter_updateValues(this, buffer, sizeof(buffer));
|
Meter_updateValues(this, buffer, sizeof(buffer));
|
||||||
(void) w;
|
|
||||||
|
|
||||||
attrset(CRT_colors[METER_TEXT]);
|
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);
|
int captionLen = strlen(this->caption);
|
||||||
x += captionLen;
|
x += captionLen;
|
||||||
attrset(CRT_colors[RESET_COLOR]);
|
w -= captionLen;
|
||||||
|
if (w <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
RichString_begin(out);
|
RichString_begin(out);
|
||||||
Meter_displayBuffer(this, buffer, &out);
|
Meter_displayBuffer(this, buffer, &out);
|
||||||
RichString_printVal(out, y, x);
|
RichString_printoffnVal(out, y, x, 0, w - 1);
|
||||||
RichString_end(out);
|
RichString_end(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +190,7 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
|
|||||||
w -= captionLen;
|
w -= captionLen;
|
||||||
attrset(CRT_colors[BAR_BORDER]);
|
attrset(CRT_colors[BAR_BORDER]);
|
||||||
mvaddch(y, x, '[');
|
mvaddch(y, x, '[');
|
||||||
mvaddch(y, x + w, ']');
|
mvaddch(y, x + MAXIMUM(w, 0), ']');
|
||||||
attrset(CRT_colors[RESET_COLOR]);
|
attrset(CRT_colors[RESET_COLOR]);
|
||||||
|
|
||||||
w--;
|
w--;
|
||||||
@ -195,14 +200,29 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// The text in the bar is right aligned;
|
// The text in the bar is right aligned;
|
||||||
// calculate needed padding and generate leading spaces
|
// Pad with maximal spaces and then calculate needed starting position offset
|
||||||
const int textLen = mbstowcs(NULL, buffer, 0);
|
|
||||||
const int padding = CLAMP(w - textLen, 0, w);
|
|
||||||
|
|
||||||
RichString_begin(bar);
|
RichString_begin(bar);
|
||||||
RichString_appendChr(&bar, ' ', padding);
|
RichString_appendChr(&bar, ' ', w);
|
||||||
RichString_append(&bar, 0, buffer);
|
RichString_appendWide(&bar, 0, buffer);
|
||||||
assert(RichString_sizeVal(bar) >= w);
|
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];
|
int blockSizes[10];
|
||||||
|
|
||||||
@ -220,11 +240,11 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
|
|||||||
// (Control against invalid values)
|
// (Control against invalid values)
|
||||||
nextOffset = CLAMP(nextOffset, 0, w);
|
nextOffset = CLAMP(nextOffset, 0, w);
|
||||||
for (int j = offset; j < nextOffset; j++)
|
for (int j = offset; j < nextOffset; j++)
|
||||||
if (RichString_getCharVal(bar, j) == ' ') {
|
if (RichString_getCharVal(bar, startPos + j) == ' ') {
|
||||||
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
|
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
|
||||||
RichString_setChar(&bar, j, BarMeterMode_characters[i]);
|
RichString_setChar(&bar, startPos + j, BarMeterMode_characters[i]);
|
||||||
} else {
|
} else {
|
||||||
RichString_setChar(&bar, j, '|');
|
RichString_setChar(&bar, startPos + j, '|');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offset = nextOffset;
|
offset = nextOffset;
|
||||||
@ -233,14 +253,15 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
|
|||||||
// ...then print the buffer.
|
// ...then print the buffer.
|
||||||
offset = 0;
|
offset = 0;
|
||||||
for (uint8_t i = 0; i < this->curItems; i++) {
|
for (uint8_t i = 0; i < this->curItems; i++) {
|
||||||
RichString_setAttrn(&bar, CRT_colors[Meter_attributes(this)[i]], offset, offset + blockSizes[i] - 1);
|
int attr = this->curAttributes ? this->curAttributes[i] : Meter_attributes(this)[i];
|
||||||
RichString_printoffnVal(bar, y, x + offset, offset, blockSizes[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 += blockSizes[i];
|
||||||
offset = CLAMP(offset, 0, w);
|
offset = CLAMP(offset, 0, w);
|
||||||
}
|
}
|
||||||
if (offset < w) {
|
if (offset < w) {
|
||||||
RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], offset, w - 1);
|
RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], startPos + offset, w - offset);
|
||||||
RichString_printoffnVal(bar, y, x + offset, offset, w - offset);
|
RichString_printoffnVal(bar, y, x + offset, startPos + offset, w - offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
RichString_end(bar);
|
RichString_end(bar);
|
||||||
@ -271,9 +292,6 @@ static const char* const GraphMeterMode_dotsAscii[] = {
|
|||||||
/*20*/":", /*21*/":", /*22*/":"
|
/*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) {
|
static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||||
|
|
||||||
if (!this->drawData) {
|
if (!this->drawData) {
|
||||||
@ -282,6 +300,8 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
|
|||||||
GraphData* data = this->drawData;
|
GraphData* data = this->drawData;
|
||||||
const int nValues = METER_BUFFER_LEN;
|
const int nValues = METER_BUFFER_LEN;
|
||||||
|
|
||||||
|
const char* const* GraphMeterMode_dots;
|
||||||
|
int GraphMeterMode_pixPerRow;
|
||||||
#ifdef HAVE_LIBNCURSESW
|
#ifdef HAVE_LIBNCURSESW
|
||||||
if (CRT_utf8) {
|
if (CRT_utf8) {
|
||||||
GraphMeterMode_dots = GraphMeterMode_dotsUtf8;
|
GraphMeterMode_dots = GraphMeterMode_dotsUtf8;
|
||||||
|
1
Meter.h
1
Meter.h
@ -100,6 +100,7 @@ struct Meter_ {
|
|||||||
int h;
|
int h;
|
||||||
const ProcessList* pl;
|
const ProcessList* pl;
|
||||||
uint8_t curItems;
|
uint8_t curItems;
|
||||||
|
const int* curAttributes;
|
||||||
double* values;
|
double* values;
|
||||||
double total;
|
double total;
|
||||||
void* meterData;
|
void* meterData;
|
||||||
|
@ -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
|
// Note: In code the meters are known to have bar/text/graph "Modes", but in UI
|
||||||
// we call them "Styles".
|
// we call them "Styles".
|
||||||
static const char* const MetersFunctions[] = {"Style ", "Move ", " ", "Delete", "Done ", NULL};
|
static const char* const MetersFunctions[] = {"Style ", "Move ", " ", "Delete", "Done ", NULL};
|
||||||
static const char* const MetersKeys[] = {"Space", "Enter", " ", "Del", "F10"};
|
static const char* const MetersKeys[] = {"Space", "Enter", "", "Del", "F10"};
|
||||||
static int MetersEvents[] = {' ', 13, ERR, KEY_DC, KEY_F(10)};
|
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
|
// We avoid UTF-8 arrows ← → here as they might display full-width on Chinese
|
||||||
// terminals, breaking our aligning.
|
// terminals, breaking our aligning.
|
||||||
@ -30,7 +30,7 @@ static int MetersEvents[] = {' ', 13, ERR, KEY_DC, KEY_F(10)};
|
|||||||
// considered "Ambiguous characters".
|
// considered "Ambiguous characters".
|
||||||
static const char* const MetersMovingFunctions[] = {"Style ", "Lock ", "Up ", "Down ", "Left ", "Right ", " ", "Delete", "Done ", NULL};
|
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 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;
|
static FunctionBar* Meters_movingBar = NULL;
|
||||||
|
|
||||||
void MetersPanel_cleanup() {
|
void MetersPanel_cleanup() {
|
||||||
@ -55,13 +55,12 @@ void MetersPanel_setMoving(MetersPanel* this, bool moving) {
|
|||||||
selected->moving = moving;
|
selected->moving = moving;
|
||||||
}
|
}
|
||||||
if (!moving) {
|
if (!moving) {
|
||||||
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOCUS]);
|
Panel_setSelectionColor(super, PANEL_SELECTION_FOCUS);
|
||||||
Panel_setDefaultBar(super);
|
Panel_setDefaultBar(super);
|
||||||
} else {
|
} else {
|
||||||
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOLLOW]);
|
Panel_setSelectionColor(super, PANEL_SELECTION_FOLLOW);
|
||||||
super->currentBar = Meters_movingBar;
|
super->currentBar = Meters_movingBar;
|
||||||
}
|
}
|
||||||
FunctionBar_draw(this->super.currentBar);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int selected) {
|
static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int selected) {
|
||||||
|
@ -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) {
|
static void NetworkIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
|
||||||
if (!hasData) {
|
if (!hasData) {
|
||||||
RichString_write(out, CRT_colors[METER_VALUE_ERROR], "no data");
|
RichString_writeAscii(out, CRT_colors[METER_VALUE_ERROR], "no data");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char buffer[64];
|
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));
|
Meter_humanUnit(buffer, cached_rxb_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_VALUE_IOREAD], "iB/s");
|
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));
|
Meter_humanUnit(buffer, cached_txb_diff, sizeof(buffer));
|
||||||
RichString_append(out, CRT_colors[METER_VALUE_IOWRITE], buffer);
|
RichString_appendAscii(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], "iB/s");
|
||||||
|
|
||||||
xSnprintf(buffer, sizeof(buffer), " (%lu/%lu packets) ", cached_rxp_diff, cached_txp_diff);
|
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 = {
|
const MeterClass NetworkIOMeter_class = {
|
||||||
|
2
Object.h
2
Object.h
@ -24,7 +24,7 @@ struct Object_;
|
|||||||
typedef struct Object_ Object;
|
typedef struct Object_ Object;
|
||||||
|
|
||||||
typedef void(*Object_Display)(const Object*, RichString*);
|
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*);
|
typedef void(*Object_Delete)(Object*);
|
||||||
|
|
||||||
#define Object_getClass(obj_) ((const Object*)(obj_))->klass
|
#define Object_getClass(obj_) ((const Object*)(obj_))->klass
|
||||||
|
@ -74,7 +74,7 @@ OpenFilesScreen* OpenFilesScreen_new(const Process* process) {
|
|||||||
} else {
|
} else {
|
||||||
this->pid = process->pid;
|
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) {
|
void OpenFilesScreen_delete(Object* this) {
|
||||||
|
20
OptionItem.c
20
OptionItem.c
@ -29,14 +29,14 @@ static void CheckItem_display(const Object* cast, RichString* out) {
|
|||||||
const CheckItem* this = (const CheckItem*)cast;
|
const CheckItem* this = (const CheckItem*)cast;
|
||||||
assert (this != NULL);
|
assert (this != NULL);
|
||||||
|
|
||||||
RichString_write(out, CRT_colors[CHECK_BOX], "[");
|
RichString_writeAscii(out, CRT_colors[CHECK_BOX], "[");
|
||||||
if (CheckItem_get(this)) {
|
if (CheckItem_get(this)) {
|
||||||
RichString_append(out, CRT_colors[CHECK_MARK], "x");
|
RichString_appendAscii(out, CRT_colors[CHECK_MARK], "x");
|
||||||
} else {
|
} else {
|
||||||
RichString_append(out, CRT_colors[CHECK_MARK], " ");
|
RichString_appendAscii(out, CRT_colors[CHECK_MARK], " ");
|
||||||
}
|
}
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NumberItem_display(const Object* cast, RichString* out) {
|
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);
|
assert (this != NULL);
|
||||||
|
|
||||||
char buffer[12];
|
char buffer[12];
|
||||||
RichString_write(out, CRT_colors[CHECK_BOX], "[");
|
RichString_writeAscii(out, CRT_colors[CHECK_BOX], "[");
|
||||||
int written;
|
int written;
|
||||||
if (this->scale < 0) {
|
if (this->scale < 0) {
|
||||||
written = xSnprintf(buffer, sizeof(buffer), "%.*f", -this->scale, pow(10, this->scale) * NumberItem_get(this));
|
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 {
|
} else {
|
||||||
written = xSnprintf(buffer, sizeof(buffer), "%d", NumberItem_get(this));
|
written = xSnprintf(buffer, sizeof(buffer), "%d", NumberItem_get(this));
|
||||||
}
|
}
|
||||||
RichString_append(out, CRT_colors[CHECK_MARK], buffer);
|
RichString_appendAscii(out, CRT_colors[CHECK_MARK], buffer);
|
||||||
RichString_append(out, CRT_colors[CHECK_BOX], "]");
|
RichString_appendAscii(out, CRT_colors[CHECK_BOX], "]");
|
||||||
for (int i = written; i < 5; i++) {
|
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 = {
|
const OptionItemClass OptionItem_class = {
|
||||||
|
90
Panel.c
90
Panel.c
@ -30,7 +30,7 @@ const PanelClass Panel_class = {
|
|||||||
.eventHandler = Panel_selectByTyping,
|
.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;
|
Panel* this;
|
||||||
this = xMalloc(sizeof(Panel));
|
this = xMalloc(sizeof(Panel));
|
||||||
Object_setClass(this, Class(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->scrollH = 0;
|
||||||
this->selected = 0;
|
this->selected = 0;
|
||||||
this->oldSelected = 0;
|
this->oldSelected = 0;
|
||||||
|
this->selectedLen = 0;
|
||||||
this->needsRedraw = true;
|
this->needsRedraw = true;
|
||||||
|
this->wasFocus = false;
|
||||||
RichString_beginAllocated(this->header);
|
RichString_beginAllocated(this->header);
|
||||||
this->defaultBar = fuBar;
|
this->defaultBar = fuBar;
|
||||||
this->currentBar = fuBar;
|
this->currentBar = fuBar;
|
||||||
this->selectionColor = CRT_colors[PANEL_SELECTION_FOCUS];
|
this->selectionColorId = PANEL_SELECTION_FOCUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel_done(Panel* this) {
|
void Panel_done(Panel* this) {
|
||||||
@ -70,19 +72,12 @@ void Panel_done(Panel* this) {
|
|||||||
RichString_end(this->header);
|
RichString_end(this->header);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel_setSelectionColor(Panel* this, int color) {
|
void Panel_setSelectionColor(Panel* this, ColorElements colorId) {
|
||||||
this->selectionColor = color;
|
this->selectionColorId = colorId;
|
||||||
}
|
|
||||||
|
|
||||||
RichString* Panel_getHeader(Panel* this) {
|
|
||||||
assert (this != NULL);
|
|
||||||
|
|
||||||
this->needsRedraw = true;
|
|
||||||
return &(this->header);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Panel_setHeader(Panel* this, const char* header) {
|
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;
|
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) {
|
void Panel_resize(Panel* this, int w, int h) {
|
||||||
assert (this != NULL);
|
assert (this != NULL);
|
||||||
|
|
||||||
if (RichString_sizeVal(this->header) > 0) {
|
|
||||||
h--;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->w = w;
|
this->w = w;
|
||||||
this->h = h;
|
this->h = h;
|
||||||
this->needsRedraw = true;
|
this->needsRedraw = true;
|
||||||
@ -217,7 +208,7 @@ void Panel_splice(Panel* this, Vector* from) {
|
|||||||
this->needsRedraw = true;
|
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);
|
assert (this != NULL);
|
||||||
|
|
||||||
int size = Vector_size(this->items);
|
int size = Vector_size(this->items);
|
||||||
@ -226,12 +217,21 @@ void Panel_draw(Panel* this, bool focus, bool highlightSelected) {
|
|||||||
int x = this->x;
|
int x = this->x;
|
||||||
int h = this->h;
|
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);
|
int headerLen = RichString_sizeVal(this->header);
|
||||||
if (headerLen > 0) {
|
if (headerLen > 0) {
|
||||||
int attr = focus
|
attrset(header_attr);
|
||||||
? CRT_colors[PANEL_HEADER_FOCUS]
|
|
||||||
: CRT_colors[PANEL_HEADER_UNFOCUS];
|
|
||||||
attrset(attr);
|
|
||||||
mvhline(y, x, ' ', this->w);
|
mvhline(y, x, ' ', this->w);
|
||||||
if (scrollH < headerLen) {
|
if (scrollH < headerLen) {
|
||||||
RichString_printoffnVal(this->header, y, x, scrollH,
|
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]);
|
attrset(CRT_colors[RESET_COLOR]);
|
||||||
y++;
|
y++;
|
||||||
|
h--;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure scroll area is on screen
|
// 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 upTo = MINIMUM(first + h, size);
|
||||||
|
|
||||||
int selectionColor = focus
|
int selectionColor = focus
|
||||||
? this->selectionColor
|
? CRT_colors[this->selectionColorId]
|
||||||
: CRT_colors[PANEL_SELECTION_UNFOCUS];
|
: CRT_colors[PANEL_SELECTION_UNFOCUS];
|
||||||
|
|
||||||
if (this->needsRedraw) {
|
if (this->needsRedraw || force_redraw) {
|
||||||
int line = 0;
|
int line = 0;
|
||||||
for (int i = first; line < h && i < upTo; i++) {
|
for (int i = first; line < h && i < upTo; i++) {
|
||||||
Object* itemObj = Vector_get(this->items, 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);
|
mvhline(y + line, x, ' ', this->w);
|
||||||
line++;
|
line++;
|
||||||
}
|
}
|
||||||
this->needsRedraw = false;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Object* oldObj = Vector_get(this->items, this->oldSelected);
|
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(new);
|
||||||
RichString_end(old);
|
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->oldSelected = this->selected;
|
||||||
|
this->wasFocus = focus;
|
||||||
|
this->needsRedraw = false;
|
||||||
move(0, 0);
|
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) {
|
bool Panel_onKey(Panel* this, int key) {
|
||||||
assert (this != NULL);
|
assert (this != NULL);
|
||||||
|
|
||||||
int size = Vector_size(this->items);
|
const int size = Vector_size(this->items);
|
||||||
|
|
||||||
#define CLAMP_INDEX(var, delta, min, max) \
|
#define PANEL_SCROLL(amount) \
|
||||||
CLAMP((var) + (delta), (min), MAXIMUM(0, (max)))
|
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) {
|
switch (key) {
|
||||||
case KEY_DOWN:
|
case KEY_DOWN:
|
||||||
@ -363,27 +381,19 @@ bool Panel_onKey(Panel* this, int key) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_PPAGE:
|
case KEY_PPAGE:
|
||||||
this->selected -= (this->h - 1);
|
PANEL_SCROLL(-(this->h - Panel_headerHeight(this)));
|
||||||
this->scrollV = CLAMP_INDEX(this->scrollV, -(this->h - 1), 0, size - this->h);
|
|
||||||
this->needsRedraw = true;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_NPAGE:
|
case KEY_NPAGE:
|
||||||
this->selected += (this->h - 1);
|
PANEL_SCROLL(+(this->h - Panel_headerHeight(this)));
|
||||||
this->scrollV = CLAMP_INDEX(this->scrollV, +(this->h - 1), 0, size - this->h);
|
|
||||||
this->needsRedraw = true;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_WHEELUP:
|
case KEY_WHEELUP:
|
||||||
this->selected -= CRT_scrollWheelVAmount;
|
PANEL_SCROLL(-CRT_scrollWheelVAmount);
|
||||||
this->scrollV = CLAMP_INDEX(this->scrollV, -CRT_scrollWheelVAmount, 0, size - this->h);
|
|
||||||
this->needsRedraw = true;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_WHEELDOWN:
|
case KEY_WHEELDOWN:
|
||||||
this->selected += CRT_scrollWheelVAmount;
|
PANEL_SCROLL(+CRT_scrollWheelVAmount);
|
||||||
this->scrollV = CLAMP_INDEX(this->scrollV, +CRT_scrollWheelVAmount, 0, size - this->h);
|
|
||||||
this->needsRedraw = true;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_HOME:
|
case KEY_HOME:
|
||||||
@ -408,7 +418,7 @@ bool Panel_onKey(Panel* this, int key) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef CLAMP_INDEX
|
#undef PANEL_SCROLL
|
||||||
|
|
||||||
// ensure selection within bounds
|
// ensure selection within bounds
|
||||||
if (this->selected < 0 || size == 0) {
|
if (this->selected < 0 || size == 0) {
|
||||||
|
35
Panel.h
35
Panel.h
@ -9,6 +9,7 @@ in the source distribution for its full text.
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "CRT.h"
|
||||||
#include "FunctionBar.h"
|
#include "FunctionBar.h"
|
||||||
#include "Object.h"
|
#include "Object.h"
|
||||||
#include "RichString.h"
|
#include "RichString.h"
|
||||||
@ -22,9 +23,10 @@ typedef enum HandlerResult_ {
|
|||||||
HANDLED = 0x01,
|
HANDLED = 0x01,
|
||||||
IGNORED = 0x02,
|
IGNORED = 0x02,
|
||||||
BREAK_LOOP = 0x04,
|
BREAK_LOOP = 0x04,
|
||||||
REDRAW = 0x08,
|
REFRESH = 0x08,
|
||||||
RESCAN = 0x10,
|
REDRAW = 0x10,
|
||||||
SYNTH_KEY = 0x20,
|
RESCAN = 0x20,
|
||||||
|
SYNTH_KEY = 0x40,
|
||||||
} HandlerResult;
|
} HandlerResult;
|
||||||
|
|
||||||
#define EVENT_SET_SELECTED (-1)
|
#define EVENT_SET_SELECTED (-1)
|
||||||
@ -33,16 +35,24 @@ typedef enum HandlerResult_ {
|
|||||||
#define EVENT_IS_HEADER_CLICK(ev_) ((ev_) >= -10000 && (ev_) <= -9000)
|
#define EVENT_IS_HEADER_CLICK(ev_) ((ev_) >= -10000 && (ev_) <= -9000)
|
||||||
#define EVENT_HEADER_CLICK_GET_X(ev_) ((ev_) + 10000)
|
#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_ {
|
typedef struct PanelClass_ {
|
||||||
const ObjectClass super;
|
const ObjectClass super;
|
||||||
const Panel_EventHandler eventHandler;
|
const Panel_EventHandler eventHandler;
|
||||||
|
const Panel_DrawFunctionBar drawFunctionBar;
|
||||||
|
const Panel_PrintHeader printHeader;
|
||||||
} PanelClass;
|
} PanelClass;
|
||||||
|
|
||||||
#define As_Panel(this_) ((const PanelClass*)((this_)->super.klass))
|
#define As_Panel(this_) ((const PanelClass*)((this_)->super.klass))
|
||||||
#define Panel_eventHandlerFn(this_) As_Panel(this_)->eventHandler
|
#define Panel_eventHandlerFn(this_) As_Panel(this_)->eventHandler
|
||||||
#define Panel_eventHandler(this_, ev_) As_Panel(this_)->eventHandler((Panel*)(this_), ev_)
|
#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_ {
|
struct Panel_ {
|
||||||
Object super;
|
Object super;
|
||||||
@ -55,10 +65,11 @@ struct Panel_ {
|
|||||||
int scrollV;
|
int scrollV;
|
||||||
short scrollH;
|
short scrollH;
|
||||||
bool needsRedraw;
|
bool needsRedraw;
|
||||||
|
bool wasFocus;
|
||||||
FunctionBar* currentBar;
|
FunctionBar* currentBar;
|
||||||
FunctionBar* defaultBar;
|
FunctionBar* defaultBar;
|
||||||
RichString header;
|
RichString header;
|
||||||
int selectionColor;
|
ColorElements selectionColorId;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define Panel_setDefaultBar(this_) do { (this_)->currentBar = (this_)->defaultBar; } while (0)
|
#define Panel_setDefaultBar(this_) do { (this_)->currentBar = (this_)->defaultBar; } while (0)
|
||||||
@ -67,7 +78,7 @@ struct Panel_ {
|
|||||||
|
|
||||||
extern const PanelClass Panel_class;
|
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);
|
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_done(Panel* this);
|
||||||
|
|
||||||
void Panel_setSelectionColor(Panel* this, int color);
|
void Panel_setSelectionColor(Panel* this, ColorElements colorId);
|
||||||
|
|
||||||
RichString* Panel_getHeader(Panel* this);
|
|
||||||
|
|
||||||
void Panel_setHeader(Panel* this, const char* header);
|
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_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);
|
void Panel_splice(Panel* this, Vector* from);
|
||||||
|
|
||||||
|
170
Process.c
170
Process.c
@ -38,23 +38,15 @@ in the source distribution for its full text.
|
|||||||
|
|
||||||
static uid_t Process_getuid = (uid_t)-1;
|
static uid_t Process_getuid = (uid_t)-1;
|
||||||
|
|
||||||
char Process_pidFormat[20] = "%7d ";
|
int Process_pidDigits = 7;
|
||||||
|
|
||||||
static char Process_titleBuffer[20][20];
|
|
||||||
|
|
||||||
void Process_setupColumnWidths() {
|
void Process_setupColumnWidths() {
|
||||||
int maxPid = Platform_getMaxPid();
|
int maxPid = Platform_getMaxPid();
|
||||||
if (maxPid == -1)
|
if (maxPid == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int digits = ceil(log10(maxPid));
|
Process_pidDigits = ceil(log10(maxPid));
|
||||||
assert(digits < 20);
|
assert(Process_pidDigits <= PROCESS_MAX_PID_DIGITS);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process_humanNumber(RichString* str, unsigned long long number, bool coloring) {
|
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) {
|
if (number < 1000) {
|
||||||
//Plain number, no markings
|
//Plain number, no markings
|
||||||
len = xSnprintf(buffer, sizeof(buffer), "%5llu ", number);
|
len = xSnprintf(buffer, sizeof(buffer), "%5llu ", number);
|
||||||
RichString_appendn(str, processColor, buffer, len);
|
RichString_appendnAscii(str, processColor, buffer, len);
|
||||||
} else if (number < 100000) {
|
} else if (number < 100000) {
|
||||||
//2 digit MB, 3 digit KB
|
//2 digit MB, 3 digit KB
|
||||||
len = xSnprintf(buffer, sizeof(buffer), "%2llu", number/1000);
|
len = xSnprintf(buffer, sizeof(buffer), "%2llu", number/1000);
|
||||||
RichString_appendn(str, processMegabytesColor, buffer, len);
|
RichString_appendnAscii(str, processMegabytesColor, buffer, len);
|
||||||
number %= 1000;
|
number %= 1000;
|
||||||
len = xSnprintf(buffer, sizeof(buffer), "%03llu ", number);
|
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) {
|
} else if (number < 1000 * ONE_K) {
|
||||||
//3 digit MB
|
//3 digit MB
|
||||||
number /= ONE_K;
|
number /= ONE_K;
|
||||||
len = xSnprintf(buffer, sizeof(buffer), "%4lluM ", number);
|
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) {
|
} else if (number < 10000 * ONE_K) {
|
||||||
//1 digit GB, 3 digit MB
|
//1 digit GB, 3 digit MB
|
||||||
number /= ONE_K;
|
number /= ONE_K;
|
||||||
len = xSnprintf(buffer, sizeof(buffer), "%1llu", number/1000);
|
len = xSnprintf(buffer, sizeof(buffer), "%1llu", number/1000);
|
||||||
RichString_appendn(str, processGigabytesColor, buffer, len);
|
RichString_appendnAscii(str, processGigabytesColor, buffer, len);
|
||||||
number %= 1000;
|
number %= 1000;
|
||||||
len = xSnprintf(buffer, sizeof(buffer), "%03lluM ", number);
|
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) {
|
} else if (number < 100000 * ONE_K) {
|
||||||
//2 digit GB, 1 digit MB
|
//2 digit GB, 1 digit MB
|
||||||
number /= 100 * ONE_K;
|
number /= 100 * ONE_K;
|
||||||
len = xSnprintf(buffer, sizeof(buffer), "%2llu", number/10);
|
len = xSnprintf(buffer, sizeof(buffer), "%2llu", number/10);
|
||||||
RichString_appendn(str, processGigabytesColor, buffer, len);
|
RichString_appendnAscii(str, processGigabytesColor, buffer, len);
|
||||||
number %= 10;
|
number %= 10;
|
||||||
len = xSnprintf(buffer, sizeof(buffer), ".%1llu", number);
|
len = xSnprintf(buffer, sizeof(buffer), ".%1llu", number);
|
||||||
RichString_appendn(str, processMegabytesColor, buffer, len);
|
RichString_appendnAscii(str, processMegabytesColor, buffer, len);
|
||||||
RichString_append(str, processGigabytesColor, "G ");
|
RichString_appendAscii(str, processGigabytesColor, "G ");
|
||||||
} else if (number < 1000 * ONE_M) {
|
} else if (number < 1000 * ONE_M) {
|
||||||
//3 digit GB
|
//3 digit GB
|
||||||
number /= ONE_M;
|
number /= ONE_M;
|
||||||
len = xSnprintf(buffer, sizeof(buffer), "%4lluG ", number);
|
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) {
|
} else if (number < 10000ULL * ONE_M) {
|
||||||
//1 digit TB, 3 digit GB
|
//1 digit TB, 3 digit GB
|
||||||
number /= ONE_M;
|
number /= ONE_M;
|
||||||
len = xSnprintf(buffer, sizeof(buffer), "%1llu", number/1000);
|
len = xSnprintf(buffer, sizeof(buffer), "%1llu", number/1000);
|
||||||
RichString_appendn(str, largeNumberColor, buffer, len);
|
RichString_appendnAscii(str, largeNumberColor, buffer, len);
|
||||||
number %= 1000;
|
number %= 1000;
|
||||||
len = xSnprintf(buffer, sizeof(buffer), "%03lluG ", number);
|
len = xSnprintf(buffer, sizeof(buffer), "%03lluG ", number);
|
||||||
RichString_appendn(str, processGigabytesColor, buffer, len);
|
RichString_appendnAscii(str, processGigabytesColor, buffer, len);
|
||||||
} else {
|
} else {
|
||||||
//2 digit TB and above
|
//2 digit TB and above
|
||||||
len = xSnprintf(buffer, sizeof(buffer), "%4.1lfT ", (double)number/ONE_G);
|
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) {
|
if (number == ULLONG_MAX) {
|
||||||
int len = xSnprintf(buffer, sizeof(buffer), " N/A ");
|
RichString_appendAscii(str, CRT_colors[PROCESS_SHADOW], " N/A ");
|
||||||
RichString_appendn(str, CRT_colors[PROCESS_SHADOW], buffer, len);
|
|
||||||
} else if (number >= 100000LL * ONE_DECIMAL_T) {
|
} else if (number >= 100000LL * ONE_DECIMAL_T) {
|
||||||
xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_G);
|
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) {
|
} else if (number >= 100LL * ONE_DECIMAL_T) {
|
||||||
xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_M);
|
xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_M);
|
||||||
RichString_appendn(str, largeNumberColor, buffer, 8);
|
RichString_appendnAscii(str, largeNumberColor, buffer, 8);
|
||||||
RichString_appendn(str, processMegabytesColor, buffer+8, 4);
|
RichString_appendnAscii(str, processMegabytesColor, buffer+8, 4);
|
||||||
} else if (number >= 10LL * ONE_DECIMAL_G) {
|
} else if (number >= 10LL * ONE_DECIMAL_G) {
|
||||||
xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_K);
|
xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_K);
|
||||||
RichString_appendn(str, largeNumberColor, buffer, 5);
|
RichString_appendnAscii(str, largeNumberColor, buffer, 5);
|
||||||
RichString_appendn(str, processMegabytesColor, buffer+5, 3);
|
RichString_appendnAscii(str, processMegabytesColor, buffer+5, 3);
|
||||||
RichString_appendn(str, processColor, buffer+8, 4);
|
RichString_appendnAscii(str, processColor, buffer+8, 4);
|
||||||
} else {
|
} else {
|
||||||
xSnprintf(buffer, sizeof(buffer), "%11llu ", number);
|
xSnprintf(buffer, sizeof(buffer), "%11llu ", number);
|
||||||
RichString_appendn(str, largeNumberColor, buffer, 2);
|
RichString_appendnAscii(str, largeNumberColor, buffer, 2);
|
||||||
RichString_appendn(str, processMegabytesColor, buffer+2, 3);
|
RichString_appendnAscii(str, processMegabytesColor, buffer+2, 3);
|
||||||
RichString_appendn(str, processColor, buffer+5, 3);
|
RichString_appendnAscii(str, processColor, buffer+5, 3);
|
||||||
RichString_appendn(str, processShadowColor, buffer+8, 4);
|
RichString_appendnAscii(str, processShadowColor, buffer+8, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,16 +163,16 @@ void Process_printTime(RichString* str, unsigned long long totalHundredths) {
|
|||||||
char buffer[10];
|
char buffer[10];
|
||||||
if (hours >= 100) {
|
if (hours >= 100) {
|
||||||
xSnprintf(buffer, sizeof(buffer), "%7lluh ", hours);
|
xSnprintf(buffer, sizeof(buffer), "%7lluh ", hours);
|
||||||
RichString_append(str, CRT_colors[LARGE_NUMBER], buffer);
|
RichString_appendAscii(str, CRT_colors[LARGE_NUMBER], buffer);
|
||||||
} else {
|
} else {
|
||||||
if (hours) {
|
if (hours) {
|
||||||
xSnprintf(buffer, sizeof(buffer), "%2lluh", 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);
|
xSnprintf(buffer, sizeof(buffer), "%02d:%02d ", minutes, seconds);
|
||||||
} else {
|
} else {
|
||||||
xSnprintf(buffer, sizeof(buffer), "%2d:%02d.%02d ", minutes, seconds, hundredths);
|
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) {
|
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;
|
const char* comm = this->comm;
|
||||||
|
|
||||||
if (this->settings->highlightBaseName || !this->settings->showProgramPath) {
|
if (this->settings->highlightBaseName || !this->settings->showProgramPath) {
|
||||||
int i, basename = 0;
|
int basename = 0;
|
||||||
for (i = 0; i < this->basenameOffset; i++) {
|
for (int i = 0; i < this->basenameOffset; i++) {
|
||||||
if (comm[i] == '/') {
|
if (comm[i] == '/') {
|
||||||
basename = i + 1;
|
basename = i + 1;
|
||||||
} else if (comm[i] == ':') {
|
} else if (comm[i] == ':') {
|
||||||
finish = i + 1;
|
len = i + 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!finish) {
|
if (len == 0) {
|
||||||
if (this->settings->showProgramPath) {
|
if (this->settings->showProgramPath) {
|
||||||
start += basename;
|
start += basename;
|
||||||
} else {
|
} else {
|
||||||
comm += basename;
|
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) {
|
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)) {
|
if (isnan(rate)) {
|
||||||
int len = xSnprintf(buffer, n, " N/A ");
|
RichString_appendAscii(str, CRT_colors[PROCESS_SHADOW], " N/A ");
|
||||||
RichString_appendn(str, CRT_colors[PROCESS_SHADOW], buffer, len);
|
|
||||||
} else if (rate < ONE_K) {
|
} else if (rate < ONE_K) {
|
||||||
int len = snprintf(buffer, n, "%7.2f B/s ", rate);
|
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) {
|
} else if (rate < ONE_M) {
|
||||||
int len = snprintf(buffer, n, "%7.2f K/s ", rate / ONE_K);
|
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) {
|
} else if (rate < ONE_G) {
|
||||||
int len = snprintf(buffer, n, "%7.2f M/s ", rate / ONE_M);
|
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) {
|
} else if (rate < ONE_T) {
|
||||||
int len = snprintf(buffer, n, "%7.2f G/s ", rate / ONE_G);
|
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 {
|
} else {
|
||||||
int len = snprintf(buffer, n, "%7.2f T/s ", rate / ONE_T);
|
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) {
|
void Process_writeField(const Process* this, RichString* str, ProcessField field) {
|
||||||
char buffer[256]; buffer[255] = '\0';
|
char buffer[256]; buffer[255] = '\0';
|
||||||
int attr = CRT_colors[DEFAULT_COLOR];
|
int attr = CRT_colors[DEFAULT_COLOR];
|
||||||
@ -320,17 +315,18 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
|
|||||||
buf += written;
|
buf += written;
|
||||||
n -= 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] );
|
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);
|
Process_writeCommand(this, attr, baseattr, str);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case MAJFLT: Process_colorNumber(str, this->majflt, coloring); return;
|
case MAJFLT: Process_colorNumber(str, this->majflt, coloring); return;
|
||||||
case MINFLT: Process_colorNumber(str, this->minflt, 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_RESIDENT: Process_humanNumber(str, this->m_resident, coloring); return;
|
||||||
case M_VIRT: Process_humanNumber(str, this->m_virt * CRT_pageSizeKB, coloring); return;
|
case M_VIRT: Process_humanNumber(str, this->m_virt, coloring); return;
|
||||||
case NICE: {
|
case NICE: {
|
||||||
xSnprintf(buffer, n, "%3ld ", this->nice);
|
xSnprintf(buffer, n, "%3ld ", this->nice);
|
||||||
attr = this->nice < 0 ? CRT_colors[PROCESS_HIGH_PRIORITY]
|
attr = this->nice < 0 ? CRT_colors[PROCESS_HIGH_PRIORITY]
|
||||||
@ -339,9 +335,9 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NLWP: xSnprintf(buffer, n, "%4ld ", this->nlwp); break;
|
case NLWP: xSnprintf(buffer, n, "%4ld ", this->nlwp); break;
|
||||||
case PGRP: xSnprintf(buffer, n, Process_pidFormat, this->pgrp); break;
|
case PGRP: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->pgrp); break;
|
||||||
case PID: xSnprintf(buffer, n, Process_pidFormat, this->pid); break;
|
case PID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->pid); break;
|
||||||
case PPID: xSnprintf(buffer, n, Process_pidFormat, this->ppid); break;
|
case PPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->ppid); break;
|
||||||
case PRIORITY: {
|
case PRIORITY: {
|
||||||
if(this->priority <= -100)
|
if(this->priority <= -100)
|
||||||
xSnprintf(buffer, n, " RT ");
|
xSnprintf(buffer, n, " RT ");
|
||||||
@ -350,7 +346,7 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PROCESSOR: xSnprintf(buffer, n, "%3d ", Settings_cpuId(this->settings, this->processor)); 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 STARTTIME: xSnprintf(buffer, n, "%s", this->starttime_show); break;
|
||||||
case STATE: {
|
case STATE: {
|
||||||
xSnprintf(buffer, n, "%c ", this->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 ST_UID: xSnprintf(buffer, n, "%5d ", this->st_uid); break;
|
||||||
case TIME: Process_printTime(str, this->time); return;
|
case TIME: Process_printTime(str, this->time); return;
|
||||||
case TGID: xSnprintf(buffer, n, Process_pidFormat, this->tgid); break;
|
case TGID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->tgid); break;
|
||||||
case TPGID: xSnprintf(buffer, n, Process_pidFormat, this->tpgid); 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 TTY_NR: xSnprintf(buffer, n, "%3u:%3u ", major(this->tty_nr), minor(this->tty_nr)); break;
|
||||||
case USER: {
|
case USER: {
|
||||||
if (Process_getuid != this->st_uid)
|
if (Process_getuid != this->st_uid)
|
||||||
attr = CRT_colors[PROCESS_SHADOW];
|
attr = CRT_colors[PROCESS_SHADOW];
|
||||||
|
|
||||||
if (this->user) {
|
if (this->user) {
|
||||||
xSnprintf(buffer, n, "%-9s ", this->user);
|
Process_printLeftAlignedField(str, attr, this->user, 9);
|
||||||
} else {
|
return;
|
||||||
xSnprintf(buffer, n, "%-9d ", this->st_uid);
|
|
||||||
}
|
|
||||||
if (buffer[9] != '\0') {
|
|
||||||
buffer[9] = ' ';
|
|
||||||
buffer[10] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xSnprintf(buffer, n, "%-9d ", this->st_uid);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
xSnprintf(buffer, n, "- ");
|
xSnprintf(buffer, n, "- ");
|
||||||
}
|
}
|
||||||
RichString_append(str, attr, buffer);
|
RichString_appendWide(str, attr, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process_display(const Object* cast, RichString* out) {
|
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) {
|
void Process_toggleTag(Process* this) {
|
||||||
this->tag = this->tag == true ? false : true;
|
this->tag = !this->tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Process_isNew(const Process* this) {
|
bool Process_isNew(const Process* this) {
|
||||||
assert(this->processList);
|
assert(this->processList);
|
||||||
if (this->processList->scanTs >= this->seenTs) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
@ -486,18 +480,18 @@ bool Process_sendSignal(Process* this, Arg sgn) {
|
|||||||
return ok;
|
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* p1 = (const Process*)v1;
|
||||||
const Process* p2 = (const Process*)v2;
|
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 Process *p1, *p2;
|
||||||
const Settings *settings = ((const Process*)v1)->settings;
|
const Settings *settings = ((const Process*)v1)->settings;
|
||||||
int r;
|
|
||||||
|
|
||||||
if (settings->direction == 1) {
|
if (Settings_getActiveDirection(settings) == 1) {
|
||||||
p1 = (const Process*)v1;
|
p1 = (const Process*)v1;
|
||||||
p2 = (const Process*)v2;
|
p2 = (const Process*)v2;
|
||||||
} else {
|
} else {
|
||||||
@ -505,7 +499,21 @@ long Process_compare(const void* v1, const void* v2) {
|
|||||||
p1 = (const Process*)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_CPU:
|
||||||
case PERCENT_NORM_CPU:
|
case PERCENT_NORM_CPU:
|
||||||
return SPACESHIP_NUMBER(p2->percent_cpu, p1->percent_cpu);
|
return SPACESHIP_NUMBER(p2->percent_cpu, p1->percent_cpu);
|
||||||
|
39
Process.h
39
Process.h
@ -13,17 +13,14 @@ in the source distribution for its full text.
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "Object.h"
|
#include "Object.h"
|
||||||
|
#include "ProcessField.h"
|
||||||
#include "RichString.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 PROCESS_FLAG_IO 0x0001
|
||||||
#define DEFAULT_HIGHLIGHT_SECS 5
|
#define DEFAULT_HIGHLIGHT_SECS 5
|
||||||
|
|
||||||
typedef enum ProcessFields {
|
typedef enum ProcessField_ {
|
||||||
NULL_PROCESSFIELD = 0,
|
NULL_PROCESSFIELD = 0,
|
||||||
PID = 1,
|
PID = 1,
|
||||||
COMM = 2,
|
COMM = 2,
|
||||||
@ -49,12 +46,12 @@ typedef enum ProcessFields {
|
|||||||
NLWP = 51,
|
NLWP = 51,
|
||||||
TGID = 52,
|
TGID = 52,
|
||||||
PERCENT_NORM_CPU = 53,
|
PERCENT_NORM_CPU = 53,
|
||||||
} ProcessField;
|
|
||||||
|
|
||||||
typedef struct ProcessPidColumn_ {
|
/* Platform specific fields, defined in ${platform}/ProcessField.h */
|
||||||
int id;
|
PLATFORM_PROCESS_FIELDS
|
||||||
const char* label;
|
|
||||||
} ProcessPidColumn;
|
LAST_PROCESSFIELD
|
||||||
|
} ProcessField;
|
||||||
|
|
||||||
struct Settings_;
|
struct Settings_;
|
||||||
|
|
||||||
@ -120,30 +117,34 @@ typedef struct ProcessFieldData_ {
|
|||||||
const char* title;
|
const char* title;
|
||||||
const char* description;
|
const char* description;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
bool pidColumn;
|
||||||
} ProcessFieldData;
|
} ProcessFieldData;
|
||||||
|
|
||||||
// Implemented in platform-specific code:
|
// Implemented in platform-specific code:
|
||||||
void Process_writeField(const Process* this, RichString* str, ProcessField field);
|
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);
|
void Process_delete(Object* cast);
|
||||||
bool Process_isThread(const Process* this);
|
bool Process_isThread(const Process* this);
|
||||||
extern ProcessFieldData Process_fields[];
|
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
|
||||||
extern ProcessPidColumn Process_pidColumns[];
|
#define PROCESS_MAX_PID_DIGITS 19
|
||||||
extern char Process_pidFormat[20];
|
extern int Process_pidDigits;
|
||||||
|
|
||||||
typedef Process*(*Process_New)(const struct Settings_*);
|
typedef Process*(*Process_New)(const struct Settings_*);
|
||||||
typedef void (*Process_WriteField)(const Process*, RichString*, ProcessField);
|
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 const char* (*Process_GetCommandStr)(const Process*);
|
||||||
|
|
||||||
typedef struct ProcessClass_ {
|
typedef struct ProcessClass_ {
|
||||||
const ObjectClass super;
|
const ObjectClass super;
|
||||||
const Process_WriteField writeField;
|
const Process_WriteField writeField;
|
||||||
|
const Process_CompareByKey compareByKey;
|
||||||
const Process_GetCommandStr getCommandStr;
|
const Process_GetCommandStr getCommandStr;
|
||||||
} ProcessClass;
|
} 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) {
|
static inline pid_t Process_getParentPid(const Process* this) {
|
||||||
return this->tgid == this->pid ? this->ppid : this->tgid;
|
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_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_display(const Object* cast, RichString* out);
|
||||||
|
|
||||||
void Process_done(Process* this);
|
void Process_done(Process* this);
|
||||||
@ -198,6 +201,8 @@ bool Process_changePriorityBy(Process* this, Arg delta);
|
|||||||
|
|
||||||
bool Process_sendSignal(Process* this, Arg sgn);
|
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
|
#endif
|
||||||
|
@ -10,8 +10,8 @@ in the source distribution for its full text.
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
|
#include "Compat.h"
|
||||||
#include "CRT.h"
|
#include "CRT.h"
|
||||||
#include "Hashtable.h"
|
#include "Hashtable.h"
|
||||||
#include "Macros.h"
|
#include "Macros.h"
|
||||||
@ -79,22 +79,48 @@ void ProcessList_setPanel(ProcessList* this, Panel* panel) {
|
|||||||
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) {
|
void ProcessList_printHeader(ProcessList* this, RichString* header) {
|
||||||
RichString_prune(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++) {
|
for (int i = 0; fields[i]; i++) {
|
||||||
const char* field = Process_fields[fields[i]].title;
|
int color;
|
||||||
if (!field) {
|
if (settings->treeView && settings->treeViewAlwaysByPID) {
|
||||||
field = "- ";
|
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]) ?
|
RichString_appendWide(header, color, alignedProcessFieldTitle(fields[i]));
|
||||||
CRT_colors[PANEL_SELECTION_FOCUS] : CRT_colors[PANEL_HEADER_FOCUS];
|
if (key == fields[i] && RichString_getCharVal(*header, RichString_size(header) - 1) == ' ') {
|
||||||
RichString_append(header, color, field);
|
header->chlen--; // rewind to override space
|
||||||
if (COMM == fields[i] && this->settings->showMergedCommand) {
|
RichString_appendnWide(header,
|
||||||
RichString_append(header, color, "(merged)");
|
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);
|
Process* pp = Hashtable_remove(this->processTable, p->pid);
|
||||||
assert(pp == p); (void)pp;
|
assert(pp == p); (void)pp;
|
||||||
|
|
||||||
unsigned int pid = p->pid;
|
pid_t pid = p->pid;
|
||||||
int idx = Vector_indexOf(this->processes, p, Process_pidCompare);
|
int idx = Vector_indexOf(this->processes, p, Process_pidCompare);
|
||||||
assert(idx != -1);
|
assert(idx != -1);
|
||||||
|
|
||||||
@ -130,7 +156,12 @@ void ProcessList_remove(ProcessList* this, Process* p) {
|
|||||||
Vector_remove(this->processes, idx);
|
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));
|
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`,
|
// The algorithm is based on `depth-first search`,
|
||||||
// even though `breadth-first search` approach may be more efficient on first glance,
|
// 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.
|
// 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.
|
// 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);
|
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 *p1 = (const Process*)v1;
|
||||||
const Process *p2 = (const Process*)v2;
|
const Process *p2 = (const Process*)v2;
|
||||||
|
|
||||||
return SPACESHIP_NUMBER(p1->tree_left, p2->tree_left);
|
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 *p1 = (const Process*)v1;
|
||||||
const Process *p2 = (const Process*)v2;
|
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) {
|
static void ProcessList_buildTree(ProcessList* this) {
|
||||||
int node_counter = 1;
|
int node_counter = 1;
|
||||||
int node_index = 0;
|
int node_index = 0;
|
||||||
int direction = this->settings->direction;
|
int direction = Settings_getActiveDirection(this->settings);
|
||||||
|
|
||||||
// Sort by PID
|
// Sort by PID
|
||||||
Vector_quickSortCustomCompare(this->processes, ProcessList_treeProcessCompareByPID);
|
Vector_quickSortCustomCompare(this->processes, ProcessList_treeProcessCompareByPID);
|
||||||
@ -446,12 +477,7 @@ ProcessField ProcessList_keyAt(const ProcessList* this, int at) {
|
|||||||
const ProcessField* fields = this->settings->fields;
|
const ProcessField* fields = this->settings->fields;
|
||||||
ProcessField field;
|
ProcessField field;
|
||||||
for (int i = 0; (field = fields[i]); i++) {
|
for (int i = 0; (field = fields[i]); i++) {
|
||||||
const char* title = Process_fields[field].title;
|
int len = strlen(alignedProcessFieldTitle(field));
|
||||||
if (!title) {
|
|
||||||
title = "- ";
|
|
||||||
}
|
|
||||||
|
|
||||||
int len = strlen(title);
|
|
||||||
if (at >= x && at <= x + len) {
|
if (at >= x && at <= x + len) {
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
@ -472,30 +498,26 @@ void ProcessList_rebuildPanel(ProcessList* this) {
|
|||||||
const char* incFilter = this->incFilter;
|
const char* incFilter = this->incFilter;
|
||||||
|
|
||||||
int currPos = Panel_getSelectedIndex(this->panel);
|
int currPos = Panel_getSelectedIndex(this->panel);
|
||||||
pid_t currPid = this->following != -1 ? this->following : 0;
|
|
||||||
int currScrollV = this->panel->scrollV;
|
int currScrollV = this->panel->scrollV;
|
||||||
|
|
||||||
Panel_prune(this->panel);
|
Panel_prune(this->panel);
|
||||||
int size = ProcessList_size(this);
|
int size = ProcessList_size(this);
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
bool hidden = false;
|
|
||||||
Process* p = ProcessList_get(this, i);
|
Process* p = ProcessList_get(this, i);
|
||||||
|
|
||||||
if ( (!p->show)
|
if ( (!p->show)
|
||||||
|| (this->userId != (uid_t) -1 && (p->st_uid != this->userId))
|
|| (this->userId != (uid_t) -1 && (p->st_uid != this->userId))
|
||||||
|| (incFilter && !(String_contains_i(Process_getCommand(p), incFilter)))
|
|| (incFilter && !(String_contains_i(Process_getCommand(p), incFilter)))
|
||||||
|| (this->pidMatchList && !Hashtable_get(this->pidMatchList, p->tgid)) )
|
|| (this->pidMatchList && !Hashtable_get(this->pidMatchList, p->tgid)) )
|
||||||
hidden = true;
|
continue;
|
||||||
|
|
||||||
if (!hidden) {
|
Panel_set(this->panel, idx, (Object*)p);
|
||||||
Panel_set(this->panel, idx, (Object*)p);
|
if ((this->following == -1 && idx == currPos) || (this->following != -1 && p->pid == this->following)) {
|
||||||
if ((this->following == -1 && idx == currPos) || (this->following != -1 && p->pid == currPid)) {
|
Panel_setSelected(this->panel, idx);
|
||||||
Panel_setSelected(this->panel, idx);
|
this->panel->scrollV = currScrollV;
|
||||||
this->panel->scrollV = currScrollV;
|
|
||||||
}
|
|
||||||
idx++;
|
|
||||||
}
|
}
|
||||||
|
idx++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,8 +563,10 @@ void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate) {
|
|||||||
if (!firstScanDone) {
|
if (!firstScanDone) {
|
||||||
this->scanTs = 0;
|
this->scanTs = 0;
|
||||||
firstScanDone = true;
|
firstScanDone = true;
|
||||||
} else if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) {
|
} else if (Compat_clock_monotonic_gettime(&now) == 0) {
|
||||||
this->scanTs = now.tv_sec;
|
// 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);
|
ProcessList_goThroughEntries(this, false);
|
||||||
@ -558,7 +582,7 @@ void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate) {
|
|||||||
// process no longer exists
|
// process no longer exists
|
||||||
if (this->settings->highlightChanges && p->wasShown) {
|
if (this->settings->highlightChanges && p->wasShown) {
|
||||||
// mark tombed
|
// mark tombed
|
||||||
p->tombTs = this->scanTs + this->settings->highlightDelaySecs;
|
p->tombTs = this->scanTs + 1000 * this->settings->highlightDelaySecs;
|
||||||
} else {
|
} else {
|
||||||
// immediately remove
|
// immediately remove
|
||||||
ProcessList_remove(this, p);
|
ProcessList_remove(this, p);
|
||||||
|
@ -27,7 +27,7 @@ ProcessLocksScreen* ProcessLocksScreen_new(const Process* process) {
|
|||||||
this->pid = process->tgid;
|
this->pid = process->tgid;
|
||||||
else
|
else
|
||||||
this->pid = process->pid;
|
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) {
|
void ProcessLocksScreen_delete(Object* this) {
|
||||||
|
73
RichString.c
73
RichString.c
@ -7,6 +7,7 @@ in the source distribution for its full text.
|
|||||||
|
|
||||||
#include "RichString.h"
|
#include "RichString.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -47,25 +48,35 @@ static void RichString_setLen(RichString* this, int len) {
|
|||||||
|
|
||||||
#ifdef HAVE_LIBNCURSESW
|
#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];
|
wchar_t data[len + 1];
|
||||||
len = mbstowcs(data, data_c, len);
|
len = mbstowcs(data, data_c, len);
|
||||||
if (len < 0)
|
if (len <= 0)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
int newLen = from + len;
|
int newLen = from + len;
|
||||||
RichString_setLen(this, newLen);
|
RichString_setLen(this, newLen);
|
||||||
for (int i = from, j = 0; i < newLen; i++, j++) {
|
for (int i = from, j = 0; i < newLen; i++, j++) {
|
||||||
this->chptr[i] = (CharType) { .attr = attrs & 0xffffff, .chars = { (iswprint(data[j]) ? data[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) {
|
static inline int RichString_writeFromAscii(RichString* this, int attrs, const char* data, int from, int len) {
|
||||||
cchar_t* ch = this->chptr + start;
|
int newLen = from + len;
|
||||||
finish = CLAMP(finish, 0, this->chlen - 1);
|
RichString_setLen(this, newLen);
|
||||||
for (int i = start; i <= finish; i++) {
|
for (int i = from, j = 0; i < newLen; i++, j++) {
|
||||||
ch->attr = attrs;
|
this->chptr[i] = (CharType) { .attr = attrs & 0xffffff, .chars = { (isprint(data[j]) ? data[j] : '?') } };
|
||||||
ch++;
|
}
|
||||||
|
|
||||||
|
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 */
|
#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;
|
int newLen = from + len;
|
||||||
RichString_setLen(this, newLen);
|
RichString_setLen(this, newLen);
|
||||||
for (int i = from, j = 0; i < newLen; i++, j++) {
|
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[i] = (((unsigned char)data_c[j]) >= 32 ? ((unsigned char)data_c[j]) : '?') | attrs;
|
||||||
}
|
}
|
||||||
this->chptr[newLen] = 0;
|
this->chptr[newLen] = 0;
|
||||||
|
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RichString_setAttrn(RichString* this, int attrs, int start, int finish) {
|
static inline int RichString_writeFromAscii(RichString* this, int attrs, const char* data_c, int from, int len) {
|
||||||
chtype* ch = this->chptr + start;
|
return RichString_writeFromWide(this, attrs, data_c, from, len);
|
||||||
finish = CLAMP(finish, 0, this->chlen - 1);
|
}
|
||||||
for (int i = start; i <= finish; i++) {
|
|
||||||
*ch = (*ch & 0xff) | attrs;
|
void RichString_setAttrn(RichString* this, int attrs, int start, int charcount) {
|
||||||
ch++;
|
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) {
|
void RichString_setAttr(RichString* this, int attrs) {
|
||||||
RichString_setAttrn(this, attrs, 0, this->chlen - 1);
|
RichString_setAttrn(this, attrs, 0, this->chlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RichString_append(RichString* this, int attrs, const char* data) {
|
int RichString_appendWide(RichString* this, int attrs, const char* data) {
|
||||||
RichString_writeFrom(this, attrs, data, this->chlen, strlen(data));
|
return RichString_writeFromWide(this, attrs, data, this->chlen, strlen(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) {
|
||||||
RichString_writeFrom(this, attrs, data, this->chlen, len);
|
return RichString_writeFromWide(this, attrs, data, this->chlen, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RichString_write(RichString* this, int attrs, const char* data) {
|
int RichString_writeWide(RichString* this, int attrs, const char* data) {
|
||||||
RichString_writeFrom(this, attrs, data, 0, strlen(data));
|
return RichString_writeFromWide(this, attrs, data, 0, strlen(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
int RichString_appendAscii(RichString* this, int attrs, const char* data) {
|
||||||
|
return RichString_writeFromAscii(this, attrs, data, this->chlen, strlen(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
int RichString_appendnAscii(RichString* this, int attrs, const char* data, int len) {
|
||||||
|
return RichString_writeFromAscii(this, attrs, data, this->chlen, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int RichString_writeAscii(RichString* this, int attrs, const char* data) {
|
||||||
|
return RichString_writeFromAscii(this, attrs, data, 0, strlen(data));
|
||||||
}
|
}
|
||||||
|
14
RichString.h
14
RichString.h
@ -42,7 +42,7 @@ typedef struct RichString_ {
|
|||||||
int highlightAttr;
|
int highlightAttr;
|
||||||
} RichString;
|
} 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);
|
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_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
|
#endif
|
||||||
|
@ -106,7 +106,7 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi
|
|||||||
if (*rescan) {
|
if (*rescan) {
|
||||||
*oldTime = newTime;
|
*oldTime = newTime;
|
||||||
ProcessList_scan(pl, this->state->pauseProcessUpdate);
|
ProcessList_scan(pl, this->state->pauseProcessUpdate);
|
||||||
if (*sortTimeout == 0 || this->settings->treeView) {
|
if (!this->state->pauseProcessUpdate && (*sortTimeout == 0 || this->settings->treeView)) {
|
||||||
ProcessList_sort(pl);
|
ProcessList_sort(pl);
|
||||||
*sortTimeout = 1;
|
*sortTimeout = 1;
|
||||||
}
|
}
|
||||||
@ -119,29 +119,20 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi
|
|||||||
*rescan = false;
|
*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;
|
const int nPanels = this->panelCount;
|
||||||
for (int i = 0; i < nPanels; i++) {
|
for (int i = 0; i < nPanels; i++) {
|
||||||
Panel* panel = (Panel*) Vector_get(this->panels, i);
|
Panel* panel = (Panel*) Vector_get(this->panels, i);
|
||||||
Panel_draw(panel, i == focus, !((panel == this->state->panel) && this->state->hideProcessSelection));
|
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 + 1);
|
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) {
|
void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
|
||||||
bool quit = false;
|
bool quit = false;
|
||||||
int focus = 0;
|
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;
|
double oldTime = 0.0;
|
||||||
|
|
||||||
@ -150,6 +141,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
|
|||||||
|
|
||||||
bool timedOut = true;
|
bool timedOut = true;
|
||||||
bool redraw = true;
|
bool redraw = true;
|
||||||
|
bool force_redraw = true;
|
||||||
bool rescan = false;
|
bool rescan = false;
|
||||||
int sortTimeout = 0;
|
int sortTimeout = 0;
|
||||||
int resetSortTimeout = 5;
|
int resetSortTimeout = 5;
|
||||||
@ -159,8 +151,9 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
|
|||||||
checkRecalculation(this, &oldTime, &sortTimeout, &redraw, &rescan, &timedOut);
|
checkRecalculation(this, &oldTime, &sortTimeout, &redraw, &rescan, &timedOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (redraw) {
|
if (redraw || force_redraw) {
|
||||||
ScreenManager_drawPanels(this, focus);
|
ScreenManager_drawPanels(this, focus, force_redraw);
|
||||||
|
force_redraw = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int prevCh = ch;
|
int prevCh = ch;
|
||||||
@ -187,7 +180,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
|
|||||||
ch = KEY_MOUSE;
|
ch = KEY_MOUSE;
|
||||||
if (panel == panelFocus || this->allowFocusChange) {
|
if (panel == panelFocus || this->allowFocusChange) {
|
||||||
focus = i;
|
focus = i;
|
||||||
panelFocus = setCurrentPanel(this, panel);
|
panelFocus = panel;
|
||||||
Object* oldSelection = Panel_getSelected(panel);
|
Object* oldSelection = Panel_getSelected(panel);
|
||||||
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
|
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
|
||||||
if (Panel_getSelected(panel) == oldSelection) {
|
if (Panel_getSelected(panel) == oldSelection) {
|
||||||
@ -234,9 +227,12 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
|
|||||||
if (result & SYNTH_KEY) {
|
if (result & SYNTH_KEY) {
|
||||||
ch = result >> 16;
|
ch = result >> 16;
|
||||||
}
|
}
|
||||||
if (result & REDRAW) {
|
if (result & REFRESH) {
|
||||||
sortTimeout = 0;
|
sortTimeout = 0;
|
||||||
}
|
}
|
||||||
|
if (result & REDRAW) {
|
||||||
|
force_redraw = true;
|
||||||
|
}
|
||||||
if (result & RESCAN) {
|
if (result & RESCAN) {
|
||||||
rescan = true;
|
rescan = true;
|
||||||
sortTimeout = 0;
|
sortTimeout = 0;
|
||||||
@ -269,7 +265,7 @@ tryLeft:
|
|||||||
focus--;
|
focus--;
|
||||||
}
|
}
|
||||||
|
|
||||||
panelFocus = setCurrentPanel(this, (Panel*) Vector_get(this->panels, focus));
|
panelFocus = (Panel*) Vector_get(this->panels, focus);
|
||||||
if (Panel_size(panelFocus) == 0 && focus > 0) {
|
if (Panel_size(panelFocus) == 0 && focus > 0) {
|
||||||
goto tryLeft;
|
goto tryLeft;
|
||||||
}
|
}
|
||||||
@ -290,7 +286,7 @@ tryRight:
|
|||||||
focus++;
|
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) {
|
if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1) {
|
||||||
goto tryRight;
|
goto tryRight;
|
||||||
}
|
}
|
||||||
|
38
Settings.c
38
Settings.c
@ -96,10 +96,10 @@ static void readFields(ProcessField* fields, uint32_t* flags, const char* line)
|
|||||||
free(trim);
|
free(trim);
|
||||||
int i, j;
|
int i, j;
|
||||||
*flags = 0;
|
*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.
|
// This "+1" is for compatibility with the older enum format.
|
||||||
int id = atoi(ids[i]) + 1;
|
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;
|
fields[j] = id;
|
||||||
*flags |= Process_fields[id].flags;
|
*flags |= Process_fields[id].flags;
|
||||||
j++;
|
j++;
|
||||||
@ -137,10 +137,17 @@ static bool Settings_read(Settings* this, const char* fileName, int initialCpuCo
|
|||||||
} else if (String_eq(option[0], "sort_key")) {
|
} else if (String_eq(option[0], "sort_key")) {
|
||||||
// This "+1" is for compatibility with the older enum format.
|
// This "+1" is for compatibility with the older enum format.
|
||||||
this->sortKey = atoi(option[1]) + 1;
|
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")) {
|
} else if (String_eq(option[0], "sort_direction")) {
|
||||||
this->direction = atoi(option[1]);
|
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")) {
|
} else if (String_eq(option[0], "tree_view")) {
|
||||||
this->treeView = atoi(option[1]);
|
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")) {
|
} else if (String_eq(option[0], "hide_kernel_threads")) {
|
||||||
this->hideKernelThreads = atoi(option[1]);
|
this->hideKernelThreads = atoi(option[1]);
|
||||||
} else if (String_eq(option[0], "hide_userland_threads")) {
|
} 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")) {
|
} else if (String_eq(option[0], "right_meter_modes")) {
|
||||||
Settings_readMeterModes(this, option[1], 1);
|
Settings_readMeterModes(this, option[1], 1);
|
||||||
didReadMeters = true;
|
didReadMeters = true;
|
||||||
|
} else if (String_eq(option[0], "hide_function_bar")) {
|
||||||
|
this->hideFunctionBar = atoi(option[1]);
|
||||||
#ifdef HAVE_LIBHWLOC
|
#ifdef HAVE_LIBHWLOC
|
||||||
} else if (String_eq(option[0], "topology_affinity")) {
|
} else if (String_eq(option[0], "topology_affinity")) {
|
||||||
this->topologyAffinity = !!atoi(option[1]);
|
this->topologyAffinity = !!atoi(option[1]);
|
||||||
@ -273,6 +282,8 @@ bool Settings_write(Settings* this) {
|
|||||||
// This "-1" is for compatibility with the older enum format.
|
// This "-1" is for compatibility with the older enum format.
|
||||||
fprintf(fd, "sort_key=%d\n", (int) this->sortKey - 1);
|
fprintf(fd, "sort_key=%d\n", (int) this->sortKey - 1);
|
||||||
fprintf(fd, "sort_direction=%d\n", (int) this->direction);
|
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_kernel_threads=%d\n", (int) this->hideKernelThreads);
|
||||||
fprintf(fd, "hide_userland_threads=%d\n", (int) this->hideUserlandThreads);
|
fprintf(fd, "hide_userland_threads=%d\n", (int) this->hideUserlandThreads);
|
||||||
fprintf(fd, "shadow_other_users=%d\n", (int) this->shadowOtherUsers);
|
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, "strip_exe_from_cmdline=%d\n", (int) this->stripExeFromCmdline);
|
||||||
fprintf(fd, "show_merged_command=%d\n", (int) this->showMergedCommand);
|
fprintf(fd, "show_merged_command=%d\n", (int) this->showMergedCommand);
|
||||||
fprintf(fd, "tree_view=%d\n", (int) this->treeView);
|
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, "header_margin=%d\n", (int) this->headerMargin);
|
||||||
fprintf(fd, "detailed_cpu_time=%d\n", (int) this->detailedCPUTime);
|
fprintf(fd, "detailed_cpu_time=%d\n", (int) this->detailedCPUTime);
|
||||||
fprintf(fd, "cpu_count_from_one=%d\n", (int) this->countCPUsFromOne);
|
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, "left_meter_modes="); writeMeterModes(this, fd, 0);
|
||||||
fprintf(fd, "right_meters="); writeMeters(this, fd, 1);
|
fprintf(fd, "right_meters="); writeMeters(this, fd, 1);
|
||||||
fprintf(fd, "right_meter_modes="); writeMeterModes(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
|
#ifdef HAVE_LIBHWLOC
|
||||||
fprintf(fd, "topology_affinity=%d\n", (int) this->topologyAffinity);
|
fprintf(fd, "topology_affinity=%d\n", (int) this->topologyAffinity);
|
||||||
#endif
|
#endif
|
||||||
@ -316,7 +329,9 @@ Settings* Settings_new(int initialCpuCount) {
|
|||||||
Settings* this = xCalloc(1, sizeof(Settings));
|
Settings* this = xCalloc(1, sizeof(Settings));
|
||||||
|
|
||||||
this->sortKey = PERCENT_CPU;
|
this->sortKey = PERCENT_CPU;
|
||||||
|
this->treeSortKey = PID;
|
||||||
this->direction = 1;
|
this->direction = 1;
|
||||||
|
this->treeDirection = 1;
|
||||||
this->shadowOtherUsers = false;
|
this->shadowOtherUsers = false;
|
||||||
this->showThreadNames = false;
|
this->showThreadNames = false;
|
||||||
this->hideKernelThreads = false;
|
this->hideKernelThreads = false;
|
||||||
@ -340,14 +355,15 @@ Settings* Settings_new(int initialCpuCount) {
|
|||||||
this->findCommInCmdline = true;
|
this->findCommInCmdline = true;
|
||||||
this->stripExeFromCmdline = true;
|
this->stripExeFromCmdline = true;
|
||||||
this->showMergedCommand = false;
|
this->showMergedCommand = false;
|
||||||
|
this->hideFunctionBar = 0;
|
||||||
#ifdef HAVE_LIBHWLOC
|
#ifdef HAVE_LIBHWLOC
|
||||||
this->topologyAffinity = false;
|
this->topologyAffinity = false;
|
||||||
#endif
|
#endif
|
||||||
this->fields = xCalloc(Platform_numberOfFields + 1, sizeof(ProcessField));
|
this->fields = xCalloc(LAST_PROCESSFIELD + 1, sizeof(ProcessField));
|
||||||
// TODO: turn 'fields' into a Vector,
|
// TODO: turn 'fields' into a Vector,
|
||||||
// (and ProcessFields into proper objects).
|
// (and ProcessFields into proper objects).
|
||||||
this->flags = 0;
|
this->flags = 0;
|
||||||
ProcessField* defaults = Platform_defaultFields;
|
const ProcessField* defaults = Platform_defaultFields;
|
||||||
for (int i = 0; defaults[i]; i++) {
|
for (int i = 0; defaults[i]; i++) {
|
||||||
this->fields[i] = defaults[i];
|
this->fields[i] = defaults[i];
|
||||||
this->flags |= Process_fields[defaults[i]].flags;
|
this->flags |= Process_fields[defaults[i]].flags;
|
||||||
@ -427,9 +443,17 @@ Settings* Settings_new(int initialCpuCount) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Settings_invertSortOrder(Settings* this) {
|
void Settings_invertSortOrder(Settings* this) {
|
||||||
if (this->direction == 1) {
|
int* attr = (this->treeView) ? &(this->treeDirection) : &(this->direction);
|
||||||
this->direction = -1;
|
*attr = (*attr == 1) ? -1 : 1;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
void Settings_setSortKey(Settings* this, ProcessField sortKey) {
|
||||||
|
if (this->treeViewAlwaysByPID || !this->treeView) {
|
||||||
|
this->sortKey = sortKey;
|
||||||
this->direction = 1;
|
this->direction = 1;
|
||||||
|
this->treeView = false;
|
||||||
|
} else {
|
||||||
|
this->treeSortKey = sortKey;
|
||||||
|
this->treeDirection = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
Settings.h
16
Settings.h
@ -33,7 +33,9 @@ typedef struct Settings_ {
|
|||||||
int delay;
|
int delay;
|
||||||
|
|
||||||
int direction;
|
int direction;
|
||||||
|
int treeDirection;
|
||||||
ProcessField sortKey;
|
ProcessField sortKey;
|
||||||
|
ProcessField treeSortKey;
|
||||||
|
|
||||||
bool countCPUsFromOne;
|
bool countCPUsFromOne;
|
||||||
bool detailedCPUTime;
|
bool detailedCPUTime;
|
||||||
@ -44,6 +46,7 @@ typedef struct Settings_ {
|
|||||||
bool degreeFahrenheit;
|
bool degreeFahrenheit;
|
||||||
#endif
|
#endif
|
||||||
bool treeView;
|
bool treeView;
|
||||||
|
bool treeViewAlwaysByPID;
|
||||||
bool showProgramPath;
|
bool showProgramPath;
|
||||||
bool shadowOtherUsers;
|
bool shadowOtherUsers;
|
||||||
bool showThreadNames;
|
bool showThreadNames;
|
||||||
@ -61,6 +64,7 @@ typedef struct Settings_ {
|
|||||||
bool accountGuestInCPUMeter;
|
bool accountGuestInCPUMeter;
|
||||||
bool headerMargin;
|
bool headerMargin;
|
||||||
bool enableMouse;
|
bool enableMouse;
|
||||||
|
int hideFunctionBar; // 0 - off, 1 - on ESC until next input, 2 - permanently
|
||||||
#ifdef HAVE_LIBHWLOC
|
#ifdef HAVE_LIBHWLOC
|
||||||
bool topologyAffinity;
|
bool topologyAffinity;
|
||||||
#endif
|
#endif
|
||||||
@ -70,6 +74,16 @@ typedef struct Settings_ {
|
|||||||
|
|
||||||
#define Settings_cpuId(settings, cpu) ((settings)->countCPUsFromOne ? (cpu)+1 : (cpu))
|
#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);
|
void Settings_delete(Settings* this);
|
||||||
|
|
||||||
bool Settings_write(Settings* this);
|
bool Settings_write(Settings* this);
|
||||||
@ -78,4 +92,6 @@ Settings* Settings_new(int initialCpuCount);
|
|||||||
|
|
||||||
void Settings_invertSortOrder(Settings* this);
|
void Settings_invertSortOrder(Settings* this);
|
||||||
|
|
||||||
|
void Settings_setSortKey(Settings* this, ProcessField sortKey);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -19,7 +19,7 @@ in the source distribution for its full text.
|
|||||||
|
|
||||||
|
|
||||||
Panel* SignalsPanel_new() {
|
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;
|
const int defaultSignal = SIGTERM;
|
||||||
int defaultPosition = 15;
|
int defaultPosition = 15;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
12
SwapMeter.c
12
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) {
|
static void SwapMeter_display(const Object* cast, RichString* out) {
|
||||||
char buffer[50];
|
char buffer[50];
|
||||||
const Meter* this = (const Meter*)cast;
|
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, 50);
|
Meter_humanUnit(buffer, this->total, sizeof(buffer));
|
||||||
RichString_append(out, CRT_colors[METER_VALUE], buffer);
|
RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
|
||||||
Meter_humanUnit(buffer, this->values[0], 50);
|
Meter_humanUnit(buffer, this->values[0], sizeof(buffer));
|
||||||
RichString_append(out, CRT_colors[METER_TEXT], " used:");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], " used:");
|
||||||
RichString_append(out, CRT_colors[METER_VALUE], buffer);
|
RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MeterClass SwapMeter_class = {
|
const MeterClass SwapMeter_class = {
|
||||||
|
20
TasksMeter.c
20
TasksMeter.c
@ -46,7 +46,7 @@ static void TasksMeter_display(const Object* cast, RichString* out) {
|
|||||||
int processes = (int) this->values[2];
|
int processes = (int) this->values[2];
|
||||||
|
|
||||||
xSnprintf(buffer, sizeof(buffer), "%d", processes);
|
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 threadValueColor = CRT_colors[METER_VALUE];
|
||||||
int threadCaptionColor = CRT_colors[METER_TEXT];
|
int threadCaptionColor = CRT_colors[METER_TEXT];
|
||||||
if (settings->highlightThreads) {
|
if (settings->highlightThreads) {
|
||||||
@ -54,21 +54,21 @@ static void TasksMeter_display(const Object* cast, RichString* out) {
|
|||||||
threadCaptionColor = CRT_colors[PROCESS_THREAD];
|
threadCaptionColor = CRT_colors[PROCESS_THREAD];
|
||||||
}
|
}
|
||||||
if (!settings->hideUserlandThreads) {
|
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]);
|
xSnprintf(buffer, sizeof(buffer), "%d", (int)this->values[1]);
|
||||||
RichString_append(out, threadValueColor, buffer);
|
RichString_appendAscii(out, threadValueColor, buffer);
|
||||||
RichString_append(out, threadCaptionColor, " thr");
|
RichString_appendAscii(out, threadCaptionColor, " thr");
|
||||||
}
|
}
|
||||||
if (!settings->hideKernelThreads) {
|
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]);
|
xSnprintf(buffer, sizeof(buffer), "%d", (int)this->values[0]);
|
||||||
RichString_append(out, threadValueColor, buffer);
|
RichString_appendAscii(out, threadValueColor, buffer);
|
||||||
RichString_append(out, threadCaptionColor, " kthr");
|
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]);
|
xSnprintf(buffer, sizeof(buffer), "%d", (int)this->values[3]);
|
||||||
RichString_append(out, CRT_colors[TASKS_RUNNING], buffer);
|
RichString_appendAscii(out, CRT_colors[TASKS_RUNNING], buffer);
|
||||||
RichString_append(out, CRT_colors[METER_TEXT], " running");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], " running");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MeterClass TasksMeter_class = {
|
const MeterClass TasksMeter_class = {
|
||||||
|
@ -33,17 +33,7 @@ static const char* const TraceScreenFunctions[] = {"Search ", "Filter ", "AutoSc
|
|||||||
|
|
||||||
static const char* const TraceScreenKeys[] = {"F3", "F4", "F8", "F9", "Esc"};
|
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};
|
static const 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,
|
|
||||||
};
|
|
||||||
|
|
||||||
TraceScreen* TraceScreen_new(Process* process) {
|
TraceScreen* TraceScreen_new(Process* process) {
|
||||||
// This initializes all TraceScreen variables to "false" so only default = true ones need to be set below
|
// 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));
|
free(InfoScreen_done((InfoScreen*)this));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceScreen_draw(InfoScreen* this) {
|
static void TraceScreen_draw(InfoScreen* this) {
|
||||||
attrset(CRT_colors[PANEL_HEADER_FOCUS]);
|
InfoScreen_drawTitled(this, "Trace of process %d - %s", this->process->pid, Process_getCommand(this->process));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TraceScreen_forkTracer(TraceScreen* this) {
|
bool TraceScreen_forkTracer(TraceScreen* this) {
|
||||||
@ -131,7 +117,7 @@ err:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceScreen_updateTrace(InfoScreen* super) {
|
static void TraceScreen_updateTrace(InfoScreen* super) {
|
||||||
TraceScreen* this = (TraceScreen*) super;
|
TraceScreen* this = (TraceScreen*) super;
|
||||||
char buffer[1025];
|
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;
|
TraceScreen* this = (TraceScreen*) super;
|
||||||
switch(ch) {
|
switch(ch) {
|
||||||
case 'f':
|
case 'f':
|
||||||
@ -195,3 +181,13 @@ bool TraceScreen_onKey(InfoScreen* super, int ch) {
|
|||||||
this->follow = false;
|
this->follow = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const InfoScreenClass TraceScreen_class = {
|
||||||
|
.super = {
|
||||||
|
.extends = Class(Object),
|
||||||
|
.delete = TraceScreen_delete
|
||||||
|
},
|
||||||
|
.draw = TraceScreen_draw,
|
||||||
|
.onErr = TraceScreen_updateTrace,
|
||||||
|
.onKey = TraceScreen_onKey,
|
||||||
|
};
|
||||||
|
@ -32,12 +32,6 @@ TraceScreen* TraceScreen_new(Process* process);
|
|||||||
|
|
||||||
void TraceScreen_delete(Object* cast);
|
void TraceScreen_delete(Object* cast);
|
||||||
|
|
||||||
void TraceScreen_draw(InfoScreen* this);
|
|
||||||
|
|
||||||
bool TraceScreen_forkTracer(TraceScreen* this);
|
bool TraceScreen_forkTracer(TraceScreen* this);
|
||||||
|
|
||||||
void TraceScreen_updateTrace(InfoScreen* super);
|
|
||||||
|
|
||||||
bool TraceScreen_onKey(InfoScreen* super, int ch);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
2
Vector.h
2
Vector.h
@ -58,7 +58,7 @@ unsigned int Vector_count(const Vector* this);
|
|||||||
|
|
||||||
#else /* NDEBUG */
|
#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];
|
return this->array[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
22
XUtils.c
22
XUtils.c
@ -13,6 +13,7 @@ in the source distribution for its full text.
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -36,9 +37,21 @@ void* xMalloc(size_t size) {
|
|||||||
return data;
|
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) {
|
void* xCalloc(size_t nmemb, size_t size) {
|
||||||
assert(nmemb > 0);
|
assert(nmemb > 0);
|
||||||
assert(size > 0);
|
assert(size > 0);
|
||||||
|
if (SIZE_MAX / nmemb < size) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
void* data = calloc(nmemb, size);
|
void* data = calloc(nmemb, size);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
fail();
|
fail();
|
||||||
@ -56,6 +69,15 @@ void* xRealloc(void* ptr, size_t size) {
|
|||||||
return data;
|
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) {
|
char* String_cat(const char* s1, const char* s2) {
|
||||||
const size_t l1 = strlen(s1);
|
const size_t l1 = strlen(s1);
|
||||||
const size_t l2 = strlen(s2);
|
const size_t l2 = strlen(s2);
|
||||||
|
4
XUtils.h
4
XUtils.h
@ -23,10 +23,14 @@ void fail(void) ATTR_NORETURN;
|
|||||||
|
|
||||||
void* xMalloc(size_t size);
|
void* xMalloc(size_t size);
|
||||||
|
|
||||||
|
void* xMallocArray(size_t nmemb, size_t size);
|
||||||
|
|
||||||
void* xCalloc(size_t nmemb, size_t size);
|
void* xCalloc(size_t nmemb, size_t size);
|
||||||
|
|
||||||
void* xRealloc(void* ptr, 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
|
* String_startsWith gives better performance if strlen(match) can be computed
|
||||||
* at compile time (e.g. when they are immutable string literals). :)
|
* at compile time (e.g. when they are immutable string literals). :)
|
||||||
|
68
configure.ac
68
configure.ac
@ -2,7 +2,7 @@
|
|||||||
# Process this file with autoconf to produce a configure script.
|
# Process this file with autoconf to produce a configure script.
|
||||||
|
|
||||||
AC_PREREQ(2.65)
|
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_SRCDIR([htop.c])
|
||||||
AC_CONFIG_AUX_DIR([.])
|
AC_CONFIG_AUX_DIR([.])
|
||||||
@ -93,13 +93,16 @@ AC_TYPE_UINT64_T
|
|||||||
AC_FUNC_CLOSEDIR_VOID
|
AC_FUNC_CLOSEDIR_VOID
|
||||||
AC_FUNC_STAT
|
AC_FUNC_STAT
|
||||||
AC_CHECK_FUNCS([\
|
AC_CHECK_FUNCS([\
|
||||||
|
clock_gettime\
|
||||||
faccessat\
|
faccessat\
|
||||||
fstatat\
|
fstatat\
|
||||||
|
host_get_clock_service\
|
||||||
openat\
|
openat\
|
||||||
readlinkat\
|
readlinkat\
|
||||||
])
|
])
|
||||||
|
|
||||||
AC_SEARCH_LIBS([dlopen], [dl dld])
|
AC_SEARCH_LIBS([dlopen], [dl dld])
|
||||||
|
AC_SEARCH_LIBS([clock_gettime], [rt])
|
||||||
|
|
||||||
save_cflags="${CFLAGS}"
|
save_cflags="${CFLAGS}"
|
||||||
CFLAGS="${CFLAGS} -std=c99"
|
CFLAGS="${CFLAGS} -std=c99"
|
||||||
@ -165,7 +168,7 @@ m4_define([HTOP_CHECK_SCRIPT],
|
|||||||
LIBS="$htop_config_script_libs $LIBS "
|
LIBS="$htop_config_script_libs $LIBS "
|
||||||
htop_script_success=yes
|
htop_script_success=yes
|
||||||
], [
|
], [
|
||||||
CFLAGS="$htop_save_CFLAGS"
|
CFLAGS="$htop_save_CFLAGS"
|
||||||
])
|
])
|
||||||
LDFLAGS="$htop_save_LDFLAGS"
|
LDFLAGS="$htop_save_LDFLAGS"
|
||||||
fi
|
fi
|
||||||
@ -188,15 +191,15 @@ AC_DEFUN([AX_CHECK_COMPILE_FLAG],
|
|||||||
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
|
[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
|
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
|
||||||
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
|
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
|
||||||
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
|
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
|
||||||
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
|
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
|
||||||
AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
|
AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
|
||||||
[AS_VAR_SET(CACHEVAR,[yes])],
|
[AS_VAR_SET(CACHEVAR,[yes])],
|
||||||
[AS_VAR_SET(CACHEVAR,[no])])
|
[AS_VAR_SET(CACHEVAR,[no])])
|
||||||
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
|
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
|
||||||
AS_VAR_IF(CACHEVAR,yes,
|
AS_VAR_IF(CACHEVAR,yes,
|
||||||
[m4_default([$2], :)],
|
[m4_default([$2], :)],
|
||||||
[m4_default([$3], :)])
|
[m4_default([$3], :)])
|
||||||
AS_VAR_POPDEF([CACHEVAR])dnl
|
AS_VAR_POPDEF([CACHEVAR])dnl
|
||||||
])dnl AX_CHECK_COMPILE_FLAGS
|
])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([ncursesw6], [addnwstr], [HAVE_LIBNCURSESW],
|
||||||
HTOP_CHECK_LIB([ncursesw], [addnwstr], [HAVE_LIBNCURSESW],
|
HTOP_CHECK_LIB([ncursesw], [addnwstr], [HAVE_LIBNCURSESW],
|
||||||
HTOP_CHECK_LIB([ncurses], [addnwstr], [HAVE_LIBNCURSESW],
|
HTOP_CHECK_LIB([ncurses], [addnwstr], [HAVE_LIBNCURSESW],
|
||||||
missing_libraries="$missing_libraries libncursesw"
|
missing_libraries="$missing_libraries libncursesw"
|
||||||
AC_MSG_ERROR([You may want to use --disable-unicode or install libncursesw.])
|
AC_MSG_ERROR([You may want to use --disable-unicode or install libncursesw.])
|
||||||
)))))))
|
)))))))
|
||||||
|
|
||||||
AC_CHECK_HEADERS([ncursesw/curses.h],[:],
|
AC_CHECK_HEADERS([ncursesw/curses.h],[:],
|
||||||
[AC_CHECK_HEADERS([ncurses/ncurses.h],[:],
|
[AC_CHECK_HEADERS([ncurses/ncurses.h],[:],
|
||||||
[AC_CHECK_HEADERS([ncurses/curses.h],[:],
|
[AC_CHECK_HEADERS([ncurses/curses.h],[:],
|
||||||
[AC_CHECK_HEADERS([ncurses.h],[:],[missing_headers="$missing_headers $ac_header"])])])])
|
[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
|
else
|
||||||
HTOP_CHECK_SCRIPT([ncurses6], [refresh], [HAVE_LIBNCURSES], "ncurses6-config",
|
HTOP_CHECK_SCRIPT([ncurses6], [refresh], [HAVE_LIBNCURSES], "ncurses6-config",
|
||||||
HTOP_CHECK_SCRIPT([ncurses], [refresh], [HAVE_LIBNCURSES], "ncurses5-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/curses.h],[:],
|
||||||
[AC_CHECK_HEADERS([ncurses/ncurses.h],[:],
|
[AC_CHECK_HEADERS([ncurses/ncurses.h],[:],
|
||||||
[AC_CHECK_HEADERS([ncurses.h],[:],[missing_headers="$missing_headers $ac_header"])])])])
|
[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
|
fi
|
||||||
|
|
||||||
if test "$my_htop_platform" = "freebsd"; then
|
if test "$my_htop_platform" = "freebsd"; then
|
||||||
@ -246,8 +266,7 @@ if test "$my_htop_platform" = "solaris"; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
AC_ARG_ENABLE(hwloc, [AS_HELP_STRING([--enable-hwloc], [enable hwloc support for CPU affinity, disables Linux affinity])],, enable_hwloc="no")
|
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
|
if test "x$enable_hwloc" = xyes; then
|
||||||
then
|
|
||||||
AC_CHECK_LIB([hwloc], [hwloc_get_proc_cpubind], [], [missing_libraries="$missing_libraries libhwloc"])
|
AC_CHECK_LIB([hwloc], [hwloc_get_proc_cpubind], [], [missing_libraries="$missing_libraries libhwloc"])
|
||||||
AC_CHECK_HEADERS([hwloc.h],[:], [missing_headers="$missing_headers $ac_header"])
|
AC_CHECK_HEADERS([hwloc.h],[:], [missing_headers="$missing_headers $ac_header"])
|
||||||
fi
|
fi
|
||||||
@ -269,9 +288,9 @@ if test "x$enable_linux_affinity" = xcheck; then
|
|||||||
if (errno == ENOSYS) return 1;
|
if (errno == ENOSYS) return 1;
|
||||||
]])],
|
]])],
|
||||||
[enable_linux_affinity=yes
|
[enable_linux_affinity=yes
|
||||||
AC_MSG_RESULT([yes])],
|
AC_MSG_RESULT([yes])],
|
||||||
[enable_linux_affinity=no
|
[enable_linux_affinity=no
|
||||||
AC_MSG_RESULT([no])],
|
AC_MSG_RESULT([no])],
|
||||||
[AC_MSG_RESULT([yes (assumed while cross compiling)])])
|
[AC_MSG_RESULT([yes (assumed while cross compiling)])])
|
||||||
fi
|
fi
|
||||||
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.])
|
AC_DEFINE(HAVE_LINUX_AFFINITY, 1, [Define if Linux sched_setaffinity and sched_getaffinity are to be used.])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "x$enable_linux_affinity" = xyes -a "x$enable_hwloc" = xyes
|
if test "x$enable_linux_affinity" = xyes -a "x$enable_hwloc" = xyes; then
|
||||||
then
|
|
||||||
AC_MSG_ERROR([--enable-hwloc and --enable-linux-affinity are mutual exclusive. Specify at most one of them.])
|
AC_MSG_ERROR([--enable-hwloc and --enable-linux-affinity are mutual exclusive. Specify at most one of them.])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_ARG_ENABLE(setuid, [AS_HELP_STRING([--enable-setuid], [enable setuid support for platforms that need it])],, enable_setuid="no")
|
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
|
if test "x$enable_setuid" = xyes; then
|
||||||
then
|
|
||||||
AC_DEFINE(HAVE_SETUID_ENABLED, 1, [Define if setuid support should be enabled.])
|
AC_DEFINE(HAVE_SETUID_ENABLED, 1, [Define if setuid support should be enabled.])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_ARG_ENABLE(delayacct, [AS_HELP_STRING([--enable-delayacct], [enable Linux delay accounting])],, enable_delayacct="no")
|
AC_ARG_ENABLE(delayacct, [AS_HELP_STRING([--enable-delayacct], [enable Linux delay accounting])],, enable_delayacct="no")
|
||||||
if test "x$enable_delayacct" = xyes
|
if test "x$enable_delayacct" = xyes; then
|
||||||
then
|
|
||||||
m4_ifdef([PKG_PROG_PKG_CONFIG], [
|
m4_ifdef([PKG_PROG_PKG_CONFIG], [
|
||||||
PKG_PROG_PKG_CONFIG()
|
PKG_PROG_PKG_CONFIG()
|
||||||
PKG_CHECK_MODULES(LIBNL3, libnl-3.0, [], [missing_libraries="$missing_libraries libnl-3"])
|
PKG_CHECK_MODULES(LIBNL3, libnl-3.0, [], [missing_libraries="$missing_libraries libnl-3"])
|
||||||
@ -321,6 +337,7 @@ AM_CFLAGS="\
|
|||||||
-Wcast-qual\
|
-Wcast-qual\
|
||||||
-Wextra\
|
-Wextra\
|
||||||
-Wfloat-equal\
|
-Wfloat-equal\
|
||||||
|
-Wformat=2\
|
||||||
-Wmissing-format-attribute\
|
-Wmissing-format-attribute\
|
||||||
-Wmissing-noreturn\
|
-Wmissing-noreturn\
|
||||||
-Wmissing-prototypes\
|
-Wmissing-prototypes\
|
||||||
@ -346,10 +363,10 @@ AC_SUBST([AM_CPPFLAGS])
|
|||||||
# Bail out on errors.
|
# Bail out on errors.
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
if test ! -z "$missing_libraries"; then
|
if test ! -z "$missing_libraries"; then
|
||||||
AC_MSG_ERROR([missing libraries: $missing_libraries])
|
AC_MSG_ERROR([missing libraries: $missing_libraries])
|
||||||
fi
|
fi
|
||||||
if test ! -z "$missing_headers"; then
|
if test ! -z "$missing_headers"; then
|
||||||
AC_MSG_ERROR([missing headers: $missing_headers])
|
AC_MSG_ERROR([missing headers: $missing_headers])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_DEFINE_UNQUOTED(COPYRIGHT, "(C) 2004-2019 Hisham Muhammad. (C) 2020 htop dev team.", [Copyright message.])
|
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_CONFIG_FILES([Makefile htop.1])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
||||||
if test "$my_htop_platform" = "unsupported"
|
if test "$my_htop_platform" = "unsupported"; then
|
||||||
then
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "****************************************************************"
|
echo "****************************************************************"
|
||||||
echo "WARNING! This platform is not currently supported by htop."
|
echo "WARNING! This platform is not currently supported by htop."
|
||||||
|
@ -14,17 +14,37 @@ in the source distribution for its full text.
|
|||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
|
|
||||||
#include "CRT.h"
|
#include "CRT.h"
|
||||||
|
#include "Platform.h"
|
||||||
#include "Process.h"
|
#include "Process.h"
|
||||||
|
|
||||||
|
|
||||||
const ProcessClass DarwinProcess_class = {
|
const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
|
||||||
.super = {
|
[0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
|
||||||
.extends = Class(Process),
|
[PID] = { .name = "PID", .title = "PID", .description = "Process/thread ID", .flags = 0, .pidColumn = true, },
|
||||||
.display = Process_display,
|
[COMM] = { .name = "Command", .title = "Command ", .description = "Command line", .flags = 0, },
|
||||||
.delete = Process_delete,
|
[STATE] = { .name = "STATE", .title = "S ", .description = "Process state (S sleeping, R running, D disk, Z zombie, T traced, W paging)", .flags = 0, },
|
||||||
.compare = Process_compare
|
[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, },
|
||||||
.writeField = Process_writeField,
|
[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) {
|
Process* DarwinProcess_new(const Settings* settings) {
|
||||||
@ -35,6 +55,7 @@ Process* DarwinProcess_new(const Settings* settings) {
|
|||||||
this->utime = 0;
|
this->utime = 0;
|
||||||
this->stime = 0;
|
this->stime = 0;
|
||||||
this->taskAccess = true;
|
this->taskAccess = true;
|
||||||
|
this->translated = false;
|
||||||
|
|
||||||
return &this->super;
|
return &this->super;
|
||||||
}
|
}
|
||||||
@ -46,6 +67,34 @@ void Process_delete(Object* cast) {
|
|||||||
free(this);
|
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) {
|
bool Process_isThread(const Process* this) {
|
||||||
(void) this;
|
(void) this;
|
||||||
return false;
|
return false;
|
||||||
@ -195,6 +244,8 @@ ERROR_A:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps, bool exists) {
|
void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps, bool exists) {
|
||||||
|
DarwinProcess* dp = (DarwinProcess*)proc;
|
||||||
|
|
||||||
const struct extern_proc* ep = &ps->kp_proc;
|
const struct extern_proc* ep = &ps->kp_proc;
|
||||||
|
|
||||||
/* UNSET HERE :
|
/* UNSET HERE :
|
||||||
@ -223,6 +274,7 @@ void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps,
|
|||||||
/* e_tdev = (major << 24) | (minor & 0xffffff) */
|
/* e_tdev = (major << 24) | (minor & 0xffffff) */
|
||||||
/* e_tdev == -1 for "no device" */
|
/* e_tdev == -1 for "no device" */
|
||||||
proc->tty_nr = ps->kp_eproc.e_tdev & 0xff; /* TODO tty_nr is unsigned */
|
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;
|
proc->starttime_ctime = ep->p_starttime.tv_sec;
|
||||||
Process_fillStarttimeBuffer(proc);
|
Process_fillStarttimeBuffer(proc);
|
||||||
@ -240,26 +292,24 @@ void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps,
|
|||||||
proc->updated = true;
|
proc->updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList* dpl) {
|
void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList* dpl, double time_interval) {
|
||||||
struct proc_taskinfo pti;
|
struct proc_taskinfo pti;
|
||||||
|
|
||||||
if (sizeof(pti) == proc_pidinfo(proc->super.pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti))) {
|
if (sizeof(pti) == proc_pidinfo(proc->super.pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti))) {
|
||||||
if (0 != proc->utime || 0 != proc->stime) {
|
uint64_t total_existing_time = proc->stime + proc->utime;
|
||||||
uint64_t diff = (pti.pti_total_system - proc->stime)
|
uint64_t total_current_time = pti.pti_total_system + pti.pti_total_user;
|
||||||
+ (pti.pti_total_user - proc->utime);
|
|
||||||
|
|
||||||
proc->super.percent_cpu = (double)diff * (double)dpl->super.cpuCount
|
if (total_existing_time && 1E-6 < time_interval) {
|
||||||
/ ((double)dpl->global_diff * 100000.0);
|
uint64_t total_time_diff = total_current_time - total_existing_time;
|
||||||
|
proc->super.percent_cpu = ((double)total_time_diff / time_interval) * 100.0;
|
||||||
// fprintf(stderr, "%f %llu %llu %llu %llu %llu\n", proc->super.percent_cpu,
|
} else {
|
||||||
// proc->stime, proc->utime, pti.pti_total_system, pti.pti_total_user, dpl->global_diff);
|
proc->super.percent_cpu = 0.0;
|
||||||
// exit(7);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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.nlwp = pti.pti_threadnum;
|
||||||
proc->super.m_virt = pti.pti_virtual_size / CRT_pageSize;
|
proc->super.m_virt = pti.pti_virtual_size / ONE_K;
|
||||||
proc->super.m_resident = pti.pti_resident_size / CRT_pageSize;
|
proc->super.m_resident = pti.pti_resident_size / ONE_K;
|
||||||
proc->super.majflt = pti.pti_faults;
|
proc->super.majflt = pti.pti_faults;
|
||||||
proc->super.percent_mem = (double)pti.pti_resident_size * 100.0
|
proc->super.percent_mem = (double)pti.pti_resident_size * 100.0
|
||||||
/ (double)dpl->host_info.max_mem;
|
/ (double)dpl->host_info.max_mem;
|
||||||
@ -341,3 +391,15 @@ void DarwinProcess_scanThreads(DarwinProcess* dp) {
|
|||||||
}
|
}
|
||||||
proc->state = state;
|
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,
|
||||||
|
};
|
||||||
|
@ -19,10 +19,13 @@ typedef struct DarwinProcess_ {
|
|||||||
uint64_t utime;
|
uint64_t utime;
|
||||||
uint64_t stime;
|
uint64_t stime;
|
||||||
bool taskAccess;
|
bool taskAccess;
|
||||||
|
bool translated;
|
||||||
} DarwinProcess;
|
} DarwinProcess;
|
||||||
|
|
||||||
extern const ProcessClass DarwinProcess_class;
|
extern const ProcessClass DarwinProcess_class;
|
||||||
|
|
||||||
|
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
|
||||||
|
|
||||||
Process* DarwinProcess_new(const Settings* settings);
|
Process* DarwinProcess_new(const Settings* settings);
|
||||||
|
|
||||||
void Process_delete(Object* cast);
|
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_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.
|
* Scan threads for process state information.
|
||||||
|
@ -7,7 +7,6 @@ in the source distribution for its full text.
|
|||||||
|
|
||||||
#include "DarwinProcessList.h"
|
#include "DarwinProcessList.h"
|
||||||
|
|
||||||
#include <err.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <libproc.h>
|
#include <libproc.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@ -21,6 +20,7 @@ in the source distribution for its full text.
|
|||||||
|
|
||||||
#include "CRT.h"
|
#include "CRT.h"
|
||||||
#include "DarwinProcess.h"
|
#include "DarwinProcess.h"
|
||||||
|
#include "Platform.h"
|
||||||
#include "ProcessList.h"
|
#include "ProcessList.h"
|
||||||
#include "zfs/openzfs_sysctl.h"
|
#include "zfs/openzfs_sysctl.h"
|
||||||
#include "zfs/ZfsArcStats.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;
|
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)) {
|
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) {
|
static void ProcessList_freeCPULoadInfo(processor_cpu_load_info_t* p) {
|
||||||
if (NULL != p && NULL != *p) {
|
if (NULL != p && NULL != *p) {
|
||||||
if (0 != munmap(*p, vm_page_size)) {
|
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;
|
*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.
|
// 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)) {
|
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;
|
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;
|
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) {
|
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) {
|
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
|
||||||
DarwinProcessList* this = xCalloc(1, sizeof(DarwinProcessList));
|
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 */
|
/* Initialize the CPU information */
|
||||||
this->super.cpuCount = ProcessList_allocateCPULoadInfo(&this->prev_load);
|
this->super.cpuCount = ProcessList_allocateCPULoadInfo(&this->prev_load);
|
||||||
@ -158,6 +158,11 @@ void ProcessList_delete(ProcessList* this) {
|
|||||||
free(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) {
|
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
DarwinProcessList* dpl = (DarwinProcessList*)super;
|
DarwinProcessList* dpl = (DarwinProcessList*)super;
|
||||||
bool preExisting = true;
|
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 */
|
/* Clear the thread counts */
|
||||||
super->kernelThreads = 0;
|
super->kernelThreads = 0;
|
||||||
super->userlandThreads = 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);
|
proc = (DarwinProcess*)ProcessList_getProcess(super, ps[i].kp_proc.p_pid, &preExisting, DarwinProcess_new);
|
||||||
|
|
||||||
DarwinProcess_setFromKInfoProc(&proc->super, &ps[i], preExisting);
|
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
|
// Disabled for High Sierra due to bug in macOS High Sierra
|
||||||
bool isScanThreadSupported = ! ( CompareKernelVersion(17, 0, 0) >= 0 && CompareKernelVersion(17, 5, 0) < 0);
|
bool isScanThreadSupported = ! ( CompareKernelVersion(17, 0, 0) >= 0 && CompareKernelVersion(17, 5, 0) < 0);
|
||||||
|
@ -6,32 +6,42 @@ Released under the GNU GPLv2, see the COPYING file
|
|||||||
in the source distribution for its full text.
|
in the source distribution for its full text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Platform.h"
|
#include "config.h" // IWYU pragma: keep
|
||||||
#include "Macros.h"
|
|
||||||
#include "CPUMeter.h"
|
|
||||||
#include "MemoryMeter.h"
|
|
||||||
#include "SwapMeter.h"
|
|
||||||
#include "TasksMeter.h"
|
|
||||||
#include "LoadAverageMeter.h"
|
|
||||||
#include "ClockMeter.h"
|
|
||||||
#include "DateMeter.h"
|
|
||||||
#include "DateTimeMeter.h"
|
|
||||||
#include "HostnameMeter.h"
|
|
||||||
#include "ProcessLocksScreen.h"
|
|
||||||
#include "UptimeMeter.h"
|
|
||||||
#include "zfs/ZfsArcMeter.h"
|
|
||||||
#include "zfs/ZfsCompressedArcMeter.h"
|
|
||||||
#include "DarwinProcessList.h"
|
|
||||||
|
|
||||||
|
#include "Platform.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
|
||||||
#include <CoreFoundation/CFString.h>
|
#include <CoreFoundation/CFString.h>
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
#include <IOKit/ps/IOPowerSources.h>
|
#include <IOKit/ps/IOPowerSources.h>
|
||||||
#include <IOKit/ps/IOPSKeys.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 };
|
#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"
|
||||||
|
|
||||||
|
#ifdef HAVE_MACH_MACH_TIME_H
|
||||||
|
#include <mach/mach_time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
const ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
|
||||||
|
|
||||||
const SignalItem Platform_signals[] = {
|
const SignalItem Platform_signals[] = {
|
||||||
{ .name = " 0 Cancel", .number = 0 },
|
{ .name = " 0 Cancel", .number = 0 },
|
||||||
@ -71,35 +81,6 @@ const SignalItem Platform_signals[] = {
|
|||||||
|
|
||||||
const unsigned int Platform_numberOfSignals = ARRAYSIZE(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[] = {
|
const MeterClass* const Platform_meterTypes[] = {
|
||||||
&CPUMeter_class,
|
&CPUMeter_class,
|
||||||
&ClockMeter_class,
|
&ClockMeter_class,
|
||||||
@ -131,10 +112,28 @@ const MeterClass* const Platform_meterTypes[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
int Platform_numberOfFields = 100;
|
double Platform_timebaseToNS = 1.0;
|
||||||
|
|
||||||
|
long Platform_clockTicksPerSec = -1;
|
||||||
|
|
||||||
void Platform_init(void) {
|
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) {
|
void Platform_done(void) {
|
||||||
@ -179,16 +178,6 @@ int Platform_getMaxPid() {
|
|||||||
return 99999;
|
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) {
|
static double Platform_setCPUAverageValues(Meter* mtr) {
|
||||||
const ProcessList* dpl = mtr->pl;
|
const ProcessList* dpl = mtr->pl;
|
||||||
int cpus = dpl->cpuCount;
|
int cpus = dpl->cpuCount;
|
||||||
|
@ -19,11 +19,12 @@ in the source distribution for its full text.
|
|||||||
#include "ProcessLocksScreen.h"
|
#include "ProcessLocksScreen.h"
|
||||||
#include "SignalsPanel.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[];
|
extern const SignalItem Platform_signals[];
|
||||||
|
|
||||||
@ -43,8 +44,6 @@ void Platform_getLoadAverage(double* one, double* five, double* fifteen);
|
|||||||
|
|
||||||
int Platform_getMaxPid(void);
|
int Platform_getMaxPid(void);
|
||||||
|
|
||||||
extern ProcessPidColumn Process_pidColumns[];
|
|
||||||
|
|
||||||
double Platform_setCPUValues(Meter* mtr, int cpu);
|
double Platform_setCPUValues(Meter* mtr, int cpu);
|
||||||
|
|
||||||
void Platform_setMemoryValues(Meter* mtr);
|
void Platform_setMemoryValues(Meter* mtr);
|
||||||
|
16
darwin/ProcessField.h
Normal file
16
darwin/ProcessField.h
Normal file
@ -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 */
|
@ -18,26 +18,16 @@ in the source distribution for its full text.
|
|||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
|
|
||||||
|
|
||||||
const ProcessClass DragonFlyBSDProcess_class = {
|
const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
|
||||||
.super = {
|
|
||||||
.extends = Class(Process),
|
|
||||||
.display = Process_display,
|
|
||||||
.delete = Process_delete,
|
|
||||||
.compare = DragonFlyBSDProcess_compare
|
|
||||||
},
|
|
||||||
.writeField = DragonFlyBSDProcess_writeField,
|
|
||||||
};
|
|
||||||
|
|
||||||
ProcessFieldData Process_fields[] = {
|
|
||||||
[0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
|
[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, },
|
[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, },
|
[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, },
|
[PPID] = { .name = "PPID", .title = "PPID", .description = "Parent process ID", .flags = 0, .pidColumn = true, },
|
||||||
[PGRP] = { .name = "PGRP", .title = " PGRP ", .description = "Process group ID", .flags = 0, },
|
[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, },
|
[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, },
|
[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, },
|
[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, },
|
[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, },
|
[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, },
|
[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, },
|
[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, },
|
[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, },
|
||||||
[JID] = { .name = "JID", .title = " JID ", .description = "Jail prison ID", .flags = 0, },
|
[JID] = { .name = "JID", .title = "JID", .description = "Jail prison ID", .flags = 0, .pidColumn = true, },
|
||||||
[JAIL] = { .name = "JAIL", .title = "JAIL ", .description = "Jail prison name", .flags = 0, },
|
[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) {
|
Process* DragonFlyBSDProcess_new(const Settings* settings) {
|
||||||
@ -84,50 +62,35 @@ void Process_delete(Object* cast) {
|
|||||||
free(this);
|
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;
|
const DragonFlyBSDProcess* fp = (const DragonFlyBSDProcess*) this;
|
||||||
char buffer[256]; buffer[255] = '\0';
|
char buffer[256]; buffer[255] = '\0';
|
||||||
int attr = CRT_colors[DEFAULT_COLOR];
|
int attr = CRT_colors[DEFAULT_COLOR];
|
||||||
int n = sizeof(buffer) - 1;
|
size_t n = sizeof(buffer) - 1;
|
||||||
switch ((int) field) {
|
switch (field) {
|
||||||
// add Platform-specific fields here
|
// add Platform-specific fields here
|
||||||
case PID: xSnprintf(buffer, n, Process_pidFormat, (fp->kernel ? -1 : this->pid)); break;
|
case PID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, (fp->kernel ? -1 : this->pid)); break;
|
||||||
case JID: xSnprintf(buffer, n, Process_pidFormat, fp->jid); break;
|
case JID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, fp->jid); break;
|
||||||
case JAIL: {
|
case JAIL: Process_printLeftAlignedField(str, attr, fp->jname, 11); return;
|
||||||
xSnprintf(buffer, n, "%-11s ", fp->jname);
|
|
||||||
if (buffer[11] != '\0') {
|
|
||||||
buffer[11] = ' ';
|
|
||||||
buffer[12] = '\0';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
Process_writeField(this, str, field);
|
Process_writeField(this, str, field);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RichString_append(str, attr, buffer);
|
RichString_appendWide(str, attr, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
long DragonFlyBSDProcess_compare(const void* v1, const void* v2) {
|
static int DragonFlyBSDProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
|
||||||
const DragonFlyBSDProcess *p1, *p2;
|
const DragonFlyBSDProcess* p1 = (const DragonFlyBSDProcess*)v1;
|
||||||
const Settings *settings = ((const Process*)v1)->settings;
|
const DragonFlyBSDProcess* p2 = (const DragonFlyBSDProcess*)v2;
|
||||||
|
|
||||||
if (settings->direction == 1) {
|
switch (key) {
|
||||||
p1 = (const DragonFlyBSDProcess*)v1;
|
|
||||||
p2 = (const DragonFlyBSDProcess*)v2;
|
|
||||||
} else {
|
|
||||||
p2 = (const DragonFlyBSDProcess*)v1;
|
|
||||||
p1 = (const DragonFlyBSDProcess*)v2;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ((int) settings->sortKey) {
|
|
||||||
// add Platform-specific fields here
|
// add Platform-specific fields here
|
||||||
case JID:
|
case JID:
|
||||||
return SPACESHIP_NUMBER(p1->jid, p2->jid);
|
return SPACESHIP_NUMBER(p1->jid, p2->jid);
|
||||||
case JAIL:
|
case JAIL:
|
||||||
return SPACESHIP_NULLSTR(p1->jname, p2->jname);
|
return SPACESHIP_NULLSTR(p1->jname, p2->jname);
|
||||||
default:
|
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));
|
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
|
||||||
|
};
|
||||||
|
@ -8,13 +8,6 @@ Released under the GNU GPLv2, see the COPYING file
|
|||||||
in the source distribution for its full text.
|
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_ {
|
typedef struct DragonFlyBSDProcess_ {
|
||||||
Process super;
|
Process super;
|
||||||
int kernel;
|
int kernel;
|
||||||
@ -29,18 +22,12 @@ typedef struct DragonFlyBSDProcess_ {
|
|||||||
|
|
||||||
extern const ProcessClass DragonFlyBSDProcess_class;
|
extern const ProcessClass DragonFlyBSDProcess_class;
|
||||||
|
|
||||||
extern ProcessFieldData Process_fields[];
|
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
|
||||||
|
|
||||||
extern ProcessPidColumn Process_pidColumns[];
|
|
||||||
|
|
||||||
Process* DragonFlyBSDProcess_new(const Settings* settings);
|
Process* DragonFlyBSDProcess_new(const Settings* settings);
|
||||||
|
|
||||||
void Process_delete(Object* cast);
|
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);
|
bool Process_isThread(const Process* this);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -15,7 +15,6 @@ in the source distribution for its full text.
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <sys/user.h>
|
#include <sys/user.h>
|
||||||
#include <err.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <string.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 = 2; sysctlnametomib("hw.physmem", MIB_hw_physmem, &len);
|
||||||
|
|
||||||
len = sizeof(pageSize);
|
len = sizeof(pageSize);
|
||||||
if (sysctlbyname("vm.stats.vm.v_page_size", &pageSize, &len, NULL, 0) == -1) {
|
if (sysctlbyname("vm.stats.vm.v_page_size", &pageSize, &len, NULL, 0) == -1)
|
||||||
pageSize = CRT_pageSize;
|
CRT_fatalError("Cannot get pagesize by sysctl");
|
||||||
pageSizeKb = CRT_pageSizeKB;
|
pageSizeKb = pageSize / ONE_K;
|
||||||
} else {
|
|
||||||
pageSizeKb = pageSize / ONE_K;
|
|
||||||
}
|
|
||||||
|
|
||||||
// usable page count vm.stats.vm.v_page_count
|
// usable page count vm.stats.vm.v_page_count
|
||||||
// actually usable memory : vm.stats.vm.v_page_count * vm.stats.vm.v_page_size
|
// 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);
|
dfpl->kd = kvm_openfiles(NULL, "/dev/null", NULL, 0, errbuf);
|
||||||
if (dfpl->kd == NULL) {
|
if (dfpl->kd == NULL) {
|
||||||
errx(1, "kvm_open: %s", errbuf);
|
CRT_fatalError("kvm_openfiles() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
return pl;
|
return pl;
|
||||||
@ -265,7 +261,7 @@ static inline void DragonFlyBSDProcessList_scanMemoryInfo(ProcessList* pl) {
|
|||||||
pl->usedSwap *= pageSizeKb;
|
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);
|
char** argv = kvm_getargv(kd, kproc, 0);
|
||||||
if (!argv) {
|
if (!argv) {
|
||||||
return xStrdup(kproc->kp_comm);
|
return xStrdup(kproc->kp_comm);
|
||||||
@ -297,25 +293,20 @@ static inline void DragonFlyBSDProcessList_scanJails(DragonFlyBSDProcessList* df
|
|||||||
char* nextpos;
|
char* nextpos;
|
||||||
|
|
||||||
if (sysctlbyname("jail.list", NULL, &len, NULL, 0) == -1) {
|
if (sysctlbyname("jail.list", NULL, &len, NULL, 0) == -1) {
|
||||||
fprintf(stderr, "initial sysctlbyname / jail.list failed\n");
|
CRT_fatalError("initial sysctlbyname / jail.list failed");
|
||||||
exit(3);
|
|
||||||
}
|
}
|
||||||
retry:
|
retry:
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
jls = xMalloc(len);
|
jls = xMalloc(len);
|
||||||
if (jls == NULL) {
|
|
||||||
fprintf(stderr, "xMalloc failed\n");
|
|
||||||
exit(4);
|
|
||||||
}
|
|
||||||
if (sysctlbyname("jail.list", jls, &len, NULL, 0) == -1) {
|
if (sysctlbyname("jail.list", jls, &len, NULL, 0) == -1) {
|
||||||
if (errno == ENOMEM) {
|
if (errno == ENOMEM) {
|
||||||
free(jls);
|
free(jls);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "sysctlbyname / jail.list failed\n");
|
CRT_fatalError("sysctlbyname / jail.list failed");
|
||||||
exit(5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dfpl->jails) {
|
if (dfpl->jails) {
|
||||||
@ -346,7 +337,7 @@ retry:
|
|||||||
free(jls);
|
free(jls);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* DragonFlyBSDProcessList_readJailName(DragonFlyBSDProcessList* dfpl, int jailid) {
|
static char* DragonFlyBSDProcessList_readJailName(DragonFlyBSDProcessList* dfpl, int jailid) {
|
||||||
char* hostname;
|
char* hostname;
|
||||||
char* jname;
|
char* jname;
|
||||||
|
|
||||||
@ -376,10 +367,10 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
// TODO Kernel Threads seem to be skipped, need to figure out the correct flag
|
// 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++) {
|
for (int i = 0; i < count; i++) {
|
||||||
struct kinfo_proc* kproc = &kprocs[i];
|
const struct kinfo_proc* kproc = &kprocs[i];
|
||||||
bool preExisting = false;
|
bool preExisting = false;
|
||||||
bool ATTR_UNUSED isIdleProcess = 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_virt = kproc->kp_vm_map_size / ONE_K;
|
||||||
proc->m_resident = kproc->kp_vm_rssize;
|
proc->m_resident = kproc->kp_vm_rssize * pageSizeKb;
|
||||||
proc->nlwp = kproc->kp_nthreads; // number of lwp thread
|
proc->nlwp = kproc->kp_nthreads; // number of lwp thread
|
||||||
proc->time = (kproc->kp_swtime + 5000) / 10000;
|
proc->time = (kproc->kp_swtime + 5000) / 10000;
|
||||||
|
|
||||||
proc->percent_cpu = 100.0 * ((double)kproc->kp_lwp.kl_pctcpu / (double)kernelFScale);
|
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) {
|
if (proc->percent_cpu > 0.1) {
|
||||||
// system idle process should own all CPU time left regardless of CPU count
|
// system idle process should own all CPU time left regardless of CPU count
|
||||||
|
@ -11,16 +11,12 @@ in the source distribution for its full text.
|
|||||||
#include <kvm.h>
|
#include <kvm.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <osreldate.h>
|
#include <osreldate.h>
|
||||||
#include <sys/kinfo.h>
|
|
||||||
#include <kinfo.h>
|
|
||||||
#include <sys/jail.h>
|
#include <sys/jail.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include "Hashtable.h"
|
#include "Hashtable.h"
|
||||||
#include "DragonFlyBSDProcess.h"
|
#include "DragonFlyBSDProcess.h"
|
||||||
|
|
||||||
#define JAIL_ERRMSGLEN 1024
|
|
||||||
extern char jail_errmsg[JAIL_ERRMSGLEN];
|
|
||||||
|
|
||||||
typedef struct CPUData_ {
|
typedef struct CPUData_ {
|
||||||
double userPercent;
|
double userPercent;
|
||||||
@ -55,10 +51,6 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
|
|||||||
|
|
||||||
void ProcessList_delete(ProcessList* this);
|
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);
|
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -31,9 +31,7 @@ in the source distribution for its full text.
|
|||||||
#include <math.h>
|
#include <math.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 };
|
||||||
|
|
||||||
int Platform_numberOfFields = LAST_PROCESSFIELD;
|
|
||||||
|
|
||||||
const SignalItem Platform_signals[] = {
|
const SignalItem Platform_signals[] = {
|
||||||
{ .name = " 0 Cancel", .number = 0 },
|
{ .name = " 0 Cancel", .number = 0 },
|
||||||
|
@ -17,11 +17,8 @@ in the source distribution for its full text.
|
|||||||
#include "ProcessLocksScreen.h"
|
#include "ProcessLocksScreen.h"
|
||||||
#include "SignalsPanel.h"
|
#include "SignalsPanel.h"
|
||||||
|
|
||||||
extern ProcessFieldData Process_fields[];
|
|
||||||
|
|
||||||
extern ProcessField Platform_defaultFields[];
|
extern const ProcessField Platform_defaultFields[];
|
||||||
|
|
||||||
extern int Platform_numberOfFields;
|
|
||||||
|
|
||||||
extern const SignalItem Platform_signals[];
|
extern const SignalItem Platform_signals[];
|
||||||
|
|
||||||
|
17
dragonflybsd/ProcessField.h
Normal file
17
dragonflybsd/ProcessField.h
Normal file
@ -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 */
|
@ -18,16 +18,16 @@ in the source distribution for its full text.
|
|||||||
|
|
||||||
const char* const nodevStr = "nodev";
|
const char* const nodevStr = "nodev";
|
||||||
|
|
||||||
ProcessFieldData Process_fields[] = {
|
const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
|
||||||
[0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
|
[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, },
|
[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, },
|
[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, },
|
[PPID] = { .name = "PPID", .title = "PPID", .description = "Parent process ID", .flags = 0, .pidColumn = true, },
|
||||||
[PGRP] = { .name = "PGRP", .title = " PGRP ", .description = "Process group ID", .flags = 0, },
|
[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, },
|
[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, },
|
[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, },
|
[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, },
|
[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, },
|
[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, },
|
[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, },
|
[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, },
|
[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, },
|
||||||
[JID] = { .name = "JID", .title = " JID ", .description = "Jail prison ID", .flags = 0, },
|
[JID] = { .name = "JID", .title = "JID", .description = "Jail prison ID", .flags = 0, .pidColumn = true, },
|
||||||
[JAIL] = { .name = "JAIL", .title = "JAIL ", .description = "Jail prison name", .flags = 0, },
|
[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) {
|
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';
|
char buffer[256]; buffer[255] = '\0';
|
||||||
int attr = CRT_colors[DEFAULT_COLOR];
|
int attr = CRT_colors[DEFAULT_COLOR];
|
||||||
int n = sizeof(buffer) - 1;
|
int n = sizeof(buffer) - 1;
|
||||||
switch ((int) field) {
|
switch (field) {
|
||||||
// add FreeBSD-specific fields here
|
// add FreeBSD-specific fields here
|
||||||
case JID: xSnprintf(buffer, n, Process_pidFormat, fp->jid); break;
|
case JID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, fp->jid); break;
|
||||||
case JAIL: {
|
case JAIL:
|
||||||
xSnprintf(buffer, n, "%-11s ", fp->jname);
|
Process_printLeftAlignedField(str, attr, fp->jname ? fp->jname : "N/A", 11);
|
||||||
if (buffer[11] != '\0') {
|
return;
|
||||||
buffer[11] = ' ';
|
|
||||||
buffer[12] = '\0';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TTY_NR:
|
case TTY_NR:
|
||||||
if (fp->ttyPath) {
|
if (fp->ttyPath) {
|
||||||
if (fp->ttyPath == nodevStr)
|
if (fp->ttyPath == nodevStr)
|
||||||
@ -105,22 +88,14 @@ static void FreeBSDProcess_writeField(const Process* this, RichString* str, Proc
|
|||||||
Process_writeField(this, str, field);
|
Process_writeField(this, str, field);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RichString_append(str, attr, buffer);
|
RichString_appendWide(str, attr, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static long FreeBSDProcess_compare(const void* v1, const void* v2) {
|
static int FreeBSDProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
|
||||||
const FreeBSDProcess *p1, *p2;
|
const FreeBSDProcess* p1 = (const FreeBSDProcess*)v1;
|
||||||
const Settings *settings = ((const Process*)v1)->settings;
|
const FreeBSDProcess* p2 = (const FreeBSDProcess*)v2;
|
||||||
|
|
||||||
if (settings->direction == 1) {
|
switch (key) {
|
||||||
p1 = (const FreeBSDProcess*)v1;
|
|
||||||
p2 = (const FreeBSDProcess*)v2;
|
|
||||||
} else {
|
|
||||||
p2 = (const FreeBSDProcess*)v1;
|
|
||||||
p1 = (const FreeBSDProcess*)v2;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ((int) settings->sortKey) {
|
|
||||||
// add FreeBSD-specific fields here
|
// add FreeBSD-specific fields here
|
||||||
case JID:
|
case JID:
|
||||||
return SPACESHIP_NUMBER(p1->jid, p2->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:
|
case TTY_NR:
|
||||||
return SPACESHIP_NULLSTR(p1->ttyPath, p2->ttyPath);
|
return SPACESHIP_NULLSTR(p1->ttyPath, p2->ttyPath);
|
||||||
default:
|
default:
|
||||||
return Process_compare(v1, v2);
|
return Process_compareByKey_Base(v1, v2, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +123,8 @@ const ProcessClass FreeBSDProcess_class = {
|
|||||||
.extends = Class(Process),
|
.extends = Class(Process),
|
||||||
.display = Process_display,
|
.display = Process_display,
|
||||||
.delete = Process_delete,
|
.delete = Process_delete,
|
||||||
.compare = FreeBSDProcess_compare
|
.compare = Process_compare
|
||||||
},
|
},
|
||||||
.writeField = FreeBSDProcess_writeField,
|
.writeField = FreeBSDProcess_writeField,
|
||||||
|
.compareByKey = FreeBSDProcess_compareByKey
|
||||||
};
|
};
|
||||||
|
@ -18,13 +18,6 @@ in the source distribution for its full text.
|
|||||||
|
|
||||||
extern const char* const nodevStr;
|
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_ {
|
typedef struct FreeBSDProcess_ {
|
||||||
Process super;
|
Process super;
|
||||||
int kernel;
|
int kernel;
|
||||||
@ -43,9 +36,7 @@ static inline bool Process_isUserlandThread(const Process* this) {
|
|||||||
|
|
||||||
extern const ProcessClass FreeBSDProcess_class;
|
extern const ProcessClass FreeBSDProcess_class;
|
||||||
|
|
||||||
extern ProcessFieldData Process_fields[];
|
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
|
||||||
|
|
||||||
extern ProcessPidColumn Process_pidColumns[];
|
|
||||||
|
|
||||||
Process* FreeBSDProcess_new(const Settings* settings);
|
Process* FreeBSDProcess_new(const Settings* settings);
|
||||||
|
|
||||||
|
@ -9,12 +9,10 @@ in the source distribution for its full text.
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <err.h>
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/_iovec.h>
|
#include <sys/_iovec.h>
|
||||||
#include <sys/dirent.h>
|
|
||||||
#include <sys/errno.h>
|
#include <sys/errno.h>
|
||||||
#include <sys/param.h> // needs to be included before <sys/jail.h> for MAXPATHLEN
|
#include <sys/param.h> // needs to be included before <sys/jail.h> for MAXPATHLEN
|
||||||
#include <sys/jail.h>
|
#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 = 2; sysctlnametomib("hw.physmem", MIB_hw_physmem, &len);
|
||||||
|
|
||||||
len = sizeof(pageSize);
|
len = sizeof(pageSize);
|
||||||
if (sysctlbyname("vm.stats.vm.v_page_size", &pageSize, &len, NULL, 0) == -1) {
|
if (sysctlbyname("vm.stats.vm.v_page_size", &pageSize, &len, NULL, 0) == -1)
|
||||||
pageSize = CRT_pageSize;
|
CRT_fatalError("Cannot get pagesize by sysctl");
|
||||||
pageSizeKb = CRT_pageSize;
|
pageSizeKb = pageSize / ONE_K;
|
||||||
} else {
|
|
||||||
pageSizeKb = pageSize / ONE_K;
|
|
||||||
}
|
|
||||||
|
|
||||||
// usable page count vm.stats.vm.v_page_count
|
// usable page count vm.stats.vm.v_page_count
|
||||||
// actually usable memory : vm.stats.vm.v_page_count * vm.stats.vm.v_page_size
|
// 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);
|
fpl->kd = kvm_openfiles(NULL, "/dev/null", NULL, 0, errbuf);
|
||||||
if (fpl->kd == NULL) {
|
if (fpl->kd == NULL) {
|
||||||
errx(1, "kvm_open: %s", errbuf);
|
CRT_fatalError("kvm_openfiles() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
fpl->ttys = Hashtable_new(20, true);
|
fpl->ttys = Hashtable_new(20, true);
|
||||||
@ -419,7 +414,7 @@ static char* FreeBSDProcessList_readJailName(const struct kinfo_proc* kproc) {
|
|||||||
char* jname = NULL;
|
char* jname = NULL;
|
||||||
char jnamebuf[MAXHOSTNAMELEN];
|
char jnamebuf[MAXHOSTNAMELEN];
|
||||||
|
|
||||||
if (kproc->ki_jid != 0 ) {
|
if (kproc->ki_jid != 0) {
|
||||||
struct iovec jiov[6];
|
struct iovec jiov[6];
|
||||||
|
|
||||||
memset(jnamebuf, 0, sizeof(jnamebuf));
|
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
|
// from FreeBSD source /src/usr.bin/top/machine.c
|
||||||
proc->m_virt = kproc->ki_size / pageSize;
|
proc->m_virt = kproc->ki_size / ONE_K;
|
||||||
proc->m_resident = kproc->ki_rssize;
|
proc->m_resident = kproc->ki_rssize * pageSizeKb;
|
||||||
proc->nlwp = kproc->ki_numthreads;
|
proc->nlwp = kproc->ki_numthreads;
|
||||||
proc->time = (kproc->ki_runtime + 5000) / 10000;
|
proc->time = (kproc->ki_runtime + 5000) / 10000;
|
||||||
|
|
||||||
proc->percent_cpu = 100.0 * ((double)kproc->ki_pctcpu / (double)kernelFScale);
|
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
|
* TODO
|
||||||
|
@ -47,9 +47,7 @@ in the source distribution for its full text.
|
|||||||
#include "zfs/ZfsCompressedArcMeter.h"
|
#include "zfs/ZfsCompressedArcMeter.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 };
|
||||||
|
|
||||||
int Platform_numberOfFields = LAST_PROCESSFIELD;
|
|
||||||
|
|
||||||
const SignalItem Platform_signals[] = {
|
const SignalItem Platform_signals[] = {
|
||||||
{ .name = " 0 Cancel", .number = 0 },
|
{ .name = " 0 Cancel", .number = 0 },
|
||||||
|
@ -19,11 +19,7 @@ in the source distribution for its full text.
|
|||||||
#include "SignalsPanel.h"
|
#include "SignalsPanel.h"
|
||||||
|
|
||||||
|
|
||||||
extern ProcessFieldData Process_fields[];
|
extern const ProcessField Platform_defaultFields[];
|
||||||
|
|
||||||
extern ProcessField Platform_defaultFields[];
|
|
||||||
|
|
||||||
extern int Platform_numberOfFields;
|
|
||||||
|
|
||||||
extern const SignalItem Platform_signals[];
|
extern const SignalItem Platform_signals[];
|
||||||
|
|
||||||
|
17
freebsd/ProcessField.h
Normal file
17
freebsd/ProcessField.h
Normal file
@ -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 */
|
68
htop.1.in
68
htop.1.in
@ -2,11 +2,9 @@
|
|||||||
.SH "NAME"
|
.SH "NAME"
|
||||||
htop \- interactive process viewer
|
htop \- interactive process viewer
|
||||||
.SH "SYNOPSIS"
|
.SH "SYNOPSIS"
|
||||||
.LP
|
|
||||||
.B htop
|
.B htop
|
||||||
.RB [ \-dCFhpustvH ]
|
.RB [ \-dCFhpustvH ]
|
||||||
.SH "DESCRIPTION"
|
.SH "DESCRIPTION"
|
||||||
.LP
|
|
||||||
.B htop
|
.B htop
|
||||||
is a cross-platform ncurses-based process viewer.
|
is a cross-platform ncurses-based process viewer.
|
||||||
.LP
|
.LP
|
||||||
@ -22,9 +20,7 @@ Tasks related to processes (killing, renicing) can be done without
|
|||||||
entering their PIDs.
|
entering their PIDs.
|
||||||
.br
|
.br
|
||||||
.SH "COMMAND-LINE OPTIONS"
|
.SH "COMMAND-LINE OPTIONS"
|
||||||
.LP
|
|
||||||
Mandatory arguments to long options are mandatory for short options too.
|
Mandatory arguments to long options are mandatory for short options too.
|
||||||
.LP
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-d \-\-delay=DELAY\fR
|
\fB\-d \-\-delay=DELAY\fR
|
||||||
Delay between updates, in tenths of seconds. If the delay value is
|
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
|
Show only the given PIDs
|
||||||
.TP
|
.TP
|
||||||
\fB\-s \-\-sort\-key COLUMN\fR
|
\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
|
.TP
|
||||||
\fB\-u \-\-user=USERNAME\fR
|
\fB\-u \-\-user=USERNAME\fR
|
||||||
Show only the processes of a given user
|
Show only the processes of a given user
|
||||||
@ -61,15 +58,14 @@ Disable support of mouse control
|
|||||||
Output version information and exit
|
Output version information and exit
|
||||||
.TP
|
.TP
|
||||||
\fB\-t \-\-tree
|
\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
|
.TP
|
||||||
\fB\-H \-\-highlight-changes=DELAY\fR
|
\fB\-H \-\-highlight-changes=DELAY\fR
|
||||||
Highlight new and old processes
|
Highlight new and old processes
|
||||||
.SH "INTERACTIVE COMMANDS"
|
.SH "INTERACTIVE COMMANDS"
|
||||||
.LP
|
|
||||||
The following commands are supported while in
|
The following commands are supported while in
|
||||||
.BR htop :
|
.BR htop :
|
||||||
.LP
|
|
||||||
.TP 5
|
.TP 5
|
||||||
.B Up, Alt-k
|
.B Up, Alt-k
|
||||||
Select (highlight) the previous process in the process list. Scroll the list
|
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
|
Incrementally search the command lines of all the displayed processes. The
|
||||||
currently selected (highlighted) command will update as you type. While in
|
currently selected (highlighted) command will update as you type. While in
|
||||||
search mode, pressing F3 will cycle through matching occurrences.
|
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
|
Alternatively the search can be started by simply typing the command
|
||||||
you are looking for, although for the first character normal key
|
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
|
your previously selected sort view. Selecting a sort view will exit
|
||||||
tree view.
|
tree view.
|
||||||
.TP
|
.TP
|
||||||
.B F6
|
.B F6, <, >
|
||||||
On sorted view, select a field for sorting, also accessible through < and >.
|
Selects a field for sorting, also accessible through < and >.
|
||||||
The current sort field is indicated by a highlight in the header.
|
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
|
.TP
|
||||||
.B F7, ]
|
.B F7, ]
|
||||||
Increase the selected process's priority (subtract from 'nice' value).
|
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
|
.B u
|
||||||
Show only processes owned by a specified user.
|
Show only processes owned by a specified user.
|
||||||
.TP
|
.TP
|
||||||
|
.B N
|
||||||
|
Sort by PID.
|
||||||
|
.TP
|
||||||
.B M
|
.B M
|
||||||
Sort by memory usage (top compatibility key).
|
Sort by memory usage (top compatibility key).
|
||||||
.TP
|
.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.
|
PID search: type in process ID and the selection highlight will be moved to it.
|
||||||
.PD
|
.PD
|
||||||
.SH "COLUMNS"
|
.SH "COLUMNS"
|
||||||
.LP
|
|
||||||
The following columns can display data about each process. A value of '\-' in
|
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
|
all the rows indicates that a column is unsupported on your system, or
|
||||||
currently unimplemented in
|
currently unimplemented in
|
||||||
@ -242,7 +239,6 @@ The names below are the ones used in the
|
|||||||
shown in
|
shown in
|
||||||
.BR htop 's
|
.BR htop 's
|
||||||
main screen, it is shown below in parenthesis.
|
main screen, it is shown below in parenthesis.
|
||||||
.LP
|
|
||||||
.TP 5
|
.TP 5
|
||||||
.B Command
|
.B Command
|
||||||
The full command line of the process (i.e. program name and arguments). If the
|
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
|
.TP
|
||||||
.B All other flags
|
.B All other flags
|
||||||
Currently unsupported (always displays '-').
|
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"
|
.SH "CONFIG FILE"
|
||||||
.LP
|
|
||||||
By default
|
By default
|
||||||
.B htop
|
.B htop
|
||||||
reads its configuration from the XDG-compliant path
|
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
|
environment variable (so you can have multiple configurations for different
|
||||||
machines that share the same home directory, for example).
|
machines that share the same home directory, for example).
|
||||||
.SH "MEMORY SIZES"
|
.SH "MEMORY SIZES"
|
||||||
.LP
|
|
||||||
Memory sizes in
|
Memory sizes in
|
||||||
.B htop
|
.B htop
|
||||||
are displayed in a human-readable form.
|
are displayed in a human-readable form.
|
||||||
@ -497,7 +532,6 @@ space and make memory size representations consistent throughout
|
|||||||
and
|
and
|
||||||
.BR limits.conf (5).
|
.BR limits.conf (5).
|
||||||
.SH "AUTHORS"
|
.SH "AUTHORS"
|
||||||
.LP
|
|
||||||
.B htop
|
.B htop
|
||||||
was originally developed by Hisham Muhammad.
|
was originally developed by Hisham Muhammad.
|
||||||
Nowadays it is maintained by the community at <htop@groups.io>.
|
Nowadays it is maintained by the community at <htop@groups.io>.
|
||||||
|
22
htop.c
22
htop.c
@ -49,8 +49,8 @@ static void printHelpFlag(void) {
|
|||||||
"-H --highlight-changes[=DELAY] Highlight new and old processes\n"
|
"-H --highlight-changes[=DELAY] Highlight new and old processes\n"
|
||||||
"-M --no-mouse Disable the mouse\n"
|
"-M --no-mouse Disable the mouse\n"
|
||||||
"-p --pid=PID[,PID,PID...] Show only the given PIDs\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"
|
"-s --sort-key=COLUMN Sort by COLUMN in list view (try --sort-key=help for a list)\n"
|
||||||
"-t --tree Show the tree view by default\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 --user[=USERNAME] Show only processes for a given user (or $USER)\n"
|
||||||
"-U --no-unicode Do not use unicode but plain ASCII\n"
|
"-U --no-unicode Do not use unicode but plain ASCII\n"
|
||||||
"-V --version Print version info\n"
|
"-V --version Print version info\n"
|
||||||
@ -93,7 +93,7 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
|
|||||||
.highlightDelaySecs = -1,
|
.highlightDelaySecs = -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct option long_opts[] =
|
const struct option long_opts[] =
|
||||||
{
|
{
|
||||||
{"help", no_argument, 0, 'h'},
|
{"help", no_argument, 0, 'h'},
|
||||||
{"version", no_argument, 0, 'V'},
|
{"version", no_argument, 0, 'V'},
|
||||||
@ -125,14 +125,14 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
|
|||||||
case 's':
|
case 's':
|
||||||
assert(optarg); /* please clang analyzer, cause optarg can be NULL in the 'u' case */
|
assert(optarg); /* please clang analyzer, cause optarg can be NULL in the 'u' case */
|
||||||
if (String_eq(optarg, "help")) {
|
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;
|
const char* name = Process_fields[j].name;
|
||||||
if (name) printf ("%s\n", name);
|
if (name) printf ("%s\n", name);
|
||||||
}
|
}
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
flags.sortKey = 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)
|
if (Process_fields[j].name == NULL)
|
||||||
continue;
|
continue;
|
||||||
if (String_eq(optarg, Process_fields[j].name)) {
|
if (String_eq(optarg, Process_fields[j].name)) {
|
||||||
@ -204,6 +204,7 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
case 'F': {
|
case 'F': {
|
||||||
assert(optarg);
|
assert(optarg);
|
||||||
|
free(flags.commFilter);
|
||||||
flags.commFilter = xStrdup(optarg);
|
flags.commFilter = xStrdup(optarg);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -298,9 +299,12 @@ int main(int argc, char** argv) {
|
|||||||
if (flags.highlightDelaySecs != -1)
|
if (flags.highlightDelaySecs != -1)
|
||||||
settings->highlightDelaySecs = flags.highlightDelaySecs;
|
settings->highlightDelaySecs = flags.highlightDelaySecs;
|
||||||
if (flags.sortKey > 0) {
|
if (flags.sortKey > 0) {
|
||||||
settings->sortKey = flags.sortKey;
|
// -t -s <key> means "tree sorted by key"
|
||||||
settings->treeView = false;
|
// -s <key> means "list sorted by key" (previous existing behavior)
|
||||||
settings->direction = 1;
|
if (!flags.treeView) {
|
||||||
|
settings->treeView = false;
|
||||||
|
}
|
||||||
|
Settings_setSortKey(settings, flags.sortKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
CRT_init(&(settings->delay), settings->colorScheme, flags.allowUnicode);
|
CRT_init(&(settings->delay), settings->colorScheme, flags.allowUnicode);
|
||||||
@ -310,8 +314,6 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
MainPanel_updateTreeFunctions(panel, settings->treeView);
|
MainPanel_updateTreeFunctions(panel, settings->treeView);
|
||||||
|
|
||||||
ProcessList_printHeader(pl, Panel_getHeader((Panel*)panel));
|
|
||||||
|
|
||||||
State state = {
|
State state = {
|
||||||
.settings = settings,
|
.settings = settings,
|
||||||
.ut = ut,
|
.ut = ut,
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
{ include: ["<bits/getopt_core.h>", "private", "<unistd.h>", "public"] },
|
{ 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/signal.h>", "private", "<signal.h>", "public"] },
|
||||||
|
|
||||||
{ include: ["<sys/_stdarg.h>", "private", "<stdarg.h>", "public"] },
|
{ include: ["<sys/_stdarg.h>", "private", "<stdarg.h>", "public"] },
|
||||||
|
@ -17,7 +17,7 @@ in the source distribution for its full text.
|
|||||||
|
|
||||||
|
|
||||||
Panel* IOPriorityPanel_new(IOPriority currPrio) {
|
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_setHeader(this, "IO Priority:");
|
||||||
Panel_add(this, (Object*) ListItem_new("None (based on nice)", IOPriority_None));
|
Panel_add(this, (Object*) ListItem_new("None (based on nice)", IOPriority_None));
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <math.h>
|
||||||
#include <sensors/sensors.h>
|
#include <sensors/sensors.h>
|
||||||
|
|
||||||
#include "XUtils.h"
|
#include "XUtils.h"
|
||||||
@ -16,12 +17,19 @@ 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_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 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 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;
|
static void* dlopenHandle = NULL;
|
||||||
|
|
||||||
int LibSensors_init(FILE* input) {
|
int LibSensors_init(FILE* input) {
|
||||||
if (!dlopenHandle) {
|
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);
|
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)
|
if (!dlopenHandle)
|
||||||
goto dlfailure;
|
goto dlfailure;
|
||||||
|
|
||||||
@ -41,6 +49,7 @@ int LibSensors_init(FILE* input) {
|
|||||||
resolve(sensors_get_features);
|
resolve(sensors_get_features);
|
||||||
resolve(sensors_get_subfeature);
|
resolve(sensors_get_subfeature);
|
||||||
resolve(sensors_get_value);
|
resolve(sensors_get_value);
|
||||||
|
resolve(sensors_get_label);
|
||||||
|
|
||||||
#undef resolve
|
#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) {
|
||||||
if (!dlopenHandle)
|
for (unsigned int i = 0; i <= cpuCount; i++)
|
||||||
return -ENOTSUP;
|
cpus[i].temperature = NAN;
|
||||||
|
|
||||||
int tempCount = 0;
|
if (!dlopenHandle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned int coreTempCount = 0;
|
||||||
|
|
||||||
int n = 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)) {
|
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];
|
char buffer[32];
|
||||||
sym_sensors_snprintf_chip_name(buffer, sizeof(buffer), chip);
|
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;
|
continue;
|
||||||
|
|
||||||
int m = 0;
|
int m = 0;
|
||||||
@ -82,7 +97,27 @@ int LibSensors_getCPUTemperatures(CPUData* cpus, int cpuCount) {
|
|||||||
if (feature->type != SENSORS_FEATURE_TEMP)
|
if (feature->type != SENSORS_FEATURE_TEMP)
|
||||||
continue;
|
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;
|
continue;
|
||||||
|
|
||||||
const sensors_subfeature *sub_feature = sym_sensors_get_subfeature(chip, feature, SENSORS_SUBFEATURE_TEMP_INPUT);
|
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)
|
if (r != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cpus[feature->number].temperature = temp;
|
cpus[tempId].temperature = temp;
|
||||||
tempCount++;
|
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 */
|
#endif /* HAVE_SENSORS_SENSORS_H */
|
||||||
|
@ -11,6 +11,6 @@
|
|||||||
int LibSensors_init(FILE* input);
|
int LibSensors_init(FILE* input);
|
||||||
void LibSensors_cleanup(void);
|
void LibSensors_cleanup(void);
|
||||||
|
|
||||||
int LibSensors_getCPUTemperatures(CPUData* cpus, int cpuCount);
|
void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int cpuCount);
|
||||||
|
|
||||||
#endif /* HEADER_LibSensors */
|
#endif /* HEADER_LibSensors */
|
||||||
|
@ -24,22 +24,22 @@ in the source distribution for its full text.
|
|||||||
|
|
||||||
|
|
||||||
/* semi-global */
|
/* semi-global */
|
||||||
long long btime;
|
int pageSize;
|
||||||
|
int pageSizeKB;
|
||||||
|
|
||||||
/* Used to identify kernel threads in Comm and Exe columns */
|
/* Used to identify kernel threads in Comm and Exe columns */
|
||||||
static const char *const kthreadID = "KTHREAD";
|
static const char *const kthreadID = "KTHREAD";
|
||||||
|
|
||||||
ProcessFieldData Process_fields[] = {
|
const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
|
||||||
[0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
|
[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, },
|
[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, },
|
[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, },
|
[PPID] = { .name = "PPID", .title = "PPID", .description = "Parent process ID", .flags = 0, .pidColumn = true, },
|
||||||
[PGRP] = { .name = "PGRP", .title = " PGRP ", .description = "Process group ID", .flags = 0, },
|
[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, },
|
[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, },
|
[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, },
|
||||||
[FLAGS] = { .name = "FLAGS", .title = NULL, .description = NULL, .flags = 0, },
|
|
||||||
[MINFLT] = { .name = "MINFLT", .title = " MINFLT ", .description = "Number of minor faults which have not required loading a memory page from disk", .flags = 0, },
|
[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, },
|
[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, },
|
[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, },
|
[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, },
|
[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, },
|
[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, },
|
[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, },
|
[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_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, },
|
[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, },
|
[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, },
|
[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, },
|
[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
|
#ifdef HAVE_OPENVZ
|
||||||
[CTID] = { .name = "CTID", .title = " CTID ", .description = "OpenVZ container ID (a.k.a. virtual environment ID)", .flags = PROCESS_FLAG_LINUX_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
|
#endif
|
||||||
#ifdef HAVE_VSERVER
|
#ifdef HAVE_VSERVER
|
||||||
[VXID] = { .name = "VXID", .title = " VXID ", .description = "VServer process ID", .flags = PROCESS_FLAG_LINUX_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, },
|
[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, },
|
[IO_PRIORITY] = { .name = "IO_PRIORITY", .title = "IO ", .description = "I/O priority", .flags = PROCESS_FLAG_LINUX_IOPRIO, },
|
||||||
#ifdef HAVE_DELAYACCT
|
#ifdef HAVE_DELAYACCT
|
||||||
[PERCENT_CPU_DELAY] = { .name = "PERCENT_CPU_DELAY", .title = "CPUD% ", .description = "CPU 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 = 0, },
|
[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 = 0, },
|
[PERCENT_SWAP_DELAY] = { .name = "PERCENT_SWAP_DELAY", .title = "SWAPD% ", .description = "Swapin delay %", .flags = PROCESS_FLAG_LINUX_DELAYACCT, },
|
||||||
#endif
|
#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_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, },
|
[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_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, },
|
[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, },
|
[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
|
/* 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;
|
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 LinuxProcess_updateIOPriority(LinuxProcess* this) {
|
||||||
IOPriority ioprio = 0;
|
IOPriority ioprio = 0;
|
||||||
// Other OSes masquerading as Linux (NetBSD?) don't have this syscall
|
// 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
|
/* 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
|
* mis-identify a string or fail, if comm or cmdline had been unsuitably
|
||||||
* modified by the process */
|
* modified by the process */
|
||||||
const char *token;
|
|
||||||
const char *tokenBase;
|
const char *tokenBase;
|
||||||
size_t tokenLen;
|
size_t tokenLen;
|
||||||
const size_t commLen = strlen(comm);
|
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) {
|
for (tokenBase = token; *token && *token != '\n'; ++token) {
|
||||||
if (*token == '/') {
|
if (*token == '/') {
|
||||||
tokenBase = token + 1;
|
tokenBase = token + 1;
|
||||||
@ -394,6 +367,16 @@ void LinuxProcess_makeCommandStr(Process* this) {
|
|||||||
char *str = strStart;
|
char *str = strStart;
|
||||||
|
|
||||||
int cmdlineBasenameOffset = lp->procCmdlineBasenameOffset;
|
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) { /* fall back to cmdline */
|
||||||
if (showMergedCommand && !procExe && procComm && strlen(procComm)) { /* Prefix column with comm */
|
if (showMergedCommand && !procExe && procComm && strlen(procComm)) { /* Prefix column with comm */
|
||||||
@ -411,11 +394,11 @@ void LinuxProcess_makeCommandStr(Process* this) {
|
|||||||
if (showProgramPath) {
|
if (showProgramPath) {
|
||||||
(void) stpcpyWithNewlineConversion(str, cmdline);
|
(void) stpcpyWithNewlineConversion(str, cmdline);
|
||||||
mc->baseStart = cmdlineBasenameOffset;
|
mc->baseStart = cmdlineBasenameOffset;
|
||||||
mc->baseEnd = lp->procCmdlineBasenameEnd;
|
mc->baseEnd = cmdlineBasenameEnd;
|
||||||
} else {
|
} else {
|
||||||
(void) stpcpyWithNewlineConversion(str, cmdline + cmdlineBasenameOffset);
|
(void) stpcpyWithNewlineConversion(str, cmdline + cmdlineBasenameOffset);
|
||||||
mc->baseStart = 0;
|
mc->baseStart = 0;
|
||||||
mc->baseEnd = lp->procCmdlineBasenameEnd - cmdlineBasenameOffset;
|
mc->baseEnd = cmdlineBasenameEnd - cmdlineBasenameOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mc->sep1) {
|
if (mc->sep1) {
|
||||||
@ -430,6 +413,9 @@ void LinuxProcess_makeCommandStr(Process* this) {
|
|||||||
int exeBasenameOffset = lp->procExeBasenameOffset;
|
int exeBasenameOffset = lp->procExeBasenameOffset;
|
||||||
int exeBasenameLen = exeLen - exeBasenameOffset;
|
int exeBasenameLen = exeLen - exeBasenameOffset;
|
||||||
|
|
||||||
|
assert(exeBasenameOffset >= 0);
|
||||||
|
assert(exeBasenameOffset <= (int)strlen(procExe));
|
||||||
|
|
||||||
/* Start with copying exe */
|
/* Start with copying exe */
|
||||||
if (showProgramPath) {
|
if (showProgramPath) {
|
||||||
str = stpcpy(str, procExe);
|
str = stpcpy(str, procExe);
|
||||||
@ -536,36 +522,36 @@ static void LinuxProcess_writeCommand(const Process* this, int attr, int baseAtt
|
|||||||
if(lp->procExeDeleted)
|
if(lp->procExeDeleted)
|
||||||
baseAttr = CRT_colors[FAILED_READ];
|
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.commEnd) {
|
||||||
if (!lp->mergedCommand.separateComm && commStart == baseStart && highlightBaseName) {
|
if (!lp->mergedCommand.separateComm && commStart == baseStart && highlightBaseName) {
|
||||||
/* If it was matched with procExe's basename, make it bold if needed */
|
/* If it was matched with procExe's basename, make it bold if needed */
|
||||||
if (commEnd > baseEnd) {
|
if (commEnd > baseEnd) {
|
||||||
RichString_setAttrn(str, A_BOLD | baseAttr, baseStart, baseEnd - 1);
|
RichString_setAttrn(str, A_BOLD | baseAttr, baseStart, baseEnd - baseStart);
|
||||||
RichString_setAttrn(str, A_BOLD | commAttr, baseEnd, commEnd - 1);
|
RichString_setAttrn(str, A_BOLD | commAttr, baseEnd, commEnd - baseEnd);
|
||||||
} else if (commEnd < baseEnd) {
|
} else if (commEnd < baseEnd) {
|
||||||
RichString_setAttrn(str, A_BOLD | commAttr, commStart, commEnd - 1);
|
RichString_setAttrn(str, A_BOLD | commAttr, commStart, commEnd - commStart);
|
||||||
RichString_setAttrn(str, A_BOLD | baseAttr, commEnd, baseEnd - 1);
|
RichString_setAttrn(str, A_BOLD | baseAttr, commEnd, baseEnd - commEnd);
|
||||||
} else {
|
} else {
|
||||||
// Actually should be highlighted commAttr, but marked baseAttr to reduce visual noise
|
// 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;
|
baseStart = baseEnd;
|
||||||
} else {
|
} else {
|
||||||
RichString_setAttrn(str, commAttr, commStart, commEnd - 1);
|
RichString_setAttrn(str, commAttr, commStart, commEnd - commStart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (baseStart < baseEnd && highlightBaseName) {
|
if (baseStart < baseEnd && highlightBaseName) {
|
||||||
RichString_setAttrn(str, baseAttr, baseStart, baseEnd - 1);
|
RichString_setAttrn(str, baseAttr, baseStart, baseEnd - baseStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mc->sep1)
|
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)
|
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) {
|
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, " ");
|
buf = stpcpy(buf, " ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n -= (buf - buffer);
|
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] );
|
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);
|
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';
|
char buffer[256]; buffer[255] = '\0';
|
||||||
int attr = CRT_colors[DEFAULT_COLOR];
|
int attr = CRT_colors[DEFAULT_COLOR];
|
||||||
size_t n = sizeof(buffer) - 1;
|
size_t n = sizeof(buffer) - 1;
|
||||||
switch ((int)field) {
|
switch (field) {
|
||||||
case TTY_NR: {
|
case TTY_NR: {
|
||||||
if (lp->ttyDevice) {
|
if (lp->ttyDevice) {
|
||||||
xSnprintf(buffer, n, "%-9s", lp->ttyDevice + 5 /* skip "/dev/" */);
|
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 CMINFLT: Process_colorNumber(str, lp->cminflt, coloring); return;
|
||||||
case CMAJFLT: Process_colorNumber(str, lp->cmajflt, 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_DRS: Process_humanNumber(str, lp->m_drs * pageSizeKB, coloring); return;
|
||||||
case M_DT: Process_humanNumber(str, lp->m_dt * CRT_pageSizeKB, coloring); return;
|
case M_DT: Process_humanNumber(str, lp->m_dt * pageSizeKB, coloring); return;
|
||||||
case M_LRS:
|
case M_LRS:
|
||||||
if (lp->m_lrs) {
|
if (lp->m_lrs) {
|
||||||
Process_humanNumber(str, lp->m_lrs * CRT_pageSizeKB, coloring);
|
Process_humanNumber(str, lp->m_lrs * pageSizeKB, coloring);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = CRT_colors[PROCESS_SHADOW];
|
attr = CRT_colors[PROCESS_SHADOW];
|
||||||
xSnprintf(buffer, n, " N/A ");
|
xSnprintf(buffer, n, " N/A ");
|
||||||
break;
|
break;
|
||||||
case M_TRS: Process_humanNumber(str, lp->m_trs * 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 * CRT_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_PSS: Process_humanNumber(str, lp->m_pss, coloring); return;
|
||||||
case M_SWAP: Process_humanNumber(str, lp->m_swap, coloring); return;
|
case M_SWAP: Process_humanNumber(str, lp->m_swap, coloring); return;
|
||||||
case M_PSSWP: Process_humanNumber(str, lp->m_psswp, 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
|
#ifdef HAVE_OPENVZ
|
||||||
case CTID: xSnprintf(buffer, n, "%-8s ", lp->ctid ? lp->ctid : ""); break;
|
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
|
#endif
|
||||||
#ifdef HAVE_VSERVER
|
#ifdef HAVE_VSERVER
|
||||||
case VXID: xSnprintf(buffer, n, "%5u ", lp->vxid); break;
|
case VXID: xSnprintf(buffer, n, "%5u ", lp->vxid); break;
|
||||||
@ -720,59 +707,58 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case PROC_COMM: {
|
case PROC_COMM: {
|
||||||
|
const char* procComm;
|
||||||
if (lp->procComm) {
|
if (lp->procComm) {
|
||||||
attr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_COMM : PROCESS_COMM];
|
attr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_COMM : PROCESS_COMM];
|
||||||
/* 15 being (TASK_COMM_LEN - 1) */
|
procComm = lp->procComm;
|
||||||
xSnprintf(buffer, n, "%-15.15s ", lp->procComm);
|
|
||||||
} else {
|
} else {
|
||||||
attr = CRT_colors[PROCESS_SHADOW];
|
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: {
|
case PROC_EXE: {
|
||||||
|
const char* procExe;
|
||||||
if (lp->procExe) {
|
if (lp->procExe) {
|
||||||
attr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_BASENAME : PROCESS_BASENAME];
|
attr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_BASENAME : PROCESS_BASENAME];
|
||||||
if (lp->procExeDeleted)
|
if (lp->procExeDeleted)
|
||||||
attr = CRT_colors[FAILED_READ];
|
attr = CRT_colors[FAILED_READ];
|
||||||
xSnprintf(buffer, n, "%-15.15s ", lp->procExe + lp->procExeBasenameOffset);
|
procExe = lp->procExe + lp->procExeBasenameOffset;
|
||||||
} else {
|
} else {
|
||||||
attr = CRT_colors[PROCESS_SHADOW];
|
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) {
|
if (!lp->cwd) {
|
||||||
xSnprintf(buffer, n, "%-25s ", "N/A");
|
|
||||||
attr = CRT_colors[PROCESS_SHADOW];
|
attr = CRT_colors[PROCESS_SHADOW];
|
||||||
|
cwd = "N/A";
|
||||||
} else if (String_startsWith(lp->cwd, "/proc/") && strstr(lp->cwd, " (deleted)") != NULL) {
|
} else if (String_startsWith(lp->cwd, "/proc/") && strstr(lp->cwd, " (deleted)") != NULL) {
|
||||||
xSnprintf(buffer, n, "%-25s ", "main thread terminated");
|
|
||||||
attr = CRT_colors[PROCESS_SHADOW];
|
attr = CRT_colors[PROCESS_SHADOW];
|
||||||
|
cwd = "main thread terminated";
|
||||||
} else {
|
} else {
|
||||||
xSnprintf(buffer, n, "%-25.25s ", lp->cwd);
|
cwd = lp->cwd;
|
||||||
}
|
}
|
||||||
break;
|
Process_printLeftAlignedField(str, attr, cwd, 25);
|
||||||
|
return;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
Process_writeField(this, str, field);
|
Process_writeField(this, str, field);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RichString_append(str, attr, buffer);
|
RichString_appendWide(str, attr, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static long LinuxProcess_compare(const void* v1, const void* v2) {
|
static int LinuxProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
|
||||||
const LinuxProcess *p1, *p2;
|
const LinuxProcess* p1 = (const LinuxProcess*)v1;
|
||||||
const Settings *settings = ((const Process*)v1)->settings;
|
const LinuxProcess* p2 = (const LinuxProcess*)v2;
|
||||||
|
|
||||||
if (settings->direction == 1) {
|
switch (key) {
|
||||||
p1 = (const LinuxProcess*)v1;
|
|
||||||
p2 = (const LinuxProcess*)v2;
|
|
||||||
} else {
|
|
||||||
p2 = (const LinuxProcess*)v1;
|
|
||||||
p1 = (const LinuxProcess*)v2;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ((int)settings->sortKey) {
|
|
||||||
case M_DRS:
|
case M_DRS:
|
||||||
return SPACESHIP_NUMBER(p2->m_drs, p1->m_drs);
|
return SPACESHIP_NUMBER(p2->m_drs, p1->m_drs);
|
||||||
case M_DT:
|
case M_DT:
|
||||||
@ -858,7 +844,7 @@ static long LinuxProcess_compare(const void* v1, const void* v2) {
|
|||||||
case CWD:
|
case CWD:
|
||||||
return SPACESHIP_NULLSTR(p1->cwd, p2->cwd);
|
return SPACESHIP_NULLSTR(p1->cwd, p2->cwd);
|
||||||
default:
|
default:
|
||||||
return Process_compare(v1, v2);
|
return Process_compareByKey_Base(v1, v2, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -871,8 +857,9 @@ const ProcessClass LinuxProcess_class = {
|
|||||||
.extends = Class(Process),
|
.extends = Class(Process),
|
||||||
.display = Process_display,
|
.display = Process_display,
|
||||||
.delete = Process_delete,
|
.delete = Process_delete,
|
||||||
.compare = LinuxProcess_compare
|
.compare = Process_compare
|
||||||
},
|
},
|
||||||
.writeField = LinuxProcess_writeField,
|
.writeField = LinuxProcess_writeField,
|
||||||
.getCommandStr = LinuxProcess_getCommandStr
|
.getCommandStr = LinuxProcess_getCommandStr,
|
||||||
|
.compareByKey = LinuxProcess_compareByKey
|
||||||
};
|
};
|
||||||
|
@ -18,85 +18,18 @@ in the source distribution for its full text.
|
|||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
|
|
||||||
|
|
||||||
#define PROCESS_FLAG_LINUX_IOPRIO 0x00000100
|
#define PROCESS_FLAG_LINUX_IOPRIO 0x00000100
|
||||||
#define PROCESS_FLAG_LINUX_OPENVZ 0x00000200
|
#define PROCESS_FLAG_LINUX_OPENVZ 0x00000200
|
||||||
#define PROCESS_FLAG_LINUX_VSERVER 0x00000400
|
#define PROCESS_FLAG_LINUX_VSERVER 0x00000400
|
||||||
#define PROCESS_FLAG_LINUX_CGROUP 0x00000800
|
#define PROCESS_FLAG_LINUX_CGROUP 0x00000800
|
||||||
#define PROCESS_FLAG_LINUX_OOM 0x00001000
|
#define PROCESS_FLAG_LINUX_OOM 0x00001000
|
||||||
#define PROCESS_FLAG_LINUX_SMAPS 0x00002000
|
#define PROCESS_FLAG_LINUX_SMAPS 0x00002000
|
||||||
#define PROCESS_FLAG_LINUX_CTXT 0x00004000
|
#define PROCESS_FLAG_LINUX_CTXT 0x00004000
|
||||||
#define PROCESS_FLAG_LINUX_SECATTR 0x00008000
|
#define PROCESS_FLAG_LINUX_SECATTR 0x00008000
|
||||||
#define PROCESS_FLAG_LINUX_LRS_FIX 0x00010000
|
#define PROCESS_FLAG_LINUX_LRS_FIX 0x00010000
|
||||||
#define PROCESS_FLAG_LINUX_CWD 0x00020000
|
#define PROCESS_FLAG_LINUX_CWD 0x00020000
|
||||||
|
#define PROCESS_FLAG_LINUX_DELAYACCT 0x00040000
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/* LinuxProcessMergedCommand is populated by LinuxProcess_makeCommandStr: It
|
/* LinuxProcessMergedCommand is populated by LinuxProcess_makeCommandStr: It
|
||||||
* contains the merged Command string, and the information needed by
|
* 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;
|
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;
|
extern const ProcessClass LinuxProcess_class;
|
||||||
|
|
||||||
|
@ -57,6 +57,16 @@ in the source distribution for its full text.
|
|||||||
#endif
|
#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) {
|
static FILE* fopenat(openat_arg_t openatArg, const char* pathname, const char* mode) {
|
||||||
assert(String_eq(mode, "r")); /* only currently supported mode */
|
assert(String_eq(mode, "r")); /* only currently supported mode */
|
||||||
|
|
||||||
@ -92,7 +102,7 @@ static void LinuxProcessList_initTtyDrivers(LinuxProcessList* this) {
|
|||||||
|
|
||||||
int numDrivers = 0;
|
int numDrivers = 0;
|
||||||
int allocd = 10;
|
int allocd = 10;
|
||||||
ttyDrivers = xMalloc(sizeof(TtyDriver) * allocd);
|
ttyDrivers = xMallocArray(allocd, sizeof(TtyDriver));
|
||||||
char* at = buf;
|
char* at = buf;
|
||||||
while (*at != '\0') {
|
while (*at != '\0') {
|
||||||
at = strchr(at, ' '); // skip first token
|
at = strchr(at, ' '); // skip first token
|
||||||
@ -126,7 +136,7 @@ static void LinuxProcessList_initTtyDrivers(LinuxProcessList* this) {
|
|||||||
numDrivers++;
|
numDrivers++;
|
||||||
if (numDrivers == allocd) {
|
if (numDrivers == allocd) {
|
||||||
allocd += 10;
|
allocd += 10;
|
||||||
ttyDrivers = xRealloc(ttyDrivers, sizeof(TtyDriver) * allocd);
|
ttyDrivers = xReallocArray(ttyDrivers, allocd, sizeof(TtyDriver));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
numDrivers++;
|
numDrivers++;
|
||||||
@ -198,39 +208,39 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
|
|||||||
ProcessList_init(pl, Class(LinuxProcess), usersTable, pidMatchList, userId);
|
ProcessList_init(pl, Class(LinuxProcess), usersTable, pidMatchList, userId);
|
||||||
LinuxProcessList_initTtyDrivers(this);
|
LinuxProcessList_initTtyDrivers(this);
|
||||||
|
|
||||||
#ifdef HAVE_DELAYACCT
|
// Initialize page size
|
||||||
LinuxProcessList_initNetlinkSocket(this);
|
pageSize = sysconf(_SC_PAGESIZE);
|
||||||
#endif
|
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+)
|
// Initialize clock ticks
|
||||||
FILE* file = fopen(PROCDIR "/self/smaps_rollup", "r");
|
jiffy = sysconf(_SC_CLK_TCK);
|
||||||
if (file != NULL) {
|
if (jiffy == -1)
|
||||||
this->haveSmapsRollup = true;
|
CRT_fatalError("Cannot get clock ticks by sysconf(_SC_CLK_TCK)");
|
||||||
fclose(file);
|
|
||||||
} else {
|
|
||||||
this->haveSmapsRollup = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read btime
|
// Test /proc/PID/smaps_rollup availability (faster to parse, Linux 4.14+)
|
||||||
|
this->haveSmapsRollup = (access(PROCDIR "/self/smaps_rollup", R_OK) == 0);
|
||||||
|
|
||||||
|
// Read btime (the kernel boot time, as number of seconds since the epoch)
|
||||||
{
|
{
|
||||||
FILE* statfile = fopen(PROCSTATFILE, "r");
|
FILE* statfile = fopen(PROCSTATFILE, "r");
|
||||||
if (statfile == NULL) {
|
if (statfile == NULL)
|
||||||
CRT_fatalError("Cannot open " PROCSTATFILE);
|
CRT_fatalError("Cannot open " PROCSTATFILE);
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
char buffer[PROC_LINE_LENGTH + 1];
|
char buffer[PROC_LINE_LENGTH + 1];
|
||||||
if (fgets(buffer, sizeof(buffer), statfile) == NULL) {
|
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);
|
|
||||||
}
|
|
||||||
break;
|
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);
|
fclose(statfile);
|
||||||
|
|
||||||
|
if (!btime)
|
||||||
|
CRT_fatalError("No btime in " PROCSTATFILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize CPU count
|
// Initialize CPU count
|
||||||
@ -267,16 +277,7 @@ void ProcessList_delete(ProcessList* pl) {
|
|||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned long long LinuxProcess_adjustTime(unsigned long long t) {
|
static inline unsigned long long LinuxProcessList_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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return t * 100 / jiffy;
|
return t * 100 / jiffy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,13 +330,13 @@ static bool LinuxProcessList_readStatFile(Process* process, openat_arg_t procFd,
|
|||||||
location += 1;
|
location += 1;
|
||||||
lp->cmajflt = strtoull(location, &location, 10);
|
lp->cmajflt = strtoull(location, &location, 10);
|
||||||
location += 1;
|
location += 1;
|
||||||
lp->utime = LinuxProcess_adjustTime(strtoull(location, &location, 10));
|
lp->utime = LinuxProcessList_adjustTime(strtoull(location, &location, 10));
|
||||||
location += 1;
|
location += 1;
|
||||||
lp->stime = LinuxProcess_adjustTime(strtoull(location, &location, 10));
|
lp->stime = LinuxProcessList_adjustTime(strtoull(location, &location, 10));
|
||||||
location += 1;
|
location += 1;
|
||||||
lp->cutime = LinuxProcess_adjustTime(strtoull(location, &location, 10));
|
lp->cutime = LinuxProcessList_adjustTime(strtoull(location, &location, 10));
|
||||||
location += 1;
|
location += 1;
|
||||||
lp->cstime = LinuxProcess_adjustTime(strtoull(location, &location, 10));
|
lp->cstime = LinuxProcessList_adjustTime(strtoull(location, &location, 10));
|
||||||
location += 1;
|
location += 1;
|
||||||
process->priority = strtol(location, &location, 10);
|
process->priority = strtol(location, &location, 10);
|
||||||
location += 1;
|
location += 1;
|
||||||
@ -345,7 +346,7 @@ static bool LinuxProcessList_readStatFile(Process* process, openat_arg_t procFd,
|
|||||||
location += 1;
|
location += 1;
|
||||||
location = strchr(location, ' ') + 1;
|
location = strchr(location, ' ') + 1;
|
||||||
if (process->starttime_ctime == 0) {
|
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 {
|
} else {
|
||||||
location = strchr(location, ' ') + 1;
|
location = strchr(location, ' ') + 1;
|
||||||
}
|
}
|
||||||
@ -483,7 +484,7 @@ static inline uint64_t fast_strtoull_hex(char **str, int maxlen) {
|
|||||||
return result;
|
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)
|
if (!data)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -573,7 +574,7 @@ static uint64_t LinuxProcessList_calcLibSize(openat_arg_t procFd) {
|
|||||||
|
|
||||||
Hashtable_delete(ht);
|
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) {
|
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);
|
fclose(statmfile);
|
||||||
|
|
||||||
if (r == 7) {
|
if (r == 7) {
|
||||||
|
process->super.m_virt *= pageSizeKB;
|
||||||
|
process->super.m_resident *= pageSizeKB;
|
||||||
|
|
||||||
if (tmp_m_lrs) {
|
if (tmp_m_lrs) {
|
||||||
process->m_lrs = tmp_m_lrs;
|
process->m_lrs = tmp_m_lrs;
|
||||||
} else if (performLookup) {
|
} else if (performLookup) {
|
||||||
@ -947,12 +951,19 @@ static int handleNetlinkMsg(struct nl_msg* nlmsg, void* linuxProcess) {
|
|||||||
static void LinuxProcessList_readDelayAcctData(LinuxProcessList* this, LinuxProcess* process) {
|
static void LinuxProcessList_readDelayAcctData(LinuxProcessList* this, LinuxProcess* process) {
|
||||||
struct nl_msg* msg;
|
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) {
|
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())) {
|
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)) {
|
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) {
|
if (nl_send_sync(this->netlink_socket, msg) < 0) {
|
||||||
process->swapin_delay_percent = NAN;
|
goto delayacct_failure;
|
||||||
process->blkio_delay_percent = NAN;
|
|
||||||
process->cpu_delay_percent = NAN;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nl_recvmsgs_default(this->netlink_socket) < 0) {
|
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
|
#endif
|
||||||
@ -1363,9 +1378,9 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* period might be 0 after system sleep */
|
/* period might be 0 after system sleep */
|
||||||
float percent_cpu = (period < 1e-6) ? 0.0f : ((lp->utime + lp->stime - lasttimes) / period * 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_cpu = CLAMP(percent_cpu, 0.0F, cpus * 100.0F);
|
||||||
proc->percent_mem = (proc->m_resident * CRT_pageSizeKB) / (double)(pl->totalMem) * 100.0;
|
proc->percent_mem = proc->m_resident / (double)(pl->totalMem) * 100.0;
|
||||||
|
|
||||||
if (!preExisting) {
|
if (!preExisting) {
|
||||||
|
|
||||||
@ -1411,7 +1426,9 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DELAYACCT
|
#ifdef HAVE_DELAYACCT
|
||||||
LinuxProcessList_readDelayAcctData(this, lp);
|
if (settings->flags & PROCESS_FLAG_LINUX_DELAYACCT) {
|
||||||
|
LinuxProcessList_readDelayAcctData(this, lp);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (settings->flags & PROCESS_FLAG_LINUX_CGROUP) {
|
if (settings->flags & PROCESS_FLAG_LINUX_CGROUP) {
|
||||||
@ -1785,7 +1802,9 @@ static void scanCPUFreqencyFromCPUinfo(LinuxProcessList* this) {
|
|||||||
continue;
|
continue;
|
||||||
} else if (
|
} 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, "cpu MHz: %lf", &frequency) == 1) ||
|
||||||
|
(sscanf(buffer, "clock : %lfMHz", &frequency) == 1) ||
|
||||||
|
(sscanf(buffer, "clock: %lfMHz", &frequency) == 1)
|
||||||
) {
|
) {
|
||||||
if (cpuid < 0 || cpuid > (cpus - 1)) {
|
if (cpuid < 0 || cpuid > (cpus - 1)) {
|
||||||
continue;
|
continue;
|
||||||
@ -1824,41 +1843,6 @@ static void LinuxProcessList_scanCPUFrequency(LinuxProcessList* this) {
|
|||||||
scanCPUFreqencyFromCPUinfo(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) {
|
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
LinuxProcessList* this = (LinuxProcessList*) super;
|
LinuxProcessList* this = (LinuxProcessList*) super;
|
||||||
const Settings* settings = super->settings;
|
const Settings* settings = super->settings;
|
||||||
@ -1876,7 +1860,7 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
|||||||
|
|
||||||
#ifdef HAVE_SENSORS_SENSORS_H
|
#ifdef HAVE_SENSORS_SENSORS_H
|
||||||
if (settings->showCPUTemperature)
|
if (settings->showCPUTemperature)
|
||||||
LinuxProcessList_scanCPUTemperature(this);
|
LibSensors_getCPUTemperatures(this->cpus, this->super.cpuCount);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// in pause mode only gather global data for meters (CPU/memory/...)
|
// in pause mode only gather global data for meters (CPU/memory/...)
|
||||||
|
@ -65,9 +65,7 @@ in the source distribution for its full text.
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, (int)M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
|
const ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
|
||||||
|
|
||||||
int Platform_numberOfFields = LAST_PROCESSFIELD;
|
|
||||||
|
|
||||||
const SignalItem Platform_signals[] = {
|
const SignalItem Platform_signals[] = {
|
||||||
{ .name = " 0 Cancel", .number = 0 },
|
{ .name = " 0 Cancel", .number = 0 },
|
||||||
|
@ -18,9 +18,7 @@ in the source distribution for its full text.
|
|||||||
#include "ProcessLocksScreen.h"
|
#include "ProcessLocksScreen.h"
|
||||||
#include "SignalsPanel.h"
|
#include "SignalsPanel.h"
|
||||||
|
|
||||||
extern ProcessField Platform_defaultFields[];
|
extern const ProcessField Platform_defaultFields[];
|
||||||
|
|
||||||
extern int Platform_numberOfFields;
|
|
||||||
|
|
||||||
extern const SignalItem Platform_signals[];
|
extern const SignalItem Platform_signals[];
|
||||||
|
|
||||||
|
@ -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]);
|
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) {
|
static void PressureStallMeter_display(const Object* cast, RichString* out) {
|
||||||
const Meter* this = (const Meter*)cast;
|
const Meter* this = (const Meter*)cast;
|
||||||
char buffer[20];
|
char buffer[20];
|
||||||
xSnprintf(buffer, sizeof(buffer), "%.2lf%% ", this->values[0]);
|
xSnprintf(buffer, sizeof(buffer), "%5.2lf%% ", this->values[0]);
|
||||||
RichString_write(out, CRT_colors[PRESSURE_STALL_TEN], buffer);
|
RichString_writeAscii(out, CRT_colors[PRESSURE_STALL_TEN], buffer);
|
||||||
xSnprintf(buffer, sizeof(buffer), "%.2lf%% ", this->values[1]);
|
xSnprintf(buffer, sizeof(buffer), "%5.2lf%% ", this->values[1]);
|
||||||
RichString_append(out, CRT_colors[PRESSURE_STALL_SIXTY], buffer);
|
RichString_appendAscii(out, CRT_colors[PRESSURE_STALL_SIXTY], buffer);
|
||||||
xSnprintf(buffer, sizeof(buffer), "%.2lf%% ", this->values[2]);
|
xSnprintf(buffer, sizeof(buffer), "%5.2lf%% ", this->values[2]);
|
||||||
RichString_append(out, CRT_colors[PRESSURE_STALL_THREEHUNDRED], buffer);
|
RichString_appendAscii(out, CRT_colors[PRESSURE_STALL_THREEHUNDRED], buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MeterClass PressureStallCPUSomeMeter_class = {
|
const MeterClass PressureStallCPUSomeMeter_class = {
|
||||||
|
53
linux/ProcessField.h
Normal file
53
linux/ProcessField.h
Normal file
@ -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 */
|
@ -35,7 +35,7 @@ static bool hasSELinuxMount(void) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sfbuf.f_type != SELINUX_MAGIC) {
|
if ((uint32_t)sfbuf.f_type != (uint32_t)SELINUX_MAGIC) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,9 +267,9 @@ static void SystemdMeter_display(ATTR_UNUSED const Object* cast, RichString* out
|
|||||||
char buffer[16];
|
char buffer[16];
|
||||||
|
|
||||||
int color = (systemState && 0 == strcmp(systemState, "running")) ? METER_VALUE_OK : METER_VALUE_ERROR;
|
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) {
|
if (nFailedUnits == INVALID_VALUE) {
|
||||||
buffer[0] = '?';
|
buffer[0] = '?';
|
||||||
@ -277,9 +277,9 @@ static void SystemdMeter_display(ATTR_UNUSED const Object* cast, RichString* out
|
|||||||
} else {
|
} else {
|
||||||
xSnprintf(buffer, sizeof(buffer), "%u", nFailedUnits);
|
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) {
|
if (nNames == INVALID_VALUE) {
|
||||||
buffer[0] = '?';
|
buffer[0] = '?';
|
||||||
@ -287,9 +287,9 @@ static void SystemdMeter_display(ATTR_UNUSED const Object* cast, RichString* out
|
|||||||
} else {
|
} else {
|
||||||
xSnprintf(buffer, sizeof(buffer), "%u", nNames);
|
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) {
|
if (nJobs == INVALID_VALUE) {
|
||||||
buffer[0] = '?';
|
buffer[0] = '?';
|
||||||
@ -297,9 +297,9 @@ static void SystemdMeter_display(ATTR_UNUSED const Object* cast, RichString* out
|
|||||||
} else {
|
} else {
|
||||||
xSnprintf(buffer, sizeof(buffer), "%u", nJobs);
|
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) {
|
if (nInstalledJobs == INVALID_VALUE) {
|
||||||
buffer[0] = '?';
|
buffer[0] = '?';
|
||||||
@ -307,9 +307,9 @@ static void SystemdMeter_display(ATTR_UNUSED const Object* cast, RichString* out
|
|||||||
} else {
|
} else {
|
||||||
xSnprintf(buffer, sizeof(buffer), "%u", nInstalledJobs);
|
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[] = {
|
static const int SystemdMeter_attributes[] = {
|
||||||
|
@ -37,17 +37,19 @@ static void ZramMeter_updateValues(Meter* this, char* buffer, size_t size) {
|
|||||||
static void ZramMeter_display(const Object* cast, RichString* out) {
|
static void ZramMeter_display(const Object* cast, RichString* out) {
|
||||||
char buffer[50];
|
char buffer[50];
|
||||||
const Meter* this = (const Meter*)cast;
|
const Meter* this = (const Meter*)cast;
|
||||||
RichString_write(out, CRT_colors[METER_TEXT], ":");
|
|
||||||
Meter_humanUnit(buffer, this->total, sizeof(buffer));
|
|
||||||
|
|
||||||
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));
|
Meter_humanUnit(buffer, this->values[0], sizeof(buffer));
|
||||||
RichString_append(out, CRT_colors[METER_TEXT], " used:");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], " used:");
|
||||||
RichString_append(out, CRT_colors[METER_VALUE], buffer);
|
RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
|
||||||
|
|
||||||
Meter_humanUnit(buffer, this->values[1], sizeof(buffer));
|
Meter_humanUnit(buffer, this->values[1], sizeof(buffer));
|
||||||
RichString_append(out, CRT_colors[METER_TEXT], " uncompressed:");
|
RichString_appendAscii(out, CRT_colors[METER_TEXT], " uncompressed:");
|
||||||
RichString_append(out, CRT_colors[METER_VALUE], buffer);
|
RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MeterClass ZramMeter_class = {
|
const MeterClass ZramMeter_class = {
|
||||||
|
@ -16,7 +16,7 @@ in the source distribution for its full text.
|
|||||||
#include "XUtils.h"
|
#include "XUtils.h"
|
||||||
|
|
||||||
|
|
||||||
ProcessFieldData Process_fields[] = {
|
const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
|
||||||
[0] = {
|
[0] = {
|
||||||
.name = "",
|
.name = "",
|
||||||
.title = NULL,
|
.title = NULL,
|
||||||
@ -25,9 +25,10 @@ ProcessFieldData Process_fields[] = {
|
|||||||
},
|
},
|
||||||
[PID] = {
|
[PID] = {
|
||||||
.name = "PID",
|
.name = "PID",
|
||||||
.title = " PID ",
|
.title = "PID",
|
||||||
.description = "Process/thread ID",
|
.description = "Process/thread ID",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
|
.pidColumn = true,
|
||||||
},
|
},
|
||||||
[COMM] = {
|
[COMM] = {
|
||||||
.name = "Command",
|
.name = "Command",
|
||||||
@ -43,21 +44,24 @@ ProcessFieldData Process_fields[] = {
|
|||||||
},
|
},
|
||||||
[PPID] = {
|
[PPID] = {
|
||||||
.name = "PPID",
|
.name = "PPID",
|
||||||
.title = " PPID ",
|
.title = "PPID",
|
||||||
.description = "Parent process ID",
|
.description = "Parent process ID",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
|
.pidColumn = true,
|
||||||
},
|
},
|
||||||
[PGRP] = {
|
[PGRP] = {
|
||||||
.name = "PGRP",
|
.name = "PGRP",
|
||||||
.title = " PGRP ",
|
.title = "PGRP",
|
||||||
.description = "Process group ID",
|
.description = "Process group ID",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
|
.pidColumn = true,
|
||||||
},
|
},
|
||||||
[SESSION] = {
|
[SESSION] = {
|
||||||
.name = "SESSION",
|
.name = "SESSION",
|
||||||
.title = " SESN ",
|
.title = "SESN",
|
||||||
.description = "Process's session ID",
|
.description = "Process's session ID",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
|
.pidColumn = true,
|
||||||
},
|
},
|
||||||
[TTY_NR] = {
|
[TTY_NR] = {
|
||||||
.name = "TTY_NR",
|
.name = "TTY_NR",
|
||||||
@ -67,9 +71,10 @@ ProcessFieldData Process_fields[] = {
|
|||||||
},
|
},
|
||||||
[TPGID] = {
|
[TPGID] = {
|
||||||
.name = "TPGID",
|
.name = "TPGID",
|
||||||
.title = " TPGID ",
|
.title = "TPGID",
|
||||||
.description = "Process ID of the fg process group of the controlling terminal",
|
.description = "Process ID of the fg process group of the controlling terminal",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
|
.pidColumn = true,
|
||||||
},
|
},
|
||||||
[MINFLT] = {
|
[MINFLT] = {
|
||||||
.name = "MINFLT",
|
.name = "MINFLT",
|
||||||
@ -163,26 +168,11 @@ ProcessFieldData Process_fields[] = {
|
|||||||
},
|
},
|
||||||
[TGID] = {
|
[TGID] = {
|
||||||
.name = "TGID",
|
.name = "TGID",
|
||||||
.title = " TGID ",
|
.title = "TGID",
|
||||||
.description = "Thread group ID (i.e. process ID)",
|
.description = "Thread group ID (i.e. process ID)",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
|
.pidColumn = true,
|
||||||
},
|
},
|
||||||
[LAST_PROCESSFIELD] = {
|
|
||||||
.name = "*** report bug! ***",
|
|
||||||
.title = NULL,
|
|
||||||
.description = NULL,
|
|
||||||
.flags = 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
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) {
|
Process* OpenBSDProcess_new(const Settings* settings) {
|
||||||
@ -209,28 +199,20 @@ static void OpenBSDProcess_writeField(const Process* this, RichString* str, Proc
|
|||||||
Process_writeField(this, str, field);
|
Process_writeField(this, str, field);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RichString_append(str, attr, buffer);
|
RichString_appendWide(str, attr, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static long OpenBSDProcess_compare(const void* v1, const void* v2) {
|
static int OpenBSDProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
|
||||||
const OpenBSDProcess *p1, *p2;
|
const OpenBSDProcess* p1 = (const OpenBSDProcess*)v1;
|
||||||
const Settings *settings = ((const Process*)v1)->settings;
|
const OpenBSDProcess* p2 = (const OpenBSDProcess*)v2;
|
||||||
|
|
||||||
if (settings->direction == 1) {
|
|
||||||
p1 = (const OpenBSDProcess*)v1;
|
|
||||||
p2 = (const OpenBSDProcess*)v2;
|
|
||||||
} else {
|
|
||||||
p2 = (const OpenBSDProcess*)v1;
|
|
||||||
p1 = (const OpenBSDProcess*)v2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove if actually used
|
// remove if actually used
|
||||||
(void)p1; (void)p2;
|
(void)p1; (void)p2;
|
||||||
|
|
||||||
switch (settings->sortKey) {
|
switch (key) {
|
||||||
// add OpenBSD-specific fields here
|
// add OpenBSD-specific fields here
|
||||||
default:
|
default:
|
||||||
return Process_compare(v1, v2);
|
return Process_compareByKey_Base(v1, v2, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,9 +221,10 @@ const ProcessClass OpenBSDProcess_class = {
|
|||||||
.extends = Class(Process),
|
.extends = Class(Process),
|
||||||
.display = Process_display,
|
.display = Process_display,
|
||||||
.delete = Process_delete,
|
.delete = Process_delete,
|
||||||
.compare = OpenBSDProcess_compare
|
.compare = Process_compare
|
||||||
},
|
},
|
||||||
.writeField = OpenBSDProcess_writeField,
|
.writeField = OpenBSDProcess_writeField,
|
||||||
|
.compareByKey = OpenBSDProcess_compareByKey
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Process_isThread(const Process* this) {
|
bool Process_isThread(const Process* this) {
|
||||||
|
@ -15,11 +15,6 @@ in the source distribution for its full text.
|
|||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
|
|
||||||
|
|
||||||
typedef enum OpenBSDProcessFields_ {
|
|
||||||
// Add platform-specific fields here, with ids >= 100
|
|
||||||
LAST_PROCESSFIELD = 100,
|
|
||||||
} OpenBSDProcessField;
|
|
||||||
|
|
||||||
typedef struct OpenBSDProcess_ {
|
typedef struct OpenBSDProcess_ {
|
||||||
Process super;
|
Process super;
|
||||||
} OpenBSDProcess;
|
} OpenBSDProcess;
|
||||||
@ -30,9 +25,7 @@ typedef struct OpenBSDProcess_ {
|
|||||||
|
|
||||||
extern const ProcessClass OpenBSDProcess_class;
|
extern const ProcessClass OpenBSDProcess_class;
|
||||||
|
|
||||||
extern ProcessFieldData Process_fields[];
|
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
|
||||||
|
|
||||||
extern ProcessPidColumn Process_pidColumns[];
|
|
||||||
|
|
||||||
Process* OpenBSDProcess_new(const Settings* settings);
|
Process* OpenBSDProcess_new(const Settings* settings);
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ in the source distribution for its full text.
|
|||||||
|
|
||||||
#include "OpenBSDProcessList.h"
|
#include "OpenBSDProcessList.h"
|
||||||
|
|
||||||
#include <err.h>
|
|
||||||
#include <kvm.h>
|
#include <kvm.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -34,6 +33,8 @@ in the source distribution for its full text.
|
|||||||
|
|
||||||
|
|
||||||
static long fscale;
|
static long fscale;
|
||||||
|
static int pageSize;
|
||||||
|
static int pageSizeKB;
|
||||||
|
|
||||||
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
|
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
|
||||||
const int mib[] = { CTL_HW, HW_NCPU };
|
const int mib[] = { CTL_HW, HW_NCPU };
|
||||||
@ -55,9 +56,13 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
|
|||||||
|
|
||||||
size = sizeof(fscale);
|
size = sizeof(fscale);
|
||||||
if (sysctl(fmib, 2, &fscale, &size, NULL, 0) < 0) {
|
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++) {
|
for (int i = 0; i <= pl->cpuCount; i++) {
|
||||||
CPUData* d = opl->cpus + i;
|
CPUData* d = opl->cpus + i;
|
||||||
d->totalTime = 1;
|
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);
|
opl->kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
|
||||||
if (opl->kd == NULL) {
|
if (opl->kd == NULL) {
|
||||||
errx(1, "kvm_open: %s", errbuf);
|
CRT_fatalError("kvm_openfiles() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
return pl;
|
return pl;
|
||||||
@ -91,11 +96,11 @@ static void OpenBSDProcessList_scanMemoryInfo(ProcessList* pl) {
|
|||||||
size_t size_uvmexp = sizeof(uvmexp);
|
size_t size_uvmexp = sizeof(uvmexp);
|
||||||
|
|
||||||
if (sysctl(uvmexp_mib, 2, &uvmexp, &size_uvmexp, NULL, 0) < 0) {
|
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->totalMem = uvmexp.npages * pageSizeKB;
|
||||||
pl->usedMem = (uvmexp.npages - uvmexp.free - uvmexp.paging) * CRT_pageSizeKB;
|
pl->usedMem = (uvmexp.npages - uvmexp.free - uvmexp.paging) * pageSizeKB;
|
||||||
|
|
||||||
// Taken from OpenBSD systat/iostat.c, top/machine.c and uvm_sysctl(9)
|
// Taken from OpenBSD systat/iostat.c, top/machine.c and uvm_sysctl(9)
|
||||||
const int bcache_mib[] = { CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT };
|
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);
|
size_t size_bcstats = sizeof(bcstats);
|
||||||
|
|
||||||
if (sysctl(bcache_mib, 3, &bcstats, &size_bcstats, NULL, 0) < 0) {
|
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>
|
* 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_virt = kproc->p_vm_dsize * pageSizeKB;
|
||||||
proc->m_resident = kproc->p_vm_rssize;
|
proc->m_resident = kproc->p_vm_rssize * pageSizeKB;
|
||||||
proc->percent_mem = (proc->m_resident * CRT_pageSizeKB) / (double)(this->super.totalMem) * 100.0;
|
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->percent_cpu = CLAMP(getpcpu(kproc), 0.0, this->super.cpuCount * 100.0);
|
||||||
//proc->nlwp = kproc->p_numthreads;
|
//proc->nlwp = kproc->p_numthreads;
|
||||||
proc->nice = kproc->p_nice - 20;
|
proc->nice = kproc->p_nice - 20;
|
||||||
|
@ -42,9 +42,7 @@ in the source distribution for its full text.
|
|||||||
#include "XUtils.h"
|
#include "XUtils.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 };
|
||||||
|
|
||||||
int Platform_numberOfFields = LAST_PROCESSFIELD;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See /usr/include/sys/signal.h
|
* See /usr/include/sys/signal.h
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user