62 Commits
3.0.4 ... 3.0.5

Author SHA1 Message Date
ce6d60e7de Release 3.0.5 2021-01-11 18:18:21 +01:00
5d92a9f20d Merge branch 'fix-palette2' of deviant/htop 2021-01-11 17:45:59 +01:00
b3500ac3b7 Clarify that only the main screen function bar is optionally hidden 2021-01-11 13:50:34 +01:00
2ba8a81d47 Fix clearing the last line in setup on function bar change (thanks cgzones) 2021-01-11 13:47:33 +01:00
V
f2f1c99ad9 Fix white text in the Light Terminal colour scheme 2021-01-11 12:54:19 +01:00
1ffe5d79bd Make Infoscreens the correct height 2021-01-11 12:53:07 +01:00
8502f4e64f Merge branch 'wide_proc_comm' of cgzones/htop 2021-01-11 12:43:39 +01:00
a5db139a0a Linux: use correct column alignment for wide fields
This affects:
- PROC_COMM, PROC_EXE and CWD on Linux
- JAIL on FreeBSD and DragonFlyBSD
- ZONE on Solaris
2021-01-11 12:02:25 +01:00
8a67d7f086 Merge branch 'RichString_attrn' of cgzones/htop 2021-01-11 09:36:42 +01:00
0b89c66f58 Merge branch 'following_exit' of cgzones/htop 2021-01-11 09:36:25 +01:00
3bb731c645 RichString_setAttrn: refactor to take a length instead of a stop index
Fixes: #459
2021-01-10 16:51:25 +01:00
fbaa0cd146 Exit follow mode cleanly after followed process dies 2021-01-10 16:43:24 +01:00
a076488809 Solaris: make Process callbacks static
Fixes prototype of SolarisProcess_compareByKey since 90ea3ac3
2021-01-09 20:17:31 +01:00
6301d5c1da Convert unnecessary static variables
They are not used in any other function and are not used maybe
uninitialized.
2021-01-09 14:31:07 +01:00
4979245aa5 Update help and man page for improved -t / -s options 2021-01-08 21:34:30 +01:00
0155980fd6 Free memory on multiple filter command line arguments 2021-01-08 21:07:05 +01:00
2af90b711f Merge branch 'err_h' of cgzones/htop 2021-01-08 17:39:04 +01:00
d55f394541 Merge branch 'light_color' of cgzones/htop 2021-01-08 17:35:26 +01:00
c7d93a8f30 Merge branch 'ncurses_format' of cgzones/htop 2021-01-08 17:31:06 +01:00
2d2a2df6f2 Refactor crash handler message to avoid embedded directive
CRT.c:821:2: error: embedding a directive within macro arguments has undefined behavior [-Werror,-Wembedded-directive]
#ifdef HAVE_EXECINFO_H
 ^
CRT.c:823:2: error: embedding a directive within macro arguments has undefined behavior [-Werror,-Wembedded-directive]
#endif
 ^
CRT.c:858:2: error: embedding a directive within macro arguments has undefined behavior [-Werror,-Wembedded-directive]
#ifdef HTOP_DARWIN
 ^
CRT.c:862:2: error: embedding a directive within macro arguments has undefined behavior [-Werror,-Wembedded-directive]
#endif
 ^

CRT.c:864:2: error: embedding a directive within macro arguments has undefined behavior [-Werror,-Wembedded-directive]
#ifdef HTOP_DARWIN
 ^
CRT.c:868:2: error: embedding a directive within macro arguments has undefined behavior [-Werror,-Wembedded-directive]
#endif
 ^
2021-01-08 16:53:16 +01:00
de645ea16c ci: enable format attributes in ncurses headers
Avoid format string issues like bfcb8ca0 by helping compilers spot such
bogus usages.

Also use LTO and O3 in the full-featured gcc job, which might trigger
additional warnings on advanced inlining, like
3695cbd5d8 and
ad3acfc847
2021-01-08 14:05:56 +01:00
6ae56f2578 Revert color change on LightTerminal
Partially revert 4b14ab9789

ColorPair(Black,Black) is not actually black on black, but due to
adjustments in CRT_setColors() black on default-background-color.

Thanks to V for reporting.
2021-01-08 11:25:25 +01:00
V
bfcb8ca019 InfoScreen: fix uncontrolled format string
mvwprintw takes a format string as its fourth argument, and title is
user-controlled. This results in e.g. crashing when trying to trace a
process with a format specifier in its command line.
2021-01-08 11:06:38 +01:00
d800d7a3ce Drop usage of formatted error messages from <err.h>
They do not clean up the ncurses environment, leaving the terminal in a
broken state.

Also drop bare usage of exit(3).
2021-01-07 16:10:05 +01:00
27db9297b7 Show arrow indicating order of sorted process column 2021-01-07 14:46:44 +01:00
330d4fe22f Unify prototype of Vector_get
Vector_get() currently takes a `const Vector*` in debug mode and a
`Vector*` else.
2021-01-06 17:14:06 +01:00
8e10cde800 Hashtable: fail hard on too big size request 2021-01-06 16:59:28 +01:00
ca2c01bd16 Hashtable: widen size from int to size_t 2021-01-06 16:59:28 +01:00
7043a93eba Hashtable: hide implementation of Hashtable and HashtableItem 2021-01-06 16:59:28 +01:00
8fe04b7494 Hashtable: use more distinct typename for key type 2021-01-06 16:59:28 +01:00
43d5c61884 LibSensors: add support for Ryzen CPUs 2021-01-06 16:54:59 +01:00
e103ec0317 Declare for loop variables inside the loop 2021-01-06 16:43:18 +01:00
7ff654f2df Drop useless double parenthesis 2021-01-06 16:42:54 +01:00
7386c6fed0 Avoid function cast by refactoring callback prototype 2021-01-06 16:42:45 +01:00
ce9e7fd14f Panel_new: reorder arguments
Reorder owner and type so they match the order of Panel_init
2021-01-04 23:12:43 +01:00
badeaf9e82 IncSet: do not resize on our own and do not search on resize
The supervising ScreenManager will resize all Panels.
Also do not start the search on resize.
2021-01-04 23:12:43 +01:00
a3cced9fb6 Add option to hide the Function Bar
Support three settings:
  - Always show Function Bar
  - Always hide the Function Bar, except in Infoscreens (Env/Locks...)
    and when editing the search and filter mode
  - Hide the Function Bar on ESC until the next user input

Closes: #439
2021-01-04 23:12:43 +01:00
24c5ca9ddf Panel: rework hight logic
The hight of a Panel dpends on whether the Panel has a header or not.
Also the header migth not be set on Panel creation, like in the
MainPanel. This currently causes the cursor to get hidden behind the
FunctionBar on down-scrolling.
2021-01-04 23:12:43 +01:00
eb6f8d569d Action: drop resize callback
The supervising ScreenManager will resize all Panels
2021-01-04 23:12:43 +01:00
8c8149d146 XUtils: check for multiplication overflow in allocation size 2021-01-02 22:35:13 +01:00
a150a81669 Fix CPU percentage on M1 silicon Macs 2021-01-02 22:33:20 +01:00
90ea3ac3c9 Object: return int on comparison
Comparisons do, due to the new introduced shaceship-comparisons,
only return -1, 0, 1 or the result of strcmp().
2021-01-02 00:00:17 +01:00
293c16e22d Only initialize and gather delay accounting data if a related column is enabled
Avoid creating and communicating over a netlink socket by default, which
triggers cap_net_admin checks as root.
2021-01-01 21:34:22 +01:00
f6aa5d29bb Action: remove trivial wrapper function 2021-01-01 21:31:30 +01:00
2c06566405 LoadMeter: dynamically adjust color and total of bar
Change the color and total based on the actual 1min load value:

    < 1         : green and total of 1.0
    < cpu-count : yellow and total of cpu-count
    else        : red and total of 2*cpu-count

Closes: #32
2020-12-26 13:32:29 +01:00
d609c04fe4 CRT: add METER_VALUE_ERROR and adjust some METER_VALUE_WARN colors 2020-12-26 13:32:29 +01:00
ca9d7cd708 Also find libsensors.so.4 for Fedora and friends 2020-12-25 13:05:37 +01:00
debeac49cd Merge branch 'cpufreq' of hadfl/htop for Solaris / OmniOS support 2020-12-25 12:24:03 +01:00
a0b899f29d Note Shift-F3 use in man page 2020-12-25 11:53:02 +01:00
8b83a9f055 Enable going back to previous search matches (Shift-F3) 2020-12-25 11:53:02 +01:00
495f2292dc add support to display CPU frequencies on Solarish platforms 2020-12-25 09:26:50 +00:00
1cc3f8074f Merge branch 'user_wide' of cgzones/htop 2020-12-23 22:55:35 +01:00
aa08279964 Linux: accept clock CPU frequency
processor   : 0
cpu         : POWER8 (architected), altivec supported
clock       : 4024.000000MHz
revision    : 2.0 (pvr 004d 0200)

Closes: #424
2020-12-23 19:58:10 +01:00
5359eae28b Process: use correct column aligning on wide username
Closes: #421
2020-12-23 19:56:51 +01:00
f1463fdd64 Added keybind 'N' for sorting by PID 2020-12-23 18:30:26 +01:00
3edb6e1ea3 Position help labels one step to the right 2020-12-23 18:24:22 +01:00
71ddc6a6a1 Merge branch 'remove-n-keybind' of jakem72360/htop 2020-12-23 18:22:17 +01:00
b9336af76f fix argument type following prototype change in "Invert Process_compare resolution so that superclass matches run first" 2020-12-23 17:35:23 +01:00
f46ddd3230 Remove 'n' and 'N' search inc/dec keybinds 2020-12-24 03:24:15 +11:00
94d7f0b585 RichString: return number of written characters on write/append functions 2020-12-23 12:47:53 +01:00
86d2931255 Restore highlighted header of current sorted process column 2020-12-23 12:47:04 +01:00
0672be7db1 Update version number for git repo builds 2020-12-22 17:41:14 +11:00
58 changed files with 597 additions and 433 deletions

View File

@ -2,6 +2,11 @@ name: CI
on: [ push, pull_request ]
env:
# Enable format attributes in ncurses headers
# Enable fortified memory/string handling
CPPFLAGS: -DGCC_PRINTF -DGCC_SCANF -D_FORTIFY_SOURCE=2
jobs:
build-ubuntu-latest-minimal-gcc:
runs-on: ubuntu-latest
@ -47,6 +52,10 @@ jobs:
build-ubuntu-latest-full-featured-gcc:
runs-on: ubuntu-latest
# Enable LTO, might trigger additional warnings on advanced inlining
env:
CFLAGS: -O3 -g -flto
LDFLAGS: -O3 -g -flto
steps:
- uses: actions/checkout@v2
- name: Install Dependencies

View File

@ -104,7 +104,7 @@ static bool changePriority(MainPanel* panel, int delta) {
return anyTagged;
}
static void addUserToVector(hkey_t key, void* userCast, void* panelCast) {
static void addUserToVector(ht_key_t key, void* userCast, void* panelCast) {
const char* user = userCast;
Panel* panel = panelCast;
Panel_add(panel, (Object*) ListItem_new(user, key));
@ -162,9 +162,11 @@ Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey) {
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_UPDATE_PANELHDR | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction sortBy(State* st) {
// ----------------------------------------
static Htop_Reaction actionSetSortColumn(State* st) {
Htop_Reaction reaction = HTOP_OK;
Panel* sortPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem), FunctionBar_newEnterEsc("Sort ", "Cancel "));
Panel* sortPanel = Panel_new(0, 0, 0, 0, Class(ListItem), true, FunctionBar_newEnterEsc("Sort ", "Cancel "));
Panel_setHeader(sortPanel, "Sort by");
ProcessField* fields = st->settings->fields;
for (int i = 0; fields[i]; i++) {
@ -187,12 +189,8 @@ static Htop_Reaction sortBy(State* st) {
return reaction | HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}
// ----------------------------------------
static Htop_Reaction actionResize(State* st) {
clear();
Panel_resize(st->panel, COLS, LINES - (st->panel->y) - 1);
return HTOP_REDRAW_BAR;
static Htop_Reaction actionSortByPID(State* st) {
return Action_setSortKey(st->settings, PID);
}
static Htop_Reaction actionSortByMemory(State* st) {
@ -250,16 +248,6 @@ static Htop_Reaction actionIncSearch(State* st) {
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionIncNext(State* st) {
IncSet_next(((MainPanel*)st->panel)->inc, INC_SEARCH, st->panel, (IncMode_GetPanelValue) MainPanel_getValue);
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionIncPrev(State* st) {
IncSet_prev(((MainPanel*)st->panel)->inc, INC_SEARCH, st->panel, (IncMode_GetPanelValue) MainPanel_getValue);
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionHigherPriority(State* st) {
bool changed = changePriority((MainPanel*)st->panel, -1);
return changed ? HTOP_REFRESH : HTOP_OK;
@ -277,10 +265,6 @@ static Htop_Reaction actionInvertSortOrder(State* st) {
return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
}
static Htop_Reaction actionSetSortColumn(State* st) {
return sortBy(st);
}
static Htop_Reaction actionExpandOrCollapse(State* st) {
bool changed = expandCollapse(st->panel);
return changed ? HTOP_RECALCULATE : HTOP_OK;
@ -341,7 +325,7 @@ static Htop_Reaction actionKill(State* st) {
if (sgn) {
if (sgn->key != 0) {
Panel_setHeader(st->panel, "Sending...");
Panel_draw(st->panel, false, true, true);
Panel_draw(st->panel, false, true, true, State_hideFunctionBar(st));
refresh();
MainPanel_foreachProcess((MainPanel*)st->panel, Process_sendSignal, (Arg) { .i = sgn->key }, NULL);
napms(500);
@ -352,7 +336,7 @@ static Htop_Reaction actionKill(State* st) {
}
static Htop_Reaction actionFilterByUser(State* st) {
Panel* usersPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem), FunctionBar_newEnterEsc("Show ", "Cancel "));
Panel* usersPanel = Panel_new(0, 0, 0, 0, Class(ListItem), true, FunctionBar_newEnterEsc("Show ", "Cancel "));
Panel_setHeader(usersPanel, "Show processes of:");
UsersTable_foreach(st->ut, addUserToVector, usersPanel);
Vector_insertionSort(usersPanel->items);
@ -462,7 +446,7 @@ static const struct {
{ .key = " K: ", .info = "hide/show kernel threads" },
{ .key = " F: ", .info = "cursor follows process" },
{ .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 = " F6 > .: ", .info = "select sort column" },
{ .key = NULL, .info = NULL }
@ -563,24 +547,24 @@ static Htop_Reaction actionHelp(State* st) {
int item;
for (item = 0; helpLeft[item].key; item++) {
attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(line + item, 9, helpLeft[item].info);
mvaddstr(line + item, 10, helpLeft[item].info);
attrset(CRT_colors[HELP_BOLD]);
mvaddstr(line + item, 0, helpLeft[item].key);
mvaddstr(line + item, 1, helpLeft[item].key);
if (String_eq(helpLeft[item].key, " H: ")) {
attrset(CRT_colors[PROCESS_THREAD]);
mvaddstr(line + item, 32, "threads");
mvaddstr(line + item, 33, "threads");
} else if (String_eq(helpLeft[item].key, " K: ")) {
attrset(CRT_colors[PROCESS_THREAD]);
mvaddstr(line + item, 26, "threads");
mvaddstr(line + item, 27, "threads");
}
}
int leftHelpItems = item;
for (item = 0; helpRight[item].key; item++) {
attrset(CRT_colors[HELP_BOLD]);
mvaddstr(line + item, 40, helpRight[item].key);
mvaddstr(line + item, 41, helpRight[item].key);
attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(line + item, 49, helpRight[item].info);
mvaddstr(line + item, 50, helpRight[item].info);
}
line += MAXIMUM(leftHelpItems, item);
line++;
@ -655,7 +639,7 @@ void Action_setBindings(Htop_Action* keys) {
keys['I'] = actionInvertSortOrder;
keys['K'] = actionToggleKernelThreads;
keys['M'] = actionSortByMemory;
keys['N'] = actionIncPrev;
keys['N'] = actionSortByPID;
keys['P'] = actionSortByCPU;
keys['S'] = actionSetup;
keys['T'] = actionSortByTime;
@ -673,7 +657,6 @@ void Action_setBindings(Htop_Action* keys) {
keys['k'] = actionKill;
keys['l'] = actionLsof;
keys['m'] = actionToggleMergedCommand;
keys['n'] = actionIncNext;
keys['p'] = actionToggleProgramPath;
keys['q'] = actionQuit;
keys['s'] = actionStrace;
@ -693,5 +676,4 @@ void Action_setBindings(Htop_Action* keys) {
keys[KEY_F(10)] = actionQuit;
keys[KEY_F(18)] = actionExpandCollapseOrSortColumn;
keys[KEY_RECLICK] = actionExpandOrCollapse;
keys[KEY_RESIZE] = actionResize;
}

View File

@ -41,6 +41,10 @@ typedef struct State_ {
bool hideProcessSelection;
} State;
static inline bool State_hideFunctionBar(const State* st) {
return st->settings->hideFunctionBar == 2 || (st->settings->hideFunctionBar == 1 && st->hideProcessSelection);
}
typedef Htop_Reaction (*Htop_Action)(State* st);
Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess);

82
CRT.c
View File

@ -41,6 +41,9 @@ in the source distribution for its full text.
#define ColorPairGrayBlack ColorPair(Magenta,Magenta)
#define ColorIndexGrayBlack ColorIndex(Magenta,Magenta)
#define ColorPairWhiteDefault ColorPair(Red, Red)
#define ColorIndexWhiteDefault ColorIndex(Red, Red)
static const char* const CRT_treeStrAscii[LAST_TREE_STR] = {
[TREE_STR_VERT] = "|",
[TREE_STR_RTEE] = "`",
@ -48,6 +51,8 @@ static const char* const CRT_treeStrAscii[LAST_TREE_STR] = {
[TREE_STR_TEND] = ",",
[TREE_STR_OPEN] = "+",
[TREE_STR_SHUT] = "-",
[TREE_STR_ASC] = "+",
[TREE_STR_DESC] = "-",
};
#ifdef HAVE_LIBNCURSESW
@ -61,6 +66,8 @@ static const char* const CRT_treeStrUtf8[LAST_TREE_STR] = {
// WITH VERTICAL STROKE' (U+1FBAF, "\xf0\x9f\xae\xaf") when
// Unicode 13 is common
[TREE_STR_SHUT] = "\xe2\x94\x80", // ─
[TREE_STR_ASC] = "\xe2\x96\xb3", // △
[TREE_STR_DESC] = "\xe2\x96\xbd", // ▽
};
bool CRT_utf8 = false;
@ -114,6 +121,7 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[METER_VALUE_IOWRITE] = ColorPair(Blue, Black),
[METER_VALUE_NOTICE] = A_BOLD | ColorPair(White, Black),
[METER_VALUE_OK] = ColorPair(Green, Black),
[METER_VALUE_WARN] = A_BOLD | ColorPair(Yellow, Black),
[LED_COLOR] = ColorPair(Green, Black),
[TASKS_RUNNING] = A_BOLD | ColorPair(Green, Black),
[PROCESS] = A_NORMAL,
@ -198,6 +206,7 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[METER_VALUE_IOWRITE] = A_NORMAL,
[METER_VALUE_NOTICE] = A_BOLD,
[METER_VALUE_OK] = A_NORMAL,
[METER_VALUE_WARN] = A_BOLD,
[LED_COLOR] = A_NORMAL,
[TASKS_RUNNING] = A_BOLD,
[PROCESS] = A_NORMAL,
@ -282,6 +291,7 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[METER_VALUE_IOWRITE] = ColorPair(Yellow, White),
[METER_VALUE_NOTICE] = A_BOLD | ColorPair(Yellow, White),
[METER_VALUE_OK] = ColorPair(Green, White),
[METER_VALUE_WARN] = A_BOLD | ColorPair(Yellow, White),
[LED_COLOR] = ColorPair(Green, White),
[TASKS_RUNNING] = ColorPair(Green, White),
[PROCESS] = ColorPair(Black, White),
@ -344,10 +354,10 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[ZRAM] = ColorPair(Yellow, White)
},
[COLORSCHEME_LIGHTTERMINAL] = {
[RESET_COLOR] = ColorPair(Blue, Black),
[DEFAULT_COLOR] = ColorPair(Blue, Black),
[RESET_COLOR] = ColorPair(Black, Black),
[DEFAULT_COLOR] = ColorPair(Black, Black),
[FUNCTION_BAR] = ColorPair(Black, Cyan),
[FUNCTION_KEY] = ColorPair(Blue, Black),
[FUNCTION_KEY] = ColorPair(Black, Black),
[PANEL_HEADER_FOCUS] = ColorPair(Black, Green),
[PANEL_HEADER_UNFOCUS] = ColorPair(Black, Green),
[PANEL_SELECTION_FOCUS] = ColorPair(Black, Cyan),
@ -360,17 +370,18 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[BATTERY] = ColorPair(Yellow, Black),
[LARGE_NUMBER] = ColorPair(Red, Black),
[METER_TEXT] = ColorPair(Blue, Black),
[METER_VALUE] = ColorPair(Blue, Black),
[METER_VALUE] = ColorPair(Black, Black),
[METER_VALUE_ERROR] = A_BOLD | ColorPair(Red, Black),
[METER_VALUE_IOREAD] = ColorPair(Green, Black),
[METER_VALUE_IOWRITE] = ColorPair(Yellow, Black),
[METER_VALUE_NOTICE] = A_BOLD | ColorPair(Yellow, Black),
[METER_VALUE_NOTICE] = A_BOLD | ColorPairWhiteDefault,
[METER_VALUE_OK] = ColorPair(Green, Black),
[METER_VALUE_WARN] = A_BOLD | ColorPair(Yellow, Black),
[LED_COLOR] = ColorPair(Green, Black),
[TASKS_RUNNING] = ColorPair(Green, Black),
[PROCESS] = ColorPair(Blue, Black),
[PROCESS] = ColorPair(Black, Black),
[PROCESS_SHADOW] = A_BOLD | ColorPairGrayBlack,
[PROCESS_TAG] = ColorPair(Yellow, Blue),
[PROCESS_TAG] = ColorPair(White, Blue),
[PROCESS_MEGABYTES] = ColorPair(Blue, Black),
[PROCESS_GIGABYTES] = ColorPair(Green, Black),
[PROCESS_BASENAME] = ColorPair(Green, Black),
@ -394,34 +405,34 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[MEMORY_BUFFERS] = ColorPair(Cyan, Black),
[MEMORY_BUFFERS_TEXT] = ColorPair(Cyan, Black),
[MEMORY_CACHE] = ColorPair(Yellow, Black),
[LOAD_AVERAGE_FIFTEEN] = ColorPair(Blue, Black),
[LOAD_AVERAGE_FIVE] = ColorPair(Blue, Black),
[LOAD_AVERAGE_ONE] = ColorPair(Yellow, Black),
[LOAD] = ColorPair(Yellow, Black),
[LOAD_AVERAGE_FIFTEEN] = ColorPair(Black, Black),
[LOAD_AVERAGE_FIVE] = ColorPair(Black, Black),
[LOAD_AVERAGE_ONE] = ColorPair(Black, Black),
[LOAD] = ColorPairWhiteDefault,
[HELP_BOLD] = ColorPair(Blue, Black),
[CLOCK] = ColorPair(Yellow, Black),
[DATE] = ColorPair(White, Black),
[DATETIME] = ColorPair(White, Black),
[CLOCK] = ColorPairWhiteDefault,
[DATE] = ColorPairWhiteDefault,
[DATETIME] = ColorPairWhiteDefault,
[CHECK_BOX] = ColorPair(Blue, Black),
[CHECK_MARK] = ColorPair(Blue, Black),
[CHECK_TEXT] = ColorPair(Blue, Black),
[HOSTNAME] = ColorPair(Yellow, Black),
[CHECK_MARK] = ColorPair(Black, Black),
[CHECK_TEXT] = ColorPair(Black, Black),
[HOSTNAME] = ColorPairWhiteDefault,
[CPU_NICE] = ColorPair(Cyan, Black),
[CPU_NICE_TEXT] = ColorPair(Cyan, Black),
[CPU_NORMAL] = ColorPair(Green, Black),
[CPU_SYSTEM] = ColorPair(Red, Black),
[CPU_IOWAIT] = A_BOLD | ColorPair(Blue, Black),
[CPU_IOWAIT] = A_BOLD | ColorPair(Black, Black),
[CPU_IRQ] = A_BOLD | ColorPair(Blue, Black),
[CPU_SOFTIRQ] = ColorPair(Blue, Black),
[CPU_STEAL] = ColorPair(Blue, Black),
[CPU_GUEST] = ColorPair(Blue, Black),
[PRESSURE_STALL_THREEHUNDRED] = ColorPair(Blue, Black),
[PRESSURE_STALL_SIXTY] = ColorPair(Blue, Black),
[PRESSURE_STALL_TEN] = ColorPair(Blue, Black),
[CPU_STEAL] = ColorPair(Black, Black),
[CPU_GUEST] = ColorPair(Black, Black),
[PRESSURE_STALL_THREEHUNDRED] = ColorPair(Black, Black),
[PRESSURE_STALL_SIXTY] = ColorPair(Black, Black),
[PRESSURE_STALL_TEN] = ColorPair(Black, Black),
[ZFS_MFU] = ColorPair(Cyan, Black),
[ZFS_MRU] = ColorPair(Yellow, Black),
[ZFS_ANON] = A_BOLD | ColorPair(Magenta, Black),
[ZFS_HEADER] = ColorPair(Blue, Black),
[ZFS_HEADER] = ColorPair(Black, Black),
[ZFS_OTHER] = A_BOLD | ColorPair(Magenta, Black),
[ZFS_COMPRESSED] = ColorPair(Cyan, Black),
[ZFS_RATIO] = A_BOLD | ColorPair(Magenta, Black),
@ -450,6 +461,7 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[METER_VALUE_IOWRITE] = ColorPair(Black, Blue),
[METER_VALUE_NOTICE] = A_BOLD | ColorPair(White, Blue),
[METER_VALUE_OK] = ColorPair(Green, Blue),
[METER_VALUE_WARN] = A_BOLD | ColorPair(Yellow, Black),
[LED_COLOR] = ColorPair(Green, Blue),
[TASKS_RUNNING] = A_BOLD | ColorPair(Green, Blue),
[PROCESS] = ColorPair(White, Blue),
@ -532,8 +544,9 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[METER_VALUE_ERROR] = A_BOLD | ColorPair(Red, Black),
[METER_VALUE_IOREAD] = ColorPair(Green, Black),
[METER_VALUE_IOWRITE] = ColorPair(Blue, Black),
[METER_VALUE_NOTICE] = A_BOLD | ColorPair(Yellow, Black),
[METER_VALUE_NOTICE] = A_BOLD | ColorPair(White, Black),
[METER_VALUE_OK] = ColorPair(Green, Black),
[METER_VALUE_WARN] = A_BOLD | ColorPair(Yellow, Black),
[LED_COLOR] = ColorPair(Green, Black),
[TASKS_RUNNING] = A_BOLD | ColorPair(Green, Black),
[PROCESS] = ColorPair(Cyan, Black),
@ -689,6 +702,7 @@ void CRT_init(const int* delay, int colorScheme, bool allowUnicode) {
define_key("\033[12~", KEY_F(2));
define_key("\033[13~", KEY_F(3));
define_key("\033[14~", KEY_F(4));
define_key("\033[14;2~", KEY_F(15));
define_key("\033[17;2~", KEY_F(18));
char sequence[3] = "\033a";
for (char c = 'a'; c <= 'z'; c++) {
@ -778,7 +792,7 @@ void CRT_setColors(int colorScheme) {
for (short int i = 0; i < 8; i++) {
for (short int j = 0; j < 8; j++) {
if (ColorIndex(i, j) != ColorIndexGrayBlack) {
if (ColorIndex(i, j) != ColorIndexGrayBlack && ColorIndex(i, j) != ColorIndexWhiteDefault) {
short int bg = (colorScheme != COLORSCHEME_BLACKNIGHT)
? (j == 0 ? -1 : j)
: j;
@ -791,6 +805,8 @@ void CRT_setColors(int colorScheme) {
short int grayBlackBg = (colorScheme != COLORSCHEME_BLACKNIGHT) ? -1 : 0;
init_pair(ColorIndexGrayBlack, grayBlackFg, grayBlackBg);
init_pair(ColorIndexWhiteDefault, White, -1);
CRT_colors = CRT_colorSchemes[colorScheme];
}
@ -807,9 +823,13 @@ void CRT_handleSIGSEGV(int signal) {
"- Your OS and kernel version (uname -a)\n"
"- Your distribution and release (lsb_release -a)\n"
"- Likely steps to reproduce (How did it happened?)\n"
);
#ifdef HAVE_EXECINFO_H
"- Backtrace of the issue (see below)\n"
fprintf(stderr, "- Backtrace of the issue (see below)\n");
#endif
fprintf(stderr,
"\n"
);
@ -844,11 +864,15 @@ void CRT_handleSIGSEGV(int signal) {
"you should provide a disassembly of your binary.\n"
"This can usually be done by running the following command:\n"
"\n"
);
#ifdef HTOP_DARWIN
" otool -tvV `which htop` > ~/htop.otool\n"
fprintf(stderr, " otool -tvV `which htop` > ~/htop.otool\n");
#else
" objdump -d -S -w `which htop` > ~/htop.objdump\n"
fprintf(stderr, " objdump -d -S -w `which htop` > ~/htop.objdump\n");
#endif
fprintf(stderr,
"\n"
"Please include the generated file in your report.\n"
"\n"

3
CRT.h
View File

@ -22,6 +22,8 @@ typedef enum TreeStr_ {
TREE_STR_TEND,
TREE_STR_OPEN,
TREE_STR_SHUT,
TREE_STR_ASC,
TREE_STR_DESC,
LAST_TREE_STR
} TreeStr;
@ -57,6 +59,7 @@ typedef enum ColorElements_ {
METER_VALUE_IOWRITE,
METER_VALUE_NOTICE,
METER_VALUE_OK,
METER_VALUE_WARN,
LED_COLOR,
UPTIME,
BATTERY,

View File

@ -1,15 +1,40 @@
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)
(thanks to Hisham Muhammad)
* Unhardcode Mac OS tick-to-milliseconds conversion
(thanks to Alexander Momchilov)
(thanks to Alexander Momchilov)
* Check if clock_gettime needs linking of librt
* Define O_PATH if not already defined
(thanks to Chris Burr)
(thanks to Chris Burr)
* Add column on Mac for processes running under translation
(thanks to Dániel Bakai)
(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

View File

@ -60,7 +60,7 @@ const InfoScreenClass CommandScreen_class = {
CommandScreen* CommandScreen_new(Process* process) {
CommandScreen* this = AllocThis(CommandScreen);
return (CommandScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 3, " ");
return (CommandScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " ");
}
void CommandScreen_delete(Object* this) {

View File

@ -124,6 +124,7 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
Panel_add(super, (Object*) NumberItem_newByRef("Update interval (in seconds)", &(settings->delay), -1, 1, 255));
Panel_add(super, (Object*) CheckItem_newByRef("Highlight new and old processes", &(settings->highlightChanges)));
Panel_add(super, (Object*) NumberItem_newByRef("- Highlight time (in seconds)", &(settings->highlightDelaySecs), 0, 1, 24*60*60));
Panel_add(super, (Object*) NumberItem_newByRef("Hide main function bar (0 - off, 1 - on ESC until next input, 2 - permanently)", &(settings->hideFunctionBar), 0, 0, 2));
#ifdef HAVE_LIBHWLOC
Panel_add(super, (Object*) CheckItem_newByRef("Show topology when selecting affinity by default", &(settings->topologyAffinity)));
#endif

View File

@ -17,7 +17,7 @@
EnvScreen* EnvScreen_new(Process* process) {
EnvScreen* this = xMalloc(sizeof(EnvScreen));
Object_setClass(this, Class(EnvScreen));
return (EnvScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 3, " ");
return (EnvScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " ");
}
void EnvScreen_delete(Object* this) {

View File

@ -15,22 +15,37 @@ in the source distribution for its full text.
#include <stdlib.h>
#include <string.h>
#include "CRT.h"
#include "Macros.h"
#include "XUtils.h"
typedef struct HashtableItem_ {
ht_key_t key;
size_t probe;
void* value;
} HashtableItem;
struct Hashtable_ {
size_t size;
HashtableItem* buckets;
size_t items;
bool owner;
};
#ifndef NDEBUG
static void Hashtable_dump(const Hashtable* this) {
fprintf(stderr, "Hashtable %p: size=%u items=%u owner=%s\n",
fprintf(stderr, "Hashtable %p: size=%zu items=%zu owner=%s\n",
(const void*)this,
this->size,
this->items,
this->owner ? "yes" : "no");
unsigned int items = 0;
for (unsigned int i = 0; i < this->size; i++) {
fprintf(stderr, " item %5u: key = %5u probe = %2u value = %p\n",
size_t items = 0;
for (size_t i = 0; i < this->size; i++) {
fprintf(stderr, " item %5zu: key = %5u probe = %2zu value = %p\n",
i,
this->buckets[i].key,
this->buckets[i].probe,
@ -40,15 +55,15 @@ static void Hashtable_dump(const Hashtable* this) {
items++;
}
fprintf(stderr, "Hashtable %p: items=%u counted=%u\n",
fprintf(stderr, "Hashtable %p: items=%zu counted=%zu\n",
(const void*)this,
this->items,
items);
}
static bool Hashtable_isConsistent(const Hashtable* this) {
unsigned int items = 0;
for (unsigned int i = 0; i < this->size; i++) {
size_t items = 0;
for (size_t i = 0; i < this->size; i++) {
if (this->buckets[i].value)
items++;
}
@ -58,9 +73,9 @@ static bool Hashtable_isConsistent(const Hashtable* this) {
return res;
}
unsigned int Hashtable_count(const Hashtable* this) {
unsigned int items = 0;
for (unsigned int i = 0; i < this->size; i++) {
size_t Hashtable_count(const Hashtable* this) {
size_t items = 0;
for (size_t i = 0; i < this->size; i++) {
if (this->buckets[i].value)
items++;
}
@ -80,18 +95,17 @@ static const uint64_t OEISprimes[] = {
34359738337, 68719476731, 137438953447
};
static uint64_t nextPrime(unsigned int n) {
assert(n <= OEISprimes[ARRAYSIZE(OEISprimes) - 1]);
for (unsigned int i = 0; i < ARRAYSIZE(OEISprimes); i++) {
static uint64_t nextPrime(size_t n) {
/* on 32-bit make sure we do not return primes not fitting in size_t */
for (size_t i = 0; i < ARRAYSIZE(OEISprimes) && OEISprimes[i] < SIZE_MAX; i++) {
if (n <= OEISprimes[i])
return OEISprimes[i];
}
return OEISprimes[ARRAYSIZE(OEISprimes) - 1];
CRT_fatalError("Hashtable: no prime found");
}
Hashtable* Hashtable_new(unsigned int size, bool owner) {
Hashtable* Hashtable_new(size_t size, bool owner) {
Hashtable* this;
this = xMalloc(sizeof(Hashtable));
@ -115,7 +129,7 @@ void Hashtable_clear(Hashtable* this) {
assert(Hashtable_isConsistent(this));
if (this->owner)
for (unsigned int i = 0; i < this->size; i++)
for (size_t i = 0; i < this->size; i++)
free(this->buckets[i].value);
memset(this->buckets, 0, this->size * sizeof(HashtableItem));
@ -124,11 +138,11 @@ void Hashtable_clear(Hashtable* this) {
assert(Hashtable_isConsistent(this));
}
static void insert(Hashtable* this, hkey_t key, void* value) {
unsigned int index = key % this->size;
unsigned int probe = 0;
static void insert(Hashtable* this, ht_key_t key, void* value) {
size_t index = key % this->size;
size_t probe = 0;
#ifndef NDEBUG
unsigned int origIndex = index;
size_t origIndex = index;
#endif
for (;;) {
@ -167,7 +181,7 @@ static void insert(Hashtable* this, hkey_t key, void* value) {
}
}
void Hashtable_setSize(Hashtable* this, unsigned int size) {
void Hashtable_setSize(Hashtable* this, size_t size) {
assert(Hashtable_isConsistent(this));
@ -175,14 +189,14 @@ void Hashtable_setSize(Hashtable* this, unsigned int size) {
return;
HashtableItem* oldBuckets = this->buckets;
unsigned int oldSize = this->size;
size_t oldSize = this->size;
this->size = nextPrime(size);
this->buckets = (HashtableItem*) xCalloc(this->size, sizeof(HashtableItem));
this->items = 0;
/* rehash */
for (unsigned int i = 0; i < oldSize; i++) {
for (size_t i = 0; i < oldSize; i++) {
if (!oldBuckets[i].value)
continue;
@ -194,15 +208,19 @@ void Hashtable_setSize(Hashtable* this, unsigned int size) {
assert(Hashtable_isConsistent(this));
}
void Hashtable_put(Hashtable* this, hkey_t key, void* value) {
void Hashtable_put(Hashtable* this, ht_key_t key, void* value) {
assert(Hashtable_isConsistent(this));
assert(this->size > 0);
assert(value);
/* grow on load-factor > 0.7 */
if (10 * this->items > 7 * this->size)
if (10 * this->items > 7 * this->size) {
if (SIZE_MAX / 2 < this->size)
CRT_fatalError("Hashtable: size overflow");
Hashtable_setSize(this, 2 * this->size);
}
insert(this, key, value);
@ -211,11 +229,11 @@ void Hashtable_put(Hashtable* this, hkey_t key, void* value) {
assert(this->size > this->items);
}
void* Hashtable_remove(Hashtable* this, hkey_t key) {
unsigned int index = key % this->size;
unsigned int probe = 0;
void* Hashtable_remove(Hashtable* this, ht_key_t key) {
size_t index = key % this->size;
size_t probe = 0;
#ifndef NDEBUG
unsigned int origIndex = index;
size_t origIndex = index;
#endif
assert(Hashtable_isConsistent(this));
@ -230,7 +248,7 @@ void* Hashtable_remove(Hashtable* this, hkey_t key) {
res = this->buckets[index].value;
}
unsigned int next = (index + 1) % this->size;
size_t next = (index + 1) % this->size;
while (this->buckets[next].value && this->buckets[next].probe > 0) {
this->buckets[index] = this->buckets[next];
@ -266,12 +284,12 @@ void* Hashtable_remove(Hashtable* this, hkey_t key) {
return res;
}
void* Hashtable_get(Hashtable* this, hkey_t key) {
unsigned int index = key % this->size;
unsigned int probe = 0;
void* Hashtable_get(Hashtable* this, ht_key_t key) {
size_t index = key % this->size;
size_t probe = 0;
void* res = NULL;
#ifndef NDEBUG
unsigned int origIndex = index;
size_t origIndex = index;
#endif
assert(Hashtable_isConsistent(this));
@ -296,7 +314,7 @@ void* Hashtable_get(Hashtable* this, hkey_t key) {
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData) {
assert(Hashtable_isConsistent(this));
for (unsigned int i = 0; i < this->size; i++) {
for (size_t i = 0; i < this->size; i++) {
HashtableItem* walk = &this->buckets[i];
if (walk->value)
f(walk->key, walk->value, userData);

View File

@ -8,44 +8,34 @@ in the source distribution for its full text.
*/
#include <stdbool.h>
#include <stddef.h>
typedef unsigned int hkey_t;
typedef unsigned int ht_key_t;
typedef void(*Hashtable_PairFunction)(hkey_t key, void* value, void* userdata);
typedef void(*Hashtable_PairFunction)(ht_key_t key, void* value, void* userdata);
typedef struct HashtableItem_ {
hkey_t key;
unsigned int probe;
void* value;
} HashtableItem;
typedef struct Hashtable_ {
unsigned int size;
HashtableItem* buckets;
unsigned int items;
bool owner;
} Hashtable;
typedef struct Hashtable_ Hashtable;
#ifndef NDEBUG
unsigned int Hashtable_count(const Hashtable* this);
size_t Hashtable_count(const Hashtable* this);
#endif /* NDEBUG */
Hashtable* Hashtable_new(unsigned int size, bool owner);
Hashtable* Hashtable_new(size_t size, bool owner);
void Hashtable_delete(Hashtable* this);
void Hashtable_clear(Hashtable* this);
void Hashtable_setSize(Hashtable* this, unsigned int size);
void Hashtable_setSize(Hashtable* this, size_t size);
void Hashtable_put(Hashtable* this, hkey_t key, void* value);
void Hashtable_put(Hashtable* this, ht_key_t key, void* value);
void* Hashtable_remove(Hashtable* this, hkey_t key);
void* Hashtable_remove(Hashtable* this, ht_key_t key);
void* Hashtable_get(Hashtable* this, hkey_t key);
void* Hashtable_get(Hashtable* this, ht_key_t key);
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData);

View File

@ -29,9 +29,9 @@ void IncSet_reset(IncSet* this, IncType type) {
IncMode_reset(&this->modes[type]);
}
static const char* const searchFunctions[] = {"Next ", "Cancel ", " Search: ", NULL};
static const char* const searchKeys[] = {"F3", "Esc", " "};
static const int searchEvents[] = {KEY_F(3), 27, ERR};
static const char* const searchFunctions[] = {"Next ", "Prev ", "Cancel ", " Search: ", NULL};
static const char* const searchKeys[] = {"F3", "S-F3", "Esc", " "};
static const int searchEvents[] = {KEY_F(3), KEY_F(15), 27, ERR};
static inline void IncMode_initSearch(IncMode* search) {
memset(search, 0, sizeof(IncMode));
@ -133,14 +133,6 @@ static bool IncMode_find(IncMode* mode, Panel* panel, IncMode_GetPanelValue getP
}
}
bool IncSet_next(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue) {
return IncMode_find(&this->modes[type], panel, getPanelValue, 1);
}
bool IncSet_prev(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue) {
return IncMode_find(&this->modes[type], panel, getPanelValue, -1);
}
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines) {
if (ch == ERR)
return true;
@ -149,11 +141,11 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
int size = Panel_size(panel);
bool filterChanged = false;
bool doSearch = true;
if (ch == KEY_F(3)) {
if (ch == KEY_F(3) || ch == KEY_F(15)) {
if (size == 0)
return true;
IncMode_find(mode, panel, getPanelValue, 1);
IncMode_find(mode, panel, getPanelValue, ch == KEY_F(3) ? 1 : -1);
doSearch = false;
} else if (0 < ch && ch < 255 && isprint((unsigned char)ch)) {
if (mode->index < INCMODE_MAX) {
@ -167,7 +159,7 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
}
}
}
} else if ((ch == KEY_BACKSPACE || ch == 127)) {
} else if (ch == KEY_BACKSPACE || ch == 127) {
if (mode->index > 0) {
mode->index--;
mode->buffer[mode->index] = 0;
@ -182,7 +174,7 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
doSearch = false;
}
} else if (ch == KEY_RESIZE) {
Panel_resize(panel, COLS, LINES - panel->y - 1);
doSearch = (mode->index > 0);
} else {
if (mode->isFilter) {
filterChanged = true;

View File

@ -48,10 +48,6 @@ IncSet* IncSet_new(FunctionBar* bar);
void IncSet_delete(IncSet* this);
bool IncSet_next(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue);
bool IncSet_prev(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue);
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines);
const char* IncSet_getListItemValue(Panel* panel, int i);

View File

@ -26,7 +26,7 @@ InfoScreen* InfoScreen_init(InfoScreen* this, const Process* process, FunctionBa
if (!bar) {
bar = FunctionBar_new(InfoScreenFunctions, InfoScreenKeys, InfoScreenEvents);
}
this->display = Panel_new(0, 1, COLS, height, false, Class(ListItem), bar);
this->display = Panel_new(0, 1, COLS, height, Class(ListItem), false, bar);
this->inc = IncSet_new(bar);
this->lines = Vector_new(this->display->items->type, true, DEFAULT_SIZE);
Panel_setHeader(this->display, panelHeader);
@ -54,9 +54,9 @@ void InfoScreen_drawTitled(InfoScreen* this, const char* fmt, ...) {
attrset(CRT_colors[METER_TEXT]);
mvhline(0, 0, ' ', COLS);
mvwprintw(stdscr, 0, 0, title);
mvaddstr(0, 0, title);
attrset(CRT_colors[DEFAULT_COLOR]);
Panel_draw(this->display, true, true, true);
Panel_draw(this->display, true, true, true, false);
IncSet_drawBar(this->inc);
}
@ -89,7 +89,7 @@ void InfoScreen_run(InfoScreen* this) {
bool looping = true;
while (looping) {
Panel_draw(panel, false, true, true);
Panel_draw(panel, false, true, true, false);
IncSet_drawBar(this->inc);
if (this->inc->active) {

View File

@ -57,7 +57,7 @@ void ListItem_append(ListItem* this, const char* text) {
this->value[newLen] = '\0';
}
static long ListItem_compare(const void* cast1, const void* cast2) {
static int ListItem_compare(const void* cast1, const void* cast2) {
const ListItem* obj1 = (const ListItem*) cast1;
const ListItem* obj2 = (const ListItem*) cast2;
return strcmp(obj1->value, obj2->value);

View File

@ -24,8 +24,36 @@ static const int LoadMeter_attributes[] = {
LOAD
};
static const int OK_attributes[] = {
METER_VALUE_OK
};
static const int Medium_attributes[] = {
METER_VALUE_WARN
};
static const int High_attributes[] = {
METER_VALUE_ERROR
};
static void LoadAverageMeter_updateValues(Meter* this, char* buffer, size_t size) {
Platform_getLoadAverage(&this->values[0], &this->values[1], &this->values[2]);
// only show bar for 1min value
this->curItems = 1;
// change bar color and total based on value
if (this->values[0] < 1.0) {
this->curAttributes = OK_attributes;
this->total = 1.0;
} else if (this->values[0] < this->pl->cpuCount) {
this->curAttributes = Medium_attributes;
this->total = this->pl->cpuCount;
} else {
this->curAttributes = High_attributes;
this->total = 2 * this->pl->cpuCount;
}
xSnprintf(buffer, size, "%.2f/%.2f/%.2f", this->values[0], this->values[1], this->values[2]);
}
@ -43,9 +71,19 @@ static void LoadAverageMeter_display(const Object* cast, RichString* out) {
static void LoadMeter_updateValues(Meter* this, char* buffer, size_t size) {
double five, fifteen;
Platform_getLoadAverage(&this->values[0], &five, &fifteen);
if (this->values[0] > this->total) {
this->total = this->values[0];
// change bar color and total based on value
if (this->values[0] < 1.0) {
this->curAttributes = OK_attributes;
this->total = 1.0;
} else if (this->values[0] < this->pl->cpuCount) {
this->curAttributes = Medium_attributes;
this->total = this->pl->cpuCount;
} else {
this->curAttributes = High_attributes;
this->total = 2 * this->pl->cpuCount;
}
xSnprintf(buffer, size, "%.2f", this->values[0]);
}

View File

@ -44,6 +44,11 @@ void MainPanel_pidSearch(MainPanel* this, int ch) {
}
}
static const char* MainPanel_getValue(Panel* this, int i) {
const Process* p = (const Process*) Panel_get(this, i);
return Process_getCommand(p);
}
static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
MainPanel* this = (MainPanel*) super;
@ -51,7 +56,12 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
Htop_Reaction reaction = HTOP_OK;
if (ch != ERR && ch != KEY_RESIZE)
/* Let supervising ScreenManager handle resize */
if (ch == KEY_RESIZE)
return IGNORED;
/* reset on every normal key */
if (ch != ERR)
this->state->hideProcessSelection = false;
if (EVENT_IS_HEADER_CLICK(ch)) {
@ -72,7 +82,7 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
reaction |= HTOP_RECALCULATE | HTOP_REDRAW_BAR | HTOP_SAVE_SETTINGS;
result = HANDLED;
} else if (ch != ERR && this->inc->active) {
bool filterChanged = IncSet_handleKey(this->inc, ch, super, (IncMode_GetPanelValue) MainPanel_getValue, NULL);
bool filterChanged = IncSet_handleKey(this->inc, ch, super, MainPanel_getValue, NULL);
if (filterChanged) {
this->state->pl->incFilter = IncSet_filter(this->inc);
reaction = HTOP_REFRESH | HTOP_REDRAW_BAR;
@ -102,7 +112,7 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
MainPanel_updateTreeFunctions(this, this->state->settings->treeView);
}
if (reaction & HTOP_UPDATE_PANELHDR) {
ProcessList_printHeader(this->state->pl, Panel_getHeader(super));
result |= REDRAW;
}
if (reaction & HTOP_REFRESH) {
result |= REFRESH;
@ -131,11 +141,6 @@ int MainPanel_selectedPid(MainPanel* this) {
return -1;
}
const char* MainPanel_getValue(MainPanel* this, int i) {
Process* p = (Process*) Panel_get((Panel*)this, i);
return Process_getCommand(p);
}
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged) {
Panel* super = (Panel*) this;
bool ok = true;
@ -160,21 +165,32 @@ bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Ar
return ok;
}
static void MainPanel_drawFunctionBar(Panel* super) {
static void MainPanel_drawFunctionBar(Panel* super, bool hideFunctionBar) {
MainPanel* this = (MainPanel*) super;
// Do not hide active search and filter bar.
if (hideFunctionBar && !this->inc->active)
return;
IncSet_drawBar(this->inc);
if (this->state->pauseProcessUpdate) {
FunctionBar_append("PAUSED", CRT_colors[PAUSED]);
}
}
static void MainPanel_printHeader(Panel* super) {
MainPanel* this = (MainPanel*) super;
ProcessList_printHeader(this->state->pl, &super->header);
}
const PanelClass MainPanel_class = {
.super = {
.extends = Class(Panel),
.delete = MainPanel_delete
},
.eventHandler = MainPanel_eventHandler,
.drawFunctionBar = MainPanel_drawFunctionBar
.drawFunctionBar = MainPanel_drawFunctionBar,
.printHeader = MainPanel_printHeader
};
MainPanel* MainPanel_new() {

View File

@ -38,8 +38,6 @@ void MainPanel_pidSearch(MainPanel* this, int ch);
int MainPanel_selectedPid(MainPanel* this);
const char* MainPanel_getValue(MainPanel* this, int i);
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged);
extern const PanelClass MainPanel_class;

11
Meter.c
View File

@ -39,6 +39,7 @@ Meter* Meter_new(const struct ProcessList_* pl, int param, const MeterClass* typ
this->param = param;
this->pl = pl;
this->curItems = type->maxItems;
this->curAttributes = NULL;
this->values = type->maxItems ? xCalloc(type->maxItems, sizeof(double)) : NULL;
this->total = type->total;
this->caption = xStrdup(type->caption);
@ -252,13 +253,14 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
// ...then print the buffer.
offset = 0;
for (uint8_t i = 0; i < this->curItems; i++) {
RichString_setAttrn(&bar, CRT_colors[Meter_attributes(this)[i]], startPos + offset, startPos + offset + blockSizes[i] - 1);
int attr = this->curAttributes ? this->curAttributes[i] : Meter_attributes(this)[i];
RichString_setAttrn(&bar, CRT_colors[attr], startPos + offset, blockSizes[i]);
RichString_printoffnVal(bar, y, x + offset, startPos + offset, MINIMUM(blockSizes[i], w - offset));
offset += blockSizes[i];
offset = CLAMP(offset, 0, w);
}
if (offset < w) {
RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], startPos + offset, startPos + w - 1);
RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], startPos + offset, w - offset);
RichString_printoffnVal(bar, y, x + offset, startPos + offset, w - offset);
}
@ -290,9 +292,6 @@ static const char* const GraphMeterMode_dotsAscii[] = {
/*20*/":", /*21*/":", /*22*/":"
};
static const char* const* GraphMeterMode_dots;
static int GraphMeterMode_pixPerRow;
static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
if (!this->drawData) {
@ -301,6 +300,8 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
GraphData* data = this->drawData;
const int nValues = METER_BUFFER_LEN;
const char* const* GraphMeterMode_dots;
int GraphMeterMode_pixPerRow;
#ifdef HAVE_LIBNCURSESW
if (CRT_utf8) {
GraphMeterMode_dots = GraphMeterMode_dotsUtf8;

View File

@ -100,6 +100,7 @@ struct Meter_ {
int h;
const ProcessList* pl;
uint8_t curItems;
const int* curAttributes;
double* values;
double total;
void* meterData;

View File

@ -24,7 +24,7 @@ struct Object_;
typedef struct Object_ Object;
typedef void(*Object_Display)(const Object*, RichString*);
typedef long(*Object_Compare)(const void*, const void*);
typedef int(*Object_Compare)(const void*, const void*);
typedef void(*Object_Delete)(Object*);
#define Object_getClass(obj_) ((const Object*)(obj_))->klass

View File

@ -74,7 +74,7 @@ OpenFilesScreen* OpenFilesScreen_new(const Process* process) {
} else {
this->pid = process->pid;
}
return (OpenFilesScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 3, " FD TYPE MODE DEVICE SIZE NODE NAME");
return (OpenFilesScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " FD TYPE MODE DEVICE SIZE NODE NAME");
}
void OpenFilesScreen_delete(Object* this) {

70
Panel.c
View File

@ -30,7 +30,7 @@ const PanelClass Panel_class = {
.eventHandler = Panel_selectByTyping,
};
Panel* Panel_new(int x, int y, int w, int h, bool owner, const ObjectClass* type, FunctionBar* fuBar) {
Panel* Panel_new(int x, int y, int w, int h, const ObjectClass* type, bool owner, FunctionBar* fuBar) {
Panel* this;
this = xMalloc(sizeof(Panel));
Object_setClass(this, Class(Panel));
@ -76,13 +76,6 @@ void Panel_setSelectionColor(Panel* this, ColorElements colorId) {
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) {
RichString_writeWide(&(this->header), CRT_colors[PANEL_HEADER_FOCUS], header);
this->needsRedraw = true;
@ -99,10 +92,6 @@ void Panel_move(Panel* this, int x, int y) {
void Panel_resize(Panel* this, int w, int h) {
assert (this != NULL);
if (RichString_sizeVal(this->header) > 0) {
h--;
}
this->w = w;
this->h = h;
this->needsRedraw = true;
@ -219,7 +208,7 @@ void Panel_splice(Panel* this, Vector* from) {
this->needsRedraw = true;
}
void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelected) {
void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelected, bool hideFunctionBar) {
assert (this != NULL);
int size = Vector_size(this->items);
@ -228,20 +217,29 @@ void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelect
int x = this->x;
int h = this->h;
if (hideFunctionBar)
h++;
const int header_attr = focus
? CRT_colors[PANEL_HEADER_FOCUS]
: CRT_colors[PANEL_HEADER_UNFOCUS];
if (force_redraw) {
if (Panel_printHeaderFn(this))
Panel_printHeader(this);
else
RichString_setAttr(&this->header, header_attr);
}
int headerLen = RichString_sizeVal(this->header);
if (headerLen > 0) {
int attr = focus
? CRT_colors[PANEL_HEADER_FOCUS]
: CRT_colors[PANEL_HEADER_UNFOCUS];
attrset(attr);
attrset(header_attr);
mvhline(y, x, ' ', this->w);
if (scrollH < headerLen) {
RichString_setAttr(&this->header, attr);
RichString_printoffnVal(this->header, y, x, scrollH,
MINIMUM(headerLen - scrollH, this->w));
}
attrset(CRT_colors[RESET_COLOR]);
y++;
h--;
}
// ensure scroll area is on screen
@ -324,8 +322,8 @@ void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelect
if (focus && (this->needsRedraw || force_redraw || !this->wasFocus)) {
if (Panel_drawFunctionBarFn(this))
Panel_drawFunctionBar(this);
else
Panel_drawFunctionBar(this, hideFunctionBar);
else if (!hideFunctionBar)
FunctionBar_draw(this->currentBar);
}
@ -335,13 +333,21 @@ void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelect
move(0, 0);
}
static int Panel_headerHeight(const Panel* this) {
return RichString_sizeVal(this->header) > 0 ? 1 : 0;
}
bool Panel_onKey(Panel* this, int key) {
assert (this != NULL);
int size = Vector_size(this->items);
const int size = Vector_size(this->items);
#define CLAMP_INDEX(var, delta, min, max) \
CLAMP((var) + (delta), (min), MAXIMUM(0, (max)))
#define PANEL_SCROLL(amount) \
do { \
this->selected += (amount); \
this->scrollV = CLAMP(this->scrollV + (amount), 0, MAXIMUM(0, (size - this->h - Panel_headerHeight(this)))); \
this->needsRedraw = true; \
} while (0)
switch (key) {
case KEY_DOWN:
@ -375,27 +381,19 @@ bool Panel_onKey(Panel* this, int key) {
break;
case KEY_PPAGE:
this->selected -= (this->h - 1);
this->scrollV = CLAMP_INDEX(this->scrollV, -(this->h - 1), 0, size - this->h);
this->needsRedraw = true;
PANEL_SCROLL(-(this->h - Panel_headerHeight(this)));
break;
case KEY_NPAGE:
this->selected += (this->h - 1);
this->scrollV = CLAMP_INDEX(this->scrollV, +(this->h - 1), 0, size - this->h);
this->needsRedraw = true;
PANEL_SCROLL(+(this->h - Panel_headerHeight(this)));
break;
case KEY_WHEELUP:
this->selected -= CRT_scrollWheelVAmount;
this->scrollV = CLAMP_INDEX(this->scrollV, -CRT_scrollWheelVAmount, 0, size - this->h);
this->needsRedraw = true;
PANEL_SCROLL(-CRT_scrollWheelVAmount);
break;
case KEY_WHEELDOWN:
this->selected += CRT_scrollWheelVAmount;
this->scrollV = CLAMP_INDEX(this->scrollV, +CRT_scrollWheelVAmount, 0, size - this->h);
this->needsRedraw = true;
PANEL_SCROLL(+CRT_scrollWheelVAmount);
break;
case KEY_HOME:
@ -420,7 +418,7 @@ bool Panel_onKey(Panel* this, int key) {
return false;
}
#undef CLAMP_INDEX
#undef PANEL_SCROLL
// ensure selection within bounds
if (this->selected < 0 || size == 0) {

22
Panel.h
View File

@ -36,19 +36,23 @@ typedef enum HandlerResult_ {
#define EVENT_HEADER_CLICK_GET_X(ev_) ((ev_) + 10000)
typedef HandlerResult (*Panel_EventHandler)(Panel*, int);
typedef void (*Panel_DrawFunctionBar)(Panel*);
typedef void (*Panel_DrawFunctionBar)(Panel*, bool);
typedef void (*Panel_PrintHeader)(Panel*);
typedef struct PanelClass_ {
const ObjectClass super;
const Panel_EventHandler eventHandler;
const Panel_DrawFunctionBar drawFunctionBar;
const Panel_PrintHeader printHeader;
} PanelClass;
#define As_Panel(this_) ((const PanelClass*)((this_)->super.klass))
#define Panel_eventHandlerFn(this_) As_Panel(this_)->eventHandler
#define Panel_eventHandler(this_, ev_) (assert(As_Panel(this_)->eventHandler), As_Panel(this_)->eventHandler((Panel*)(this_), ev_))
#define Panel_drawFunctionBarFn(this_) As_Panel(this_)->drawFunctionBar
#define Panel_drawFunctionBar(this_) (assert(As_Panel(this_)->drawFunctionBar), As_Panel(this_)->drawFunctionBar((Panel*)(this_)))
#define As_Panel(this_) ((const PanelClass*)((this_)->super.klass))
#define Panel_eventHandlerFn(this_) As_Panel(this_)->eventHandler
#define Panel_eventHandler(this_, ev_) (assert(As_Panel(this_)->eventHandler), As_Panel(this_)->eventHandler((Panel*)(this_), ev_))
#define Panel_drawFunctionBarFn(this_) As_Panel(this_)->drawFunctionBar
#define Panel_drawFunctionBar(this_, hideFB_) (assert(As_Panel(this_)->drawFunctionBar), As_Panel(this_)->drawFunctionBar((Panel*)(this_), hideFB_))
#define Panel_printHeaderFn(this_) As_Panel(this_)->printHeader
#define Panel_printHeader(this_) (assert(As_Panel(this_)->printHeader), As_Panel(this_)->printHeader((Panel*)(this_)))
struct Panel_ {
Object super;
@ -74,7 +78,7 @@ struct Panel_ {
extern const PanelClass Panel_class;
Panel* Panel_new(int x, int y, int w, int h, bool owner, const ObjectClass* type, FunctionBar* fuBar);
Panel* Panel_new(int x, int y, int w, int h, const ObjectClass* type, bool owner, FunctionBar* fuBar);
void Panel_delete(Object* cast);
@ -84,8 +88,6 @@ void Panel_done(Panel* this);
void Panel_setSelectionColor(Panel* this, ColorElements colorId);
RichString* Panel_getHeader(Panel* this);
void Panel_setHeader(Panel* this, const char* header);
void Panel_move(Panel* this, int x, int y);
@ -116,7 +118,7 @@ int Panel_size(Panel* this);
void Panel_setSelected(Panel* this, int selected);
void Panel_draw(Panel* this, bool force_redraw, 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);

View File

@ -183,34 +183,34 @@ void Process_fillStarttimeBuffer(Process* this) {
}
static inline void Process_writeCommand(const Process* this, int attr, int baseattr, RichString* str) {
int start = RichString_size(str), finish = 0;
int start = RichString_size(str);
int len = 0;
const char* comm = this->comm;
if (this->settings->highlightBaseName || !this->settings->showProgramPath) {
int i, basename = 0;
for (i = 0; i < this->basenameOffset; i++) {
int basename = 0;
for (int i = 0; i < this->basenameOffset; i++) {
if (comm[i] == '/') {
basename = i + 1;
} else if (comm[i] == ':') {
finish = i + 1;
len = i + 1;
break;
}
}
if (!finish) {
if (len == 0) {
if (this->settings->showProgramPath) {
start += basename;
} else {
comm += basename;
}
finish = this->basenameOffset - basename;
len = this->basenameOffset - basename;
}
finish += start - 1;
}
RichString_appendWide(str, attr, comm);
if (this->settings->highlightBaseName) {
RichString_setAttrn(str, baseattr, start, finish);
RichString_setAttrn(str, baseattr, start, len);
}
}
@ -244,6 +244,11 @@ void Process_outputRate(RichString* str, char* buffer, size_t n, double rate, in
}
}
void Process_printLeftAlignedField(RichString* str, int attr, const char* content, unsigned int width) {
int c = RichString_appendnWide(str, attr, content, MINIMUM(width, strlen(content)));
RichString_appendChr(str, ' ', width + 1 - c);
}
void Process_writeField(const Process* this, RichString* str, ProcessField field) {
char buffer[256]; buffer[255] = '\0';
int attr = CRT_colors[DEFAULT_COLOR];
@ -363,15 +368,13 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
case USER: {
if (Process_getuid != this->st_uid)
attr = CRT_colors[PROCESS_SHADOW];
if (this->user) {
xSnprintf(buffer, n, "%-9s ", this->user);
} else {
xSnprintf(buffer, n, "%-9d ", this->st_uid);
}
if (buffer[9] != '\0') {
buffer[9] = ' ';
buffer[10] = '\0';
Process_printLeftAlignedField(str, attr, this->user, 9);
return;
}
xSnprintf(buffer, n, "%-9d ", this->st_uid);
break;
}
default:
@ -477,14 +480,14 @@ bool Process_sendSignal(Process* this, Arg sgn) {
return ok;
}
long Process_pidCompare(const void* v1, const void* v2) {
int Process_pidCompare(const void* v1, const void* v2) {
const Process* p1 = (const Process*)v1;
const Process* p2 = (const Process*)v2;
return SPACESHIP_NUMBER(p1->pid, p2->pid);
}
long Process_compare(const void* v1, const void* v2) {
int Process_compare(const void* v1, const void* v2) {
const Process *p1, *p2;
const Settings *settings = ((const Process*)v1)->settings;
@ -498,7 +501,7 @@ long Process_compare(const void* v1, const void* v2) {
ProcessField key = Settings_getActiveSortKey(settings);
long result = Process_compareByKey(p1, p2, key);
int result = Process_compareByKey(p1, p2, key);
// Implement tie-breaker (needed to make tree mode more stable)
if (!result)
@ -507,7 +510,7 @@ long Process_compare(const void* v1, const void* v2) {
return result;
}
long Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField key) {
int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField key) {
int r;
switch (key) {

View File

@ -122,7 +122,7 @@ typedef struct ProcessFieldData_ {
// Implemented in platform-specific code:
void Process_writeField(const Process* this, RichString* str, ProcessField field);
long Process_compare(const void* v1, const void* v2);
int Process_compare(const void* v1, const void* v2);
void Process_delete(Object* cast);
bool Process_isThread(const Process* this);
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
@ -131,7 +131,7 @@ extern int Process_pidDigits;
typedef Process*(*Process_New)(const struct Settings_*);
typedef void (*Process_WriteField)(const Process*, RichString*, ProcessField);
typedef long (*Process_CompareByKey)(const Process*, const Process*, ProcessField);
typedef int (*Process_CompareByKey)(const Process*, const Process*, ProcessField);
typedef const char* (*Process_GetCommandStr)(const Process*);
typedef struct ProcessClass_ {
@ -179,6 +179,8 @@ void Process_fillStarttimeBuffer(Process* this);
void Process_outputRate(RichString* str, char* buffer, size_t n, double rate, int coloring);
void Process_printLeftAlignedField(RichString* str, int attr, const char* content, unsigned int width);
void Process_display(const Object* cast, RichString* out);
void Process_done(Process* this);
@ -199,8 +201,8 @@ bool Process_changePriorityBy(Process* this, Arg delta);
bool Process_sendSignal(Process* this, Arg sgn);
long Process_pidCompare(const void* v1, const void* v2);
int Process_pidCompare(const void* v1, const void* v2);
long Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField key);
int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField key);
#endif

View File

@ -112,6 +112,13 @@ void ProcessList_printHeader(ProcessList* this, RichString* header) {
}
RichString_appendWide(header, color, alignedProcessFieldTitle(fields[i]));
if (key == fields[i] && RichString_getCharVal(*header, RichString_size(header) - 1) == ' ') {
header->chlen--; // rewind to override space
RichString_appendnWide(header,
CRT_colors[PANEL_SELECTION_FOCUS],
CRT_treeStr[Settings_getActiveDirection(this->settings) == 1 ? TREE_STR_DESC : TREE_STR_ASC],
1);
}
if (COMM == fields[i] && settings->showMergedCommand) {
RichString_appendAscii(header, color, "(merged)");
}
@ -141,7 +148,7 @@ void ProcessList_remove(ProcessList* this, Process* p) {
Process* pp = Hashtable_remove(this->processTable, p->pid);
assert(pp == p); (void)pp;
unsigned int pid = p->pid;
pid_t pid = p->pid;
int idx = Vector_indexOf(this->processes, p, Process_pidCompare);
assert(idx != -1);
@ -149,7 +156,12 @@ void ProcessList_remove(ProcessList* this, Process* p) {
Vector_remove(this->processes, idx);
}
assert(Hashtable_get(this->processTable, pid) == NULL); (void)pid;
if (this->following != -1 && this->following == pid) {
this->following = -1;
Panel_setSelectionColor(this->panel, PANEL_SELECTION_FOCUS);
}
assert(Hashtable_get(this->processTable, pid) == NULL);
assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
}
@ -348,14 +360,14 @@ static void ProcessList_buildTreeBranch(ProcessList* this, pid_t pid, int level,
Vector_delete(children);
}
static long ProcessList_treeProcessCompare(const void* v1, const void* v2) {
static int ProcessList_treeProcessCompare(const void* v1, const void* v2) {
const Process *p1 = (const Process*)v1;
const Process *p2 = (const Process*)v2;
return SPACESHIP_NUMBER(p1->tree_left, p2->tree_left);
}
static long ProcessList_treeProcessCompareByPID(const void* v1, const void* v2) {
static int ProcessList_treeProcessCompareByPID(const void* v1, const void* v2) {
const Process *p1 = (const Process*)v1;
const Process *p2 = (const Process*)v2;
@ -486,7 +498,6 @@ void ProcessList_rebuildPanel(ProcessList* this) {
const char* incFilter = this->incFilter;
int currPos = Panel_getSelectedIndex(this->panel);
pid_t currPid = this->following != -1 ? this->following : 0;
int currScrollV = this->panel->scrollV;
Panel_prune(this->panel);
@ -502,7 +513,7 @@ void ProcessList_rebuildPanel(ProcessList* this) {
continue;
Panel_set(this->panel, idx, (Object*)p);
if ((this->following == -1 && idx == currPos) || (this->following != -1 && p->pid == currPid)) {
if ((this->following == -1 && idx == currPos) || (this->following != -1 && p->pid == this->following)) {
Panel_setSelected(this->panel, idx);
this->panel->scrollV = currScrollV;
}

View File

@ -27,7 +27,7 @@ ProcessLocksScreen* ProcessLocksScreen_new(const Process* process) {
this->pid = process->tgid;
else
this->pid = process->pid;
return (ProcessLocksScreen*) InfoScreen_init(&this->super, process, NULL, LINES-3, " ID TYPE EXCLUSION READ/WRITE DEVICE:INODE START END FILENAME");
return (ProcessLocksScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " ID TYPE EXCLUSION READ/WRITE DEVICE:INODE START END FILENAME");
}
void ProcessLocksScreen_delete(Object* this) {

View File

@ -48,33 +48,35 @@ static void RichString_setLen(RichString* this, int len) {
#ifdef HAVE_LIBNCURSESW
static inline void RichString_writeFromWide(RichString* this, int attrs, const char* data_c, int from, int len) {
static inline int RichString_writeFromWide(RichString* this, int attrs, const char* data_c, int from, int len) {
wchar_t data[len + 1];
len = mbstowcs(data, data_c, len);
if (len < 0)
return;
if (len <= 0)
return 0;
int newLen = from + len;
RichString_setLen(this, newLen);
for (int i = from, j = 0; i < newLen; i++, j++) {
this->chptr[i] = (CharType) { .attr = attrs & 0xffffff, .chars = { (iswprint(data[j]) ? data[j] : '?') } };
}
return wcswidth(data, len);
}
static inline void RichString_writeFromAscii(RichString* this, int attrs, const char* data, int from, int len) {
static inline int RichString_writeFromAscii(RichString* this, int attrs, const char* data, int from, int len) {
int newLen = from + len;
RichString_setLen(this, newLen);
for (int i = from, j = 0; i < newLen; i++, j++) {
this->chptr[i] = (CharType) { .attr = attrs & 0xffffff, .chars = { (isprint(data[j]) ? data[j] : '?') } };
}
return len;
}
inline void RichString_setAttrn(RichString* this, int attrs, int start, int finish) {
cchar_t* ch = this->chptr + start;
finish = CLAMP(finish, 0, this->chlen - 1);
for (int i = start; i <= finish; i++) {
ch->attr = attrs;
ch++;
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;
}
}
@ -91,25 +93,25 @@ int RichString_findChar(RichString* this, char c, int start) {
#else /* HAVE_LIBNCURSESW */
static inline void RichString_writeFromWide(RichString* this, int attrs, const char* data_c, int from, int len) {
static inline int RichString_writeFromWide(RichString* this, int attrs, const char* data_c, int from, int len) {
int newLen = from + len;
RichString_setLen(this, newLen);
for (int i = from, j = 0; i < newLen; i++, j++) {
this->chptr[i] = (((unsigned char)data_c[j]) >= 32 ? ((unsigned char)data_c[j]) : '?') | attrs;
}
this->chptr[newLen] = 0;
return len;
}
static inline void RichString_writeFromAscii(RichString* this, int attrs, const char* data_c, int from, int len) {
RichString_writeFromWide(this, attrs, data_c, from, len);
static inline int RichString_writeFromAscii(RichString* this, int attrs, const char* data_c, int from, int len) {
return RichString_writeFromWide(this, attrs, data_c, from, len);
}
void RichString_setAttrn(RichString* this, int attrs, int start, int finish) {
chtype* ch = this->chptr + start;
finish = CLAMP(finish, 0, this->chlen - 1);
for (int i = start; i <= finish; i++) {
*ch = (*ch & 0xff) | attrs;
ch++;
void RichString_setAttrn(RichString* this, int attrs, int start, int charcount) {
int end = CLAMP(start + charcount, 0, this->chlen);
for (int i = start; i < end; i++) {
this->chptr[i] = (this->chptr[i] & 0xff) | attrs;
}
}
@ -142,29 +144,29 @@ void RichString_appendChr(RichString* this, char c, int count) {
}
void RichString_setAttr(RichString* this, int attrs) {
RichString_setAttrn(this, attrs, 0, this->chlen - 1);
RichString_setAttrn(this, attrs, 0, this->chlen);
}
void RichString_appendWide(RichString* this, int attrs, const char* data) {
RichString_writeFromWide(this, attrs, data, this->chlen, strlen(data));
int RichString_appendWide(RichString* this, int attrs, const char* data) {
return RichString_writeFromWide(this, attrs, data, this->chlen, strlen(data));
}
void RichString_appendnWide(RichString* this, int attrs, const char* data, int len) {
RichString_writeFromWide(this, attrs, data, this->chlen, len);
int RichString_appendnWide(RichString* this, int attrs, const char* data, int len) {
return RichString_writeFromWide(this, attrs, data, this->chlen, len);
}
void RichString_writeWide(RichString* this, int attrs, const char* data) {
RichString_writeFromWide(this, attrs, data, 0, strlen(data));
int RichString_writeWide(RichString* this, int attrs, const char* data) {
return RichString_writeFromWide(this, attrs, data, 0, strlen(data));
}
void RichString_appendAscii(RichString* this, int attrs, const char* data) {
RichString_writeFromAscii(this, attrs, data, this->chlen, strlen(data));
int RichString_appendAscii(RichString* this, int attrs, const char* data) {
return RichString_writeFromAscii(this, attrs, data, this->chlen, strlen(data));
}
void RichString_appendnAscii(RichString* this, int attrs, const char* data, int len) {
RichString_writeFromAscii(this, attrs, data, this->chlen, len);
int RichString_appendnAscii(RichString* this, int attrs, const char* data, int len) {
return RichString_writeFromAscii(this, attrs, data, this->chlen, len);
}
void RichString_writeAscii(RichString* this, int attrs, const char* data) {
RichString_writeFromAscii(this, attrs, data, 0, strlen(data));
int RichString_writeAscii(RichString* this, int attrs, const char* data) {
return RichString_writeFromAscii(this, attrs, data, 0, strlen(data));
}

View File

@ -42,7 +42,7 @@ typedef struct RichString_ {
int highlightAttr;
} RichString;
void RichString_setAttrn(RichString* this, int attrs, int start, int finish);
void RichString_setAttrn(RichString* this, int attrs, int start, int charcount);
int RichString_findChar(RichString* this, char c, int start);
@ -52,16 +52,16 @@ void RichString_setAttr(RichString* this, int attrs);
void RichString_appendChr(RichString* this, char c, int count);
void RichString_appendWide(RichString* this, int attrs, const char* data);
int RichString_appendWide(RichString* this, int attrs, const char* data);
void RichString_appendnWide(RichString* this, int attrs, const char* data, int len);
int RichString_appendnWide(RichString* this, int attrs, const char* data, int len);
void RichString_writeWide(RichString* this, int attrs, const char* data);
int RichString_writeWide(RichString* this, int attrs, const char* data);
void RichString_appendAscii(RichString* this, int attrs, const char* data);
int RichString_appendAscii(RichString* this, int attrs, const char* data);
void RichString_appendnAscii(RichString* this, int attrs, const char* data, int len);
int RichString_appendnAscii(RichString* this, int attrs, const char* data, int len);
void RichString_writeAscii(RichString* this, int attrs, const char* data);
int RichString_writeAscii(RichString* this, int attrs, const char* data);
#endif

View File

@ -123,8 +123,8 @@ static void ScreenManager_drawPanels(ScreenManager* this, int focus, bool force_
const int nPanels = this->panelCount;
for (int i = 0; i < nPanels; i++) {
Panel* panel = (Panel*) Vector_get(this->panels, i);
Panel_draw(panel, force_redraw, i == focus, !((panel == this->state->panel) && this->state->hideProcessSelection));
mvvline(panel->y, panel->x + panel->w, ' ', panel->h + 1);
Panel_draw(panel, force_redraw, i == focus, !((panel == this->state->panel) && this->state->hideProcessSelection), State_hideFunctionBar(this->state));
mvvline(panel->y, panel->x + panel->w, ' ', panel->h + (State_hideFunctionBar(this->state) ? 1 : 0));
}
}
@ -141,7 +141,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
bool timedOut = true;
bool redraw = true;
bool force_redraw = false;
bool force_redraw = true;
bool rescan = false;
int sortTimeout = 0;
int resetSortTimeout = 5;

View File

@ -221,6 +221,8 @@ static bool Settings_read(Settings* this, const char* fileName, int initialCpuCo
} else if (String_eq(option[0], "right_meter_modes")) {
Settings_readMeterModes(this, option[1], 1);
didReadMeters = true;
} else if (String_eq(option[0], "hide_function_bar")) {
this->hideFunctionBar = atoi(option[1]);
#ifdef HAVE_LIBHWLOC
} else if (String_eq(option[0], "topology_affinity")) {
this->topologyAffinity = !!atoi(option[1]);
@ -315,6 +317,7 @@ bool Settings_write(Settings* this) {
fprintf(fd, "left_meter_modes="); writeMeterModes(this, fd, 0);
fprintf(fd, "right_meters="); writeMeters(this, fd, 1);
fprintf(fd, "right_meter_modes="); writeMeterModes(this, fd, 1);
fprintf(fd, "hide_function_bar=%d\n", (int) this->hideFunctionBar);
#ifdef HAVE_LIBHWLOC
fprintf(fd, "topology_affinity=%d\n", (int) this->topologyAffinity);
#endif
@ -352,6 +355,7 @@ Settings* Settings_new(int initialCpuCount) {
this->findCommInCmdline = true;
this->stripExeFromCmdline = true;
this->showMergedCommand = false;
this->hideFunctionBar = 0;
#ifdef HAVE_LIBHWLOC
this->topologyAffinity = false;
#endif

View File

@ -64,6 +64,7 @@ typedef struct Settings_ {
bool accountGuestInCPUMeter;
bool headerMargin;
bool enableMouse;
int hideFunctionBar; // 0 - off, 1 - on ESC until next input, 2 - permanently
#ifdef HAVE_LIBHWLOC
bool topologyAffinity;
#endif

View File

@ -19,7 +19,7 @@ in the source distribution for its full text.
Panel* SignalsPanel_new() {
Panel* this = Panel_new(1, 1, 1, 1, true, Class(ListItem), FunctionBar_newEnterEsc("Send ", "Cancel "));
Panel* this = Panel_new(1, 1, 1, 1, Class(ListItem), true, FunctionBar_newEnterEsc("Send ", "Cancel "));
const int defaultSignal = SIGTERM;
int defaultPosition = 15;
unsigned int i;

View File

@ -58,7 +58,7 @@ unsigned int Vector_count(const Vector* this);
#else /* NDEBUG */
static inline Object* Vector_get(Vector* this, int idx) {
static inline Object* Vector_get(const Vector* this, int idx) {
return this->array[idx];
}

View File

@ -13,6 +13,7 @@ in the source distribution for its full text.
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@ -36,9 +37,21 @@ void* xMalloc(size_t size) {
return data;
}
void* xMallocArray(size_t nmemb, size_t size) {
assert(nmemb > 0);
assert(size > 0);
if (SIZE_MAX / nmemb < size) {
fail();
}
return xMalloc(nmemb * size);
}
void* xCalloc(size_t nmemb, size_t size) {
assert(nmemb > 0);
assert(size > 0);
if (SIZE_MAX / nmemb < size) {
fail();
}
void* data = calloc(nmemb, size);
if (!data) {
fail();
@ -56,6 +69,15 @@ void* xRealloc(void* ptr, size_t size) {
return data;
}
void* xReallocArray(void* ptr, size_t nmemb, size_t size) {
assert(nmemb > 0);
assert(size > 0);
if (SIZE_MAX / nmemb < size) {
fail();
}
return xRealloc(ptr, nmemb * size);
}
char* String_cat(const char* s1, const char* s2) {
const size_t l1 = strlen(s1);
const size_t l2 = strlen(s2);

View File

@ -23,10 +23,14 @@ void fail(void) ATTR_NORETURN;
void* xMalloc(size_t size);
void* xMallocArray(size_t nmemb, size_t size);
void* xCalloc(size_t nmemb, size_t size);
void* xRealloc(void* ptr, size_t size);
void* xReallocArray(void* ptr, size_t nmemb, size_t size);
/*
* String_startsWith gives better performance if strlen(match) can be computed
* at compile time (e.g. when they are immutable string literals). :)

View File

@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.65)
AC_INIT([htop],[3.0.4],[htop@groups.io])
AC_INIT([htop],[3.0.5],[htop@groups.io])
AC_CONFIG_SRCDIR([htop.c])
AC_CONFIG_AUX_DIR([.])

View File

@ -82,7 +82,7 @@ static void DarwinProcess_writeField(const Process* this, RichString* str, Proce
RichString_appendWide(str, attr, buffer);
}
static long DarwinProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
static int DarwinProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
const DarwinProcess* p1 = (const DarwinProcess*)v1;
const DarwinProcess* p2 = (const DarwinProcess*)v2;

View File

@ -7,7 +7,6 @@ in the source distribution for its full text.
#include "DarwinProcessList.h"
#include <err.h>
#include <errno.h>
#include <libproc.h>
#include <stdbool.h>
@ -161,7 +160,7 @@ void ProcessList_delete(ProcessList* this) {
static double ticksToNanoseconds(const double ticks) {
const double nanos_per_sec = 1e9;
return ticks / (double) Platform_clockTicksPerSec * Platform_timebaseToNS * nanos_per_sec;
return (ticks / Platform_timebaseToNS) * (nanos_per_sec / (double) Platform_clockTicksPerSec);
}
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {

View File

@ -71,14 +71,7 @@ static void DragonFlyBSDProcess_writeField(const Process* this, RichString* str,
// add Platform-specific fields here
case PID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, (fp->kernel ? -1 : this->pid)); break;
case JID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, fp->jid); break;
case JAIL: {
xSnprintf(buffer, n, "%-11s ", fp->jname);
if (buffer[11] != '\0') {
buffer[11] = ' ';
buffer[12] = '\0';
}
break;
}
case JAIL: Process_printLeftAlignedField(str, attr, fp->jname, 11); return;
default:
Process_writeField(this, str, field);
return;
@ -86,7 +79,7 @@ static void DragonFlyBSDProcess_writeField(const Process* this, RichString* str,
RichString_appendWide(str, attr, buffer);
}
static long DragonFlyBSDProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
static int DragonFlyBSDProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
const DragonFlyBSDProcess* p1 = (const DragonFlyBSDProcess*)v1;
const DragonFlyBSDProcess* p2 = (const DragonFlyBSDProcess*)v2;

View File

@ -15,7 +15,6 @@ in the source distribution for its full text.
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <err.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>
@ -112,7 +111,7 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
dfpl->kd = kvm_openfiles(NULL, "/dev/null", NULL, 0, errbuf);
if (dfpl->kd == NULL) {
errx(1, "kvm_open: %s", errbuf);
CRT_fatalError("kvm_openfiles() failed");
}
return pl;
@ -294,25 +293,20 @@ static inline void DragonFlyBSDProcessList_scanJails(DragonFlyBSDProcessList* df
char* nextpos;
if (sysctlbyname("jail.list", NULL, &len, NULL, 0) == -1) {
fprintf(stderr, "initial sysctlbyname / jail.list failed\n");
exit(3);
CRT_fatalError("initial sysctlbyname / jail.list failed");
}
retry:
if (len == 0)
return;
jls = xMalloc(len);
if (jls == NULL) {
fprintf(stderr, "xMalloc failed\n");
exit(4);
}
if (sysctlbyname("jail.list", jls, &len, NULL, 0) == -1) {
if (errno == ENOMEM) {
free(jls);
goto retry;
}
fprintf(stderr, "sysctlbyname / jail.list failed\n");
exit(5);
CRT_fatalError("sysctlbyname / jail.list failed");
}
if (dfpl->jails) {

View File

@ -71,14 +71,9 @@ static void FreeBSDProcess_writeField(const Process* this, RichString* str, Proc
switch (field) {
// add FreeBSD-specific fields here
case JID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, fp->jid); break;
case JAIL: {
xSnprintf(buffer, n, "%-11s ", fp->jname);
if (buffer[11] != '\0') {
buffer[11] = ' ';
buffer[12] = '\0';
}
break;
}
case JAIL:
Process_printLeftAlignedField(str, attr, fp->jname ? fp->jname : "N/A", 11);
return;
case TTY_NR:
if (fp->ttyPath) {
if (fp->ttyPath == nodevStr)
@ -96,7 +91,7 @@ static void FreeBSDProcess_writeField(const Process* this, RichString* str, Proc
RichString_appendWide(str, attr, buffer);
}
static long FreeBSDProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
static int FreeBSDProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
const FreeBSDProcess* p1 = (const FreeBSDProcess*)v1;
const FreeBSDProcess* p2 = (const FreeBSDProcess*)v2;

View File

@ -9,7 +9,6 @@ in the source distribution for its full text.
#include <assert.h>
#include <dirent.h>
#include <err.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
@ -145,7 +144,7 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
fpl->kd = kvm_openfiles(NULL, "/dev/null", NULL, 0, errbuf);
if (fpl->kd == NULL) {
errx(1, "kvm_open: %s", errbuf);
CRT_fatalError("kvm_openfiles() failed");
}
fpl->ttys = Hashtable_new(20, true);
@ -415,7 +414,7 @@ static char* FreeBSDProcessList_readJailName(const struct kinfo_proc* kproc) {
char* jname = NULL;
char jnamebuf[MAXHOSTNAMELEN];
if (kproc->ki_jid != 0 ) {
if (kproc->ki_jid != 0) {
struct iovec jiov[6];
memset(jnamebuf, 0, sizeof(jnamebuf));

View File

@ -42,7 +42,8 @@ Display a help message and exit
Show only the given PIDs
.TP
\fB\-s \-\-sort\-key COLUMN\fR
Sort by this column (use \-\-sort\-key help for a column list)
Sort by this column (use \-\-sort\-key help for a column list).
This will force a list view unless you specify -t at the same time.
.TP
\fB\-u \-\-user=USERNAME\fR
Show only the processes of a given user
@ -57,7 +58,8 @@ Disable support of mouse control
Output version information and exit
.TP
\fB\-t \-\-tree
Show processes in tree view
Show processes in tree view. This can be used to force a tree view when
requesting a sort order with -s.
.TP
\fB\-H \-\-highlight-changes=DELAY\fR
Highlight new and old processes
@ -135,6 +137,7 @@ select which columns are displayed, in which order.
Incrementally search the command lines of all the displayed processes. The
currently selected (highlighted) command will update as you type. While in
search mode, pressing F3 will cycle through matching occurrences.
Pressing Shift-F3 will cycle backwards.
Alternatively the search can be started by simply typing the command
you are looking for, although for the first character normal key
@ -184,6 +187,9 @@ Set CPU affinity: mark which CPUs a process is allowed to use.
.B u
Show only processes owned by a specified user.
.TP
.B N
Sort by PID.
.TP
.B M
Sort by memory usage (top compatibility key).
.TP

9
htop.c
View File

@ -49,8 +49,8 @@ static void printHelpFlag(void) {
"-H --highlight-changes[=DELAY] Highlight new and old processes\n"
"-M --no-mouse Disable the mouse\n"
"-p --pid=PID[,PID,PID...] Show only the given PIDs\n"
"-s --sort-key=COLUMN Sort by COLUMN (try --sort-key=help for a list)\n"
"-t --tree Show the tree view by default\n"
"-s --sort-key=COLUMN Sort by COLUMN in list view (try --sort-key=help for a list)\n"
"-t --tree Show the tree view (can be combined with -s)\n"
"-u --user[=USERNAME] Show only processes for a given user (or $USER)\n"
"-U --no-unicode Do not use unicode but plain ASCII\n"
"-V --version Print version info\n"
@ -93,7 +93,7 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
.highlightDelaySecs = -1,
};
static struct option long_opts[] =
const struct option long_opts[] =
{
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
@ -204,6 +204,7 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
}
case 'F': {
assert(optarg);
free(flags.commFilter);
flags.commFilter = xStrdup(optarg);
break;
@ -313,8 +314,6 @@ int main(int argc, char** argv) {
MainPanel_updateTreeFunctions(panel, settings->treeView);
ProcessList_printHeader(pl, Panel_getHeader((Panel*)panel));
State state = {
.settings = settings,
.ut = ut,

View File

@ -17,7 +17,7 @@ in the source distribution for its full text.
Panel* IOPriorityPanel_new(IOPriority currPrio) {
Panel* this = Panel_new(1, 1, 1, 1, true, Class(ListItem), FunctionBar_newEnterEsc("Set ", "Cancel "));
Panel* this = Panel_new(1, 1, 1, 1, Class(ListItem), true, FunctionBar_newEnterEsc("Set ", "Cancel "));
Panel_setHeader(this, "IO Priority:");
Panel_add(this, (Object*) ListItem_new("None (based on nice)", IOPriority_None));

View File

@ -23,13 +23,15 @@ static void* dlopenHandle = NULL;
int LibSensors_init(FILE* input) {
if (!dlopenHandle) {
/* Find the unversioned libsensors.so (symlink) and prefer that, but Debian has .so.5 and Fedora .so.4 without
matching symlinks (unless people install the -dev packages) */
dlopenHandle = dlopen("libsensors.so", RTLD_LAZY);
if (!dlopenHandle) {
/* Debian contains no unversioned .so in libsensors5, only in the -dev package, so work around that: */
if (!dlopenHandle)
dlopenHandle = dlopen("libsensors.so.5", RTLD_LAZY);
if (!dlopenHandle)
goto dlfailure;
}
if (!dlopenHandle)
dlopenHandle = dlopen("libsensors.so.4", RTLD_LAZY);
if (!dlopenHandle)
goto dlfailure;
/* Clear any errors */
dlerror();
@ -84,7 +86,10 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int cpuCount) {
for (const sensors_chip_name *chip = sym_sensors_get_detected_chips(NULL, &n); chip; chip = sym_sensors_get_detected_chips(NULL, &n)) {
char buffer[32];
sym_sensors_snprintf_chip_name(buffer, sizeof(buffer), chip);
if (!String_startsWith(buffer, "coretemp") && !String_startsWith(buffer, "cpu_thermal"))
if (!String_startsWith(buffer, "coretemp") &&
!String_startsWith(buffer, "cpu_thermal") &&
!String_startsWith(buffer, "k10temp") &&
!String_startsWith(buffer, "zenpower"))
continue;
int m = 0;
@ -102,6 +107,8 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int cpuCount) {
} 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 {

View File

@ -88,9 +88,9 @@ const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
[OOM] = { .name = "OOM", .title = " OOM ", .description = "OOM (Out-of-Memory) killer score", .flags = PROCESS_FLAG_LINUX_OOM, },
[IO_PRIORITY] = { .name = "IO_PRIORITY", .title = "IO ", .description = "I/O priority", .flags = PROCESS_FLAG_LINUX_IOPRIO, },
#ifdef HAVE_DELAYACCT
[PERCENT_CPU_DELAY] = { .name = "PERCENT_CPU_DELAY", .title = "CPUD% ", .description = "CPU delay %", .flags = 0, },
[PERCENT_IO_DELAY] = { .name = "PERCENT_IO_DELAY", .title = "IOD% ", .description = "Block I/O delay %", .flags = 0, },
[PERCENT_SWAP_DELAY] = { .name = "PERCENT_SWAP_DELAY", .title = "SWAPD% ", .description = "Swapin delay %", .flags = 0, },
[PERCENT_CPU_DELAY] = { .name = "PERCENT_CPU_DELAY", .title = "CPUD% ", .description = "CPU delay %", .flags = PROCESS_FLAG_LINUX_DELAYACCT, },
[PERCENT_IO_DELAY] = { .name = "PERCENT_IO_DELAY", .title = "IOD% ", .description = "Block I/O delay %", .flags = PROCESS_FLAG_LINUX_DELAYACCT, },
[PERCENT_SWAP_DELAY] = { .name = "PERCENT_SWAP_DELAY", .title = "SWAPD% ", .description = "Swapin delay %", .flags = PROCESS_FLAG_LINUX_DELAYACCT, },
#endif
[M_PSS] = { .name = "M_PSS", .title = " PSS ", .description = "proportional set size, same as M_RESIDENT but each page is divided by the number of processes sharing it.", .flags = PROCESS_FLAG_LINUX_SMAPS, },
[M_SWAP] = { .name = "M_SWAP", .title = " SWAP ", .description = "Size of the process's swapped pages", .flags = PROCESS_FLAG_LINUX_SMAPS, },
@ -198,12 +198,11 @@ static bool findCommInCmdline(const char *comm, const char *cmdline, int cmdline
/* Try to find procComm in tokenized cmdline - this might in rare cases
* mis-identify a string or fail, if comm or cmdline had been unsuitably
* modified by the process */
const char *token;
const char *tokenBase;
size_t tokenLen;
const size_t commLen = strlen(comm);
for (token = cmdline + cmdlineBasenameOffset; *token; ) {
for (const char *token = cmdline + cmdlineBasenameOffset; *token; ) {
for (tokenBase = token; *token && *token != '\n'; ++token) {
if (*token == '/') {
tokenBase = token + 1;
@ -529,30 +528,30 @@ static void LinuxProcess_writeCommand(const Process* this, int attr, int baseAtt
if (!lp->mergedCommand.separateComm && commStart == baseStart && highlightBaseName) {
/* If it was matched with procExe's basename, make it bold if needed */
if (commEnd > baseEnd) {
RichString_setAttrn(str, A_BOLD | baseAttr, baseStart, baseEnd - 1);
RichString_setAttrn(str, A_BOLD | commAttr, baseEnd, commEnd - 1);
RichString_setAttrn(str, A_BOLD | baseAttr, baseStart, baseEnd - baseStart);
RichString_setAttrn(str, A_BOLD | commAttr, baseEnd, commEnd - baseEnd);
} else if (commEnd < baseEnd) {
RichString_setAttrn(str, A_BOLD | commAttr, commStart, commEnd - 1);
RichString_setAttrn(str, A_BOLD | baseAttr, commEnd, baseEnd - 1);
RichString_setAttrn(str, A_BOLD | commAttr, commStart, commEnd - commStart);
RichString_setAttrn(str, A_BOLD | baseAttr, commEnd, baseEnd - commEnd);
} else {
// Actually should be highlighted commAttr, but marked baseAttr to reduce visual noise
RichString_setAttrn(str, A_BOLD | baseAttr, commStart, commEnd - 1);
RichString_setAttrn(str, A_BOLD | baseAttr, commStart, commEnd - commStart);
}
baseStart = baseEnd;
} else {
RichString_setAttrn(str, commAttr, commStart, commEnd - 1);
RichString_setAttrn(str, commAttr, commStart, commEnd - commStart);
}
}
if (baseStart < baseEnd && highlightBaseName) {
RichString_setAttrn(str, baseAttr, baseStart, baseEnd - 1);
RichString_setAttrn(str, baseAttr, baseStart, baseEnd - baseStart);
}
if (mc->sep1)
RichString_setAttrn(str, CRT_colors[FAILED_READ], strStart + mc->sep1, strStart + mc->sep1);
RichString_setAttrn(str, CRT_colors[FAILED_READ], strStart + mc->sep1, 1);
if (mc->sep2)
RichString_setAttrn(str, CRT_colors[FAILED_READ], strStart + mc->sep2, strStart + mc->sep2);
RichString_setAttrn(str, CRT_colors[FAILED_READ], strStart + mc->sep2, 1);
}
static void LinuxProcess_writeCommandField(const Process *this, RichString *str, char *buffer, int n, int attr) {
@ -708,39 +707,46 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces
return;
}
case PROC_COMM: {
const char* procComm;
if (lp->procComm) {
attr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_COMM : PROCESS_COMM];
/* 15 being (TASK_COMM_LEN - 1) */
xSnprintf(buffer, n, "%-15.15s ", lp->procComm);
procComm = lp->procComm;
} else {
attr = CRT_colors[PROCESS_SHADOW];
xSnprintf(buffer, n, "%-15.15s ", Process_isKernelThread(lp) ? kthreadID : "N/A");
procComm = Process_isKernelThread(lp) ? kthreadID : "N/A";
}
break;
/* 15 being (TASK_COMM_LEN - 1) */
Process_printLeftAlignedField(str, attr, procComm, 15);
return;
}
case PROC_EXE: {
const char* procExe;
if (lp->procExe) {
attr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_BASENAME : PROCESS_BASENAME];
if (lp->procExeDeleted)
attr = CRT_colors[FAILED_READ];
xSnprintf(buffer, n, "%-15.15s ", lp->procExe + lp->procExeBasenameOffset);
procExe = lp->procExe + lp->procExeBasenameOffset;
} else {
attr = CRT_colors[PROCESS_SHADOW];
xSnprintf(buffer, n, "%-15.15s ", Process_isKernelThread(lp) ? kthreadID : "N/A");
procExe = Process_isKernelThread(lp) ? kthreadID : "N/A";
}
break;
Process_printLeftAlignedField(str, attr, procExe, 15);
return;
}
case CWD:
case CWD: {
const char* cwd;
if (!lp->cwd) {
xSnprintf(buffer, n, "%-25s ", "N/A");
attr = CRT_colors[PROCESS_SHADOW];
cwd = "N/A";
} else if (String_startsWith(lp->cwd, "/proc/") && strstr(lp->cwd, " (deleted)") != NULL) {
xSnprintf(buffer, n, "%-25s ", "main thread terminated");
attr = CRT_colors[PROCESS_SHADOW];
cwd = "main thread terminated";
} else {
xSnprintf(buffer, n, "%-25.25s ", lp->cwd);
cwd = lp->cwd;
}
break;
Process_printLeftAlignedField(str, attr, cwd, 25);
return;
}
default:
Process_writeField(this, str, field);
return;
@ -748,7 +754,7 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces
RichString_appendWide(str, attr, buffer);
}
static long LinuxProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
static int LinuxProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
const LinuxProcess* p1 = (const LinuxProcess*)v1;
const LinuxProcess* p2 = (const LinuxProcess*)v2;

View File

@ -18,16 +18,17 @@ in the source distribution for its full text.
#include "Settings.h"
#define PROCESS_FLAG_LINUX_IOPRIO 0x00000100
#define PROCESS_FLAG_LINUX_OPENVZ 0x00000200
#define PROCESS_FLAG_LINUX_VSERVER 0x00000400
#define PROCESS_FLAG_LINUX_CGROUP 0x00000800
#define PROCESS_FLAG_LINUX_OOM 0x00001000
#define PROCESS_FLAG_LINUX_SMAPS 0x00002000
#define PROCESS_FLAG_LINUX_CTXT 0x00004000
#define PROCESS_FLAG_LINUX_SECATTR 0x00008000
#define PROCESS_FLAG_LINUX_LRS_FIX 0x00010000
#define PROCESS_FLAG_LINUX_CWD 0x00020000
#define PROCESS_FLAG_LINUX_IOPRIO 0x00000100
#define PROCESS_FLAG_LINUX_OPENVZ 0x00000200
#define PROCESS_FLAG_LINUX_VSERVER 0x00000400
#define PROCESS_FLAG_LINUX_CGROUP 0x00000800
#define PROCESS_FLAG_LINUX_OOM 0x00001000
#define PROCESS_FLAG_LINUX_SMAPS 0x00002000
#define PROCESS_FLAG_LINUX_CTXT 0x00004000
#define PROCESS_FLAG_LINUX_SECATTR 0x00008000
#define PROCESS_FLAG_LINUX_LRS_FIX 0x00010000
#define PROCESS_FLAG_LINUX_CWD 0x00020000
#define PROCESS_FLAG_LINUX_DELAYACCT 0x00040000
/* LinuxProcessMergedCommand is populated by LinuxProcess_makeCommandStr: It

View File

@ -102,7 +102,7 @@ static void LinuxProcessList_initTtyDrivers(LinuxProcessList* this) {
int numDrivers = 0;
int allocd = 10;
ttyDrivers = xMalloc(sizeof(TtyDriver) * allocd);
ttyDrivers = xMallocArray(allocd, sizeof(TtyDriver));
char* at = buf;
while (*at != '\0') {
at = strchr(at, ' '); // skip first token
@ -136,7 +136,7 @@ static void LinuxProcessList_initTtyDrivers(LinuxProcessList* this) {
numDrivers++;
if (numDrivers == allocd) {
allocd += 10;
ttyDrivers = xRealloc(ttyDrivers, sizeof(TtyDriver) * allocd);
ttyDrivers = xReallocArray(ttyDrivers, allocd, sizeof(TtyDriver));
}
}
numDrivers++;
@ -208,10 +208,6 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
ProcessList_init(pl, Class(LinuxProcess), usersTable, pidMatchList, userId);
LinuxProcessList_initTtyDrivers(this);
#ifdef HAVE_DELAYACCT
LinuxProcessList_initNetlinkSocket(this);
#endif
// Initialize page size
pageSize = sysconf(_SC_PAGESIZE);
if (pageSize == -1)
@ -488,7 +484,7 @@ static inline uint64_t fast_strtoull_hex(char **str, int maxlen) {
return result;
}
static void LinuxProcessList_calcLibSize_helper(ATTR_UNUSED hkey_t key, void* value, void* data) {
static void LinuxProcessList_calcLibSize_helper(ATTR_UNUSED ht_key_t key, void* value, void* data) {
if (!data)
return;
@ -955,12 +951,19 @@ static int handleNetlinkMsg(struct nl_msg* nlmsg, void* linuxProcess) {
static void LinuxProcessList_readDelayAcctData(LinuxProcessList* this, LinuxProcess* process) {
struct nl_msg* msg;
if (!this->netlink_socket) {
LinuxProcessList_initNetlinkSocket(this);
if (!this->netlink_socket) {
goto delayacct_failure;
}
}
if (nl_socket_modify_cb(this->netlink_socket, NL_CB_VALID, NL_CB_CUSTOM, handleNetlinkMsg, process) < 0) {
return;
goto delayacct_failure;
}
if (! (msg = nlmsg_alloc())) {
return;
goto delayacct_failure;
}
if (! genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, this->netlink_family, 0, NLM_F_REQUEST, TASKSTATS_CMD_GET, TASKSTATS_VERSION)) {
@ -972,15 +975,19 @@ static void LinuxProcessList_readDelayAcctData(LinuxProcessList* this, LinuxProc
}
if (nl_send_sync(this->netlink_socket, msg) < 0) {
process->swapin_delay_percent = NAN;
process->blkio_delay_percent = NAN;
process->cpu_delay_percent = NAN;
return;
goto delayacct_failure;
}
if (nl_recvmsgs_default(this->netlink_socket) < 0) {
return;
goto delayacct_failure;
}
return;
delayacct_failure:
process->swapin_delay_percent = NAN;
process->blkio_delay_percent = NAN;
process->cpu_delay_percent = NAN;
}
#endif
@ -1419,7 +1426,9 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
}
#ifdef HAVE_DELAYACCT
LinuxProcessList_readDelayAcctData(this, lp);
if (settings->flags & PROCESS_FLAG_LINUX_DELAYACCT) {
LinuxProcessList_readDelayAcctData(this, lp);
}
#endif
if (settings->flags & PROCESS_FLAG_LINUX_CGROUP) {
@ -1793,7 +1802,9 @@ static void scanCPUFreqencyFromCPUinfo(LinuxProcessList* this) {
continue;
} else if (
(sscanf(buffer, "cpu MHz : %lf", &frequency) == 1) ||
(sscanf(buffer, "cpu MHz: %lf", &frequency) == 1)
(sscanf(buffer, "cpu MHz: %lf", &frequency) == 1) ||
(sscanf(buffer, "clock : %lfMHz", &frequency) == 1) ||
(sscanf(buffer, "clock: %lfMHz", &frequency) == 1)
) {
if (cpuid < 0 || cpuid > (cpus - 1)) {
continue;

View File

@ -202,7 +202,7 @@ static void OpenBSDProcess_writeField(const Process* this, RichString* str, Proc
RichString_appendWide(str, attr, buffer);
}
static long OpenBSDProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
static int OpenBSDProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
const OpenBSDProcess* p1 = (const OpenBSDProcess*)v1;
const OpenBSDProcess* p2 = (const OpenBSDProcess*)v2;

View File

@ -8,7 +8,6 @@ in the source distribution for its full text.
#include "OpenBSDProcessList.h"
#include <err.h>
#include <kvm.h>
#include <limits.h>
#include <stdlib.h>
@ -57,11 +56,11 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
size = sizeof(fscale);
if (sysctl(fmib, 2, &fscale, &size, NULL, 0) < 0) {
err(1, "fscale sysctl call failed");
CRT_fatalError("fscale sysctl call failed");
}
if ((pageSize = sysconf(_SC_PAGESIZE)) == -1)
err(1, "pagesize sysconf call failed");
CRT_fatalError("pagesize sysconf call failed");
pageSizeKB = pageSize / ONE_K;
for (int i = 0; i <= pl->cpuCount; i++) {
@ -72,7 +71,7 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
opl->kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
if (opl->kd == NULL) {
errx(1, "kvm_open: %s", errbuf);
CRT_fatalError("kvm_openfiles() failed");
}
return pl;
@ -97,7 +96,7 @@ static void OpenBSDProcessList_scanMemoryInfo(ProcessList* pl) {
size_t size_uvmexp = sizeof(uvmexp);
if (sysctl(uvmexp_mib, 2, &uvmexp, &size_uvmexp, NULL, 0) < 0) {
err(1, "uvmexp sysctl call failed");
CRT_fatalError("uvmexp sysctl call failed");
}
pl->totalMem = uvmexp.npages * pageSizeKB;
@ -109,7 +108,7 @@ static void OpenBSDProcessList_scanMemoryInfo(ProcessList* pl) {
size_t size_bcstats = sizeof(bcstats);
if (sysctl(bcache_mib, 3, &bcstats, &size_bcstats, NULL, 0) < 0) {
err(1, "cannot get vfs.bcachestat");
CRT_fatalError("cannot get vfs.bcachestat");
}
pl->cachedMem = bcstats.numbufpages * pageSizeKB;

View File

@ -205,7 +205,7 @@ double Platform_setCPUValues(Meter* this, int cpu) {
percent = isnan(percent) ? 0.0 : CLAMP(percent, 0.0, 100.0);
v[CPU_METER_FREQUENCY] = NAN;
v[CPU_METER_FREQUENCY] = cpuData->frequency;
v[CPU_METER_TEMPERATURE] = NAN;
return percent;

View File

@ -18,17 +18,6 @@ in the source distribution for its full text.
#include <sys/syscall.h>
const ProcessClass SolarisProcess_class = {
.super = {
.extends = Class(Process),
.display = Process_display,
.delete = Process_delete,
.compare = Process_compare
},
.writeField = SolarisProcess_writeField,
.compareByKey = SolarisProcess_compareByKey
};
const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
[0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
[PID] = { .name = "PID", .title = "PID", .description = "Process/thread ID", .flags = 0, .pidColumn = true, },
@ -78,7 +67,7 @@ void Process_delete(Object* cast) {
free(sp);
}
void SolarisProcess_writeField(const Process* this, RichString* str, ProcessField field) {
static void SolarisProcess_writeField(const Process* this, RichString* str, ProcessField field) {
const SolarisProcess* sp = (const SolarisProcess*) this;
char buffer[256]; buffer[255] = '\0';
int attr = CRT_colors[DEFAULT_COLOR];
@ -90,7 +79,7 @@ void SolarisProcess_writeField(const Process* this, RichString* str, ProcessFiel
case TASKID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->taskid); break;
case POOLID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->poolid); break;
case CONTID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->contid); break;
case ZONE: xSnprintf(buffer, n, "%-*s ", ZONENAME_MAX/4, sp->zname); break;
case ZONE: Process_printLeftAlignedField(str, attr, sp->zname ? sp->zname : "global", ZONENAME_MAX/4); return;
case PID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->realpid); break;
case PPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->realppid); break;
case LWPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->lwpid); break;
@ -101,7 +90,7 @@ void SolarisProcess_writeField(const Process* this, RichString* str, ProcessFiel
RichString_appendWide(str, attr, buffer);
}
long SolarisProcess_compareByKey(const void* v1, const void* v2, ProcessField key) {
static int SolarisProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
const SolarisProcess* p1 = (const SolarisProcess*)v1;
const SolarisProcess* p2 = (const SolarisProcess*)v2;
@ -140,3 +129,14 @@ bool Process_isThread(const Process* this) {
return 0;
}
}
const ProcessClass SolarisProcess_class = {
.super = {
.extends = Class(Process),
.display = Process_display,
.delete = Process_delete,
.compare = Process_compare
},
.writeField = SolarisProcess_writeField,
.compareByKey = SolarisProcess_compareByKey
};

View File

@ -40,10 +40,6 @@ Process* SolarisProcess_new(const Settings* settings);
void Process_delete(Object* cast);
void SolarisProcess_writeField(const Process* this, RichString* str, ProcessField field);
long SolarisProcess_compareByKey(const Process* v1, const Process* v2, ProcessField field);
bool Process_isThread(const Process* this);
#endif

View File

@ -14,7 +14,6 @@ in the source distribution for its full text.
#include <stdlib.h>
#include <sys/types.h>
#include <sys/user.h>
#include <err.h>
#include <limits.h>
#include <string.h>
#include <procfs.h>
@ -72,11 +71,11 @@ static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) {
const SolarisProcessList* spl = (SolarisProcessList*) pl;
int cpus = pl->cpuCount;
kstat_t* cpuinfo = NULL;
int kchain = 0;
kstat_named_t* idletime = NULL;
kstat_named_t* intrtime = NULL;
kstat_named_t* krnltime = NULL;
kstat_named_t* usertime = NULL;
kstat_named_t* cpu_freq = NULL;
double idlebuf = 0;
double intrbuf = 0;
double krnlbuf = 0;
@ -94,21 +93,31 @@ static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) {
// Calculate per-CPU statistics first
for (int i = 0; i < cpus; i++) {
if (spl->kd != NULL) {
cpuinfo = kstat_lookup(spl->kd, "cpu", i, "sys");
}
if (cpuinfo != NULL) {
kchain = kstat_read(spl->kd, cpuinfo, NULL);
}
if (kchain != -1 ) {
idletime = kstat_data_lookup(cpuinfo, "cpu_nsec_idle");
intrtime = kstat_data_lookup(cpuinfo, "cpu_nsec_intr");
krnltime = kstat_data_lookup(cpuinfo, "cpu_nsec_kernel");
usertime = kstat_data_lookup(cpuinfo, "cpu_nsec_user");
if ((cpuinfo = kstat_lookup(spl->kd, "cpu", i, "sys")) != NULL) {
if (kstat_read(spl->kd, cpuinfo, NULL) != -1) {
idletime = kstat_data_lookup(cpuinfo, "cpu_nsec_idle");
intrtime = kstat_data_lookup(cpuinfo, "cpu_nsec_intr");
krnltime = kstat_data_lookup(cpuinfo, "cpu_nsec_kernel");
usertime = kstat_data_lookup(cpuinfo, "cpu_nsec_user");
}
}
}
assert( (idletime != NULL) && (intrtime != NULL)
&& (krnltime != NULL) && (usertime != NULL) );
if (pl->settings->showCPUFrequency) {
if (spl->kd != NULL) {
if ((cpuinfo = kstat_lookup(spl->kd, "cpu_info", i, NULL)) != NULL) {
if (kstat_read(spl->kd, cpuinfo, NULL) != -1) {
cpu_freq = kstat_data_lookup(cpuinfo, "current_clock_Hz");
}
}
}
assert( cpu_freq != NULL );
}
CPUData* cpuData = &(spl->cpus[i + arrskip]);
uint64_t totaltime = (idletime->value.ui64 - cpuData->lidle)
@ -128,6 +137,8 @@ static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) {
cpuData->lkrnl = krnltime->value.ui64;
cpuData->lintr = intrtime->value.ui64;
cpuData->lidle = idletime->value.ui64;
// Add frequency in MHz
cpuData->frequency = pl->settings->showCPUFrequency ? (double)cpu_freq->value.ui64 / 1E6 : NAN;
// Accumulate the current percentages into buffers for later average calculation
if (cpus > 1) {
userbuf += cpuData->userPercent;
@ -165,8 +176,8 @@ static inline void SolarisProcessList_scanMemoryInfo(ProcessList* pl) {
// Part 1 - physical memory
if (spl->kd != NULL && meminfo == NULL) {
// Look up the kstat chain just one, it never changes
meminfo = kstat_lookup(spl->kd, "unix", 0, "system_pages");
// Look up the kstat chain just once, it never changes
meminfo = kstat_lookup(spl->kd, "unix", 0, "system_pages");
}
if (meminfo != NULL) {
ksrphyserr = kstat_read(spl->kd, meminfo, NULL);

View File

@ -33,6 +33,7 @@ typedef struct CPUData_ {
double irqPercent;
double idlePercent;
double systemAllPercent;
double frequency;
uint64_t luser;
uint64_t lkrnl;
uint64_t lintr;