summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.editorconfig1
-rw-r--r--.github/workflows/ci.yml29
-rw-r--r--Action.c48
-rw-r--r--Action.h10
-rw-r--r--Affinity.c7
-rw-r--r--Affinity.h15
-rw-r--r--AffinityPanel.h4
-rw-r--r--AvailableColumnsPanel.h2
-rw-r--r--AvailableMetersPanel.c6
-rw-r--r--AvailableMetersPanel.h2
-rw-r--r--BatteryMeter.c2
-rw-r--r--CPUMeter.c141
-rw-r--r--CPUMeter.h8
-rw-r--r--CRT.c49
-rw-r--r--CRT.h33
-rw-r--r--CategoriesPanel.h4
-rw-r--r--CheckItem.c4
-rw-r--r--CheckItem.h8
-rw-r--r--ColorsPanel.c2
-rw-r--r--ColorsPanel.h2
-rw-r--r--ColumnsPanel.c4
-rw-r--r--ColumnsPanel.h6
-rw-r--r--DisplayOptionsPanel.c5
-rw-r--r--DisplayOptionsPanel.h2
-rw-r--r--EnvScreen.h8
-rw-r--r--FunctionBar.c2
-rw-r--r--FunctionBar.h14
-rw-r--r--Hashtable.c8
-rw-r--r--Hashtable.h12
-rw-r--r--Header.c12
-rw-r--r--Header.h26
-rw-r--r--IncSet.c44
-rw-r--r--IncSet.h20
-rw-r--r--InfoScreen.c10
-rw-r--r--InfoScreen.h12
-rw-r--r--ListItem.h8
-rw-r--r--MainPanel.c14
-rw-r--r--MainPanel.h22
-rw-r--r--Makefile.am4
-rw-r--r--MemoryMeter.c2
-rw-r--r--Meter.c19
-rw-r--r--Meter.h14
-rw-r--r--MetersPanel.c2
-rw-r--r--MetersPanel.h4
-rw-r--r--Object.c8
-rw-r--r--Object.h10
-rw-r--r--OpenFilesScreen.c1
-rw-r--r--OpenFilesScreen.h8
-rw-r--r--Panel.c4
-rw-r--r--Panel.h46
-rw-r--r--Process.c51
-rw-r--r--Process.h36
-rw-r--r--ProcessList.c10
-rw-r--r--ProcessList.h28
-rw-r--r--README54
-rw-r--r--RichString.c2
-rw-r--r--RichString.h18
-rw-r--r--ScreenManager.c24
-rw-r--r--ScreenManager.h12
-rw-r--r--Settings.c35
-rw-r--r--Settings.h14
-rw-r--r--SignalsPanel.h2
-rw-r--r--StringUtils.c7
-rw-r--r--StringUtils.h12
-rw-r--r--TasksMeter.c8
-rw-r--r--TraceScreen.c2
-rw-r--r--TraceScreen.h12
-rw-r--r--UsersTable.h6
-rw-r--r--Vector.c4
-rw-r--r--Vector.h26
-rw-r--r--XAlloc.h10
-rw-r--r--configure.ac9
-rw-r--r--darwin/DarwinProcess.c12
-rw-r--r--darwin/Platform.c4
-rw-r--r--dragonflybsd/DragonFlyBSDProcess.c4
-rw-r--r--dragonflybsd/DragonFlyBSDProcessList.c2
-rw-r--r--dragonflybsd/Platform.c3
-rw-r--r--freebsd/FreeBSDProcess.c4
-rw-r--r--freebsd/FreeBSDProcessList.c63
-rw-r--r--freebsd/Platform.c3
-rw-r--r--htop.1.in91
-rw-r--r--htop.c54
-rw-r--r--htop.desktop2
-rw-r--r--htop.h2
-rw-r--r--linux/Battery.c20
-rw-r--r--linux/Battery.h2
-rw-r--r--linux/IOPriority.c2
-rw-r--r--linux/IOPriority.h2
-rw-r--r--linux/IOPriorityPanel.h4
-rw-r--r--linux/LinuxCRT.h2
-rw-r--r--linux/LinuxProcess.c37
-rw-r--r--linux/LinuxProcess.h31
-rw-r--r--linux/LinuxProcessList.c204
-rw-r--r--linux/LinuxProcessList.h22
-rw-r--r--linux/Platform.c32
-rw-r--r--linux/Platform.h21
-rw-r--r--linux/PressureStallMeter.c133
-rw-r--r--linux/PressureStallMeter.h25
-rw-r--r--openbsd/Battery.c7
-rw-r--r--openbsd/Battery.h1
-rw-r--r--openbsd/OpenBSDProcess.c2
-rw-r--r--openbsd/OpenBSDProcessList.c142
-rw-r--r--openbsd/OpenBSDProcessList.h18
-rw-r--r--openbsd/Platform.c107
-rw-r--r--openbsd/Platform.h15
-rwxr-xr-xscripts/MakeHeader.py4
-rw-r--r--solaris/Platform.c17
-rw-r--r--solaris/Platform.h2
-rw-r--r--solaris/SolarisProcess.c2
-rw-r--r--solaris/SolarisProcessList.c30
-rw-r--r--solaris/SolarisProcessList.h4
-rw-r--r--unsupported/Platform.c7
-rw-r--r--unsupported/UnsupportedProcessList.c2
113 files changed, 1522 insertions, 729 deletions
diff --git a/.editorconfig b/.editorconfig
index 18807892..dd881dd0 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -14,3 +14,4 @@ charset = utf-8
[*.{c,h}]
indent_style = space
indent_size = 3
+trim_trailing_whitespace = true
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000..74d0ece8
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,29 @@
+name: CI
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ build-ubuntu-latest:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Build
+ run: |
+ sudo apt-get install libncursesw5-dev
+ ./autogen.sh
+ ./configure
+ make
+
+# build-macos-latest:
+# runs-on: macos-latest
+# steps:
+# - uses: actions/checkout@v2
+# - name: make
+# run: |
+# ./autogen.sh
+# ./configure
+# make
diff --git a/Action.c b/Action.c
index 9a7c3c56..825e743d 100644
--- a/Action.c
+++ b/Action.c
@@ -62,11 +62,11 @@ typedef struct State_ {
}*/
-Object* Action_pickFromVector(State* st, Panel* list, int x) {
+Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess) {
Panel* panel = st->panel;
Header* header = st->header;
Settings* settings = st->settings;
-
+
int y = panel->y;
ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, false);
scr->allowFocusChange = false;
@@ -75,8 +75,8 @@ Object* Action_pickFromVector(State* st, Panel* list, int x) {
Panel* panelFocus;
int ch;
bool unfollow = false;
- int pid = MainPanel_selectedPid((MainPanel*)panel);
- if (header->pl->following == -1) {
+ int pid = followProcess ? MainPanel_selectedPid((MainPanel*)panel) : -1;
+ if (followProcess && header->pl->following == -1) {
header->pl->following = pid;
unfollow = true;
}
@@ -88,11 +88,16 @@ Object* Action_pickFromVector(State* st, Panel* list, int x) {
Panel_move(panel, 0, y);
Panel_resize(panel, COLS, LINES-y-1);
if (panelFocus == list && ch == 13) {
- Process* selected = (Process*)Panel_getSelected(panel);
- if (selected && selected->pid == pid)
+ if (followProcess) {
+ Process* selected = (Process*)Panel_getSelected(panel);
+ if (selected && selected->pid == pid)
+ return Panel_getSelected(list);
+ else
+ beep();
+ } else {
return Panel_getSelected(list);
- else
- beep();
+ }
+
}
return NULL;
}
@@ -189,7 +194,7 @@ static Htop_Reaction sortBy(State* st) {
Panel_setSelected(sortPanel, i);
free(name);
}
- ListItem* field = (ListItem*) Action_pickFromVector(st, sortPanel, 15);
+ ListItem* field = (ListItem*) Action_pickFromVector(st, sortPanel, 15, false);
if (field) {
reaction |= Action_setSortKey(st->settings, field->key);
}
@@ -248,10 +253,21 @@ static Htop_Reaction actionIncFilter(State* st) {
}
static Htop_Reaction actionIncSearch(State* st) {
+ IncSet_reset(((MainPanel*)st->panel)->inc, INC_SEARCH);
IncSet_activate(((MainPanel*)st->panel)->inc, INC_SEARCH, st->panel);
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;
@@ -297,7 +313,7 @@ static Htop_Reaction actionSetAffinity(State* st) {
return HTOP_OK;
#if (HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY)
Panel* panel = st->panel;
-
+
Process* p = (Process*) Panel_getSelected(panel);
if (!p) return HTOP_OK;
Affinity* affinity = Affinity_get(p, st->pl);
@@ -305,7 +321,7 @@ static Htop_Reaction actionSetAffinity(State* st) {
Panel* affinityPanel = AffinityPanel_new(st->pl, affinity);
Affinity_delete(affinity);
- void* set = Action_pickFromVector(st, affinityPanel, 15);
+ void* set = Action_pickFromVector(st, affinityPanel, 15, true);
if (set) {
Affinity* affinity = AffinityPanel_getAffinity(affinityPanel, st->pl);
bool ok = MainPanel_foreachProcess((MainPanel*)panel, (MainPanel_ForeachProcessFn) Affinity_set, (Arg){ .v = affinity }, NULL);
@@ -319,7 +335,7 @@ static Htop_Reaction actionSetAffinity(State* st) {
static Htop_Reaction actionKill(State* st) {
Panel* signalsPanel = (Panel*) SignalsPanel_new();
- ListItem* sgn = (ListItem*) Action_pickFromVector(st, signalsPanel, 15);
+ ListItem* sgn = (ListItem*) Action_pickFromVector(st, signalsPanel, 15, true);
if (sgn) {
if (sgn->key != 0) {
Panel_setHeader(st->panel, "Sending...");
@@ -340,7 +356,7 @@ static Htop_Reaction actionFilterByUser(State* st) {
Vector_insertionSort(usersPanel->items);
ListItem* allUsers = ListItem_new("All users", -1);
Panel_insert(usersPanel, 0, (Object*) allUsers);
- ListItem* picked = (ListItem*) Action_pickFromVector(st, usersPanel, 20);
+ ListItem* picked = (ListItem*) Action_pickFromVector(st, usersPanel, 20, false);
if (picked) {
if (picked == allUsers) {
st->pl->userId = -1;
@@ -463,7 +479,7 @@ static Htop_Reaction actionHelp(State* st) {
if (settings->detailedCPUTime) {
addattrstr(CRT_colors[CPU_NICE_TEXT], "low"); addstr("/");
addattrstr(CRT_colors[CPU_NORMAL], "normal"); addstr("/");
- addattrstr(CRT_colors[CPU_KERNEL], "kernel"); addstr("/");
+ addattrstr(CRT_colors[CPU_SYSTEM], "kernel"); addstr("/");
addattrstr(CRT_colors[CPU_IRQ], "irq"); addstr("/");
addattrstr(CRT_colors[CPU_SOFTIRQ], "soft-irq"); addstr("/");
addattrstr(CRT_colors[CPU_STEAL], "steal"); addstr("/");
@@ -473,7 +489,7 @@ static Htop_Reaction actionHelp(State* st) {
} else {
addattrstr(CRT_colors[CPU_NICE_TEXT], "low-priority"); addstr("/");
addattrstr(CRT_colors[CPU_NORMAL], "normal"); addstr("/");
- addattrstr(CRT_colors[CPU_KERNEL], "kernel"); addstr("/");
+ addattrstr(CRT_colors[CPU_SYSTEM], "kernel"); addstr("/");
addattrstr(CRT_colors[CPU_GUEST], "virtualiz");
addattrstr(CRT_colors[BAR_SHADOW], " used%");
}
@@ -559,6 +575,8 @@ void Action_setBindings(Htop_Action* keys) {
keys['\\'] = actionIncFilter;
keys[KEY_F(3)] = actionIncSearch;
keys['/'] = actionIncSearch;
+ keys['n'] = actionIncNext;
+ keys['N'] = actionIncPrev;
keys[']'] = actionHigherPriority;
keys[KEY_F(7)] = actionHigherPriority;
diff --git a/Action.h b/Action.h
index 1dfdcb47..c49e9dac 100644
--- a/Action.h
+++ b/Action.h
@@ -39,20 +39,20 @@ typedef struct State_ {
} State;
-Object* Action_pickFromVector(State* st, Panel* list, int x);
+extern Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess);
// ----------------------------------------
-bool Action_setUserOnly(const char* userName, uid_t* userId);
+extern bool Action_setUserOnly(const char* userName, uid_t* userId);
-Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey);
+extern Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey);
// ----------------------------------------
-Htop_Reaction Action_follow(State* st);
+extern Htop_Reaction Action_follow(State* st);
-void Action_setBindings(Htop_Action* keys);
+extern void Action_setBindings(Htop_Action* keys);
#endif
diff --git a/Affinity.c b/Affinity.c
index c928fec1..b6eafcee 100644
--- a/Affinity.c
+++ b/Affinity.c
@@ -1,6 +1,7 @@
/*
htop - Affinity.c
(C) 2004-2011 Hisham H. Muhammad
+(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
@@ -79,7 +80,8 @@ Affinity* Affinity_get(Process* proc, ProcessList* pl) {
return affinity;
}
-bool Affinity_set(Process* proc, Affinity* this) {
+bool Affinity_set(Process* proc, Arg arg) {
+ Affinity *this = arg.v;
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
for (int i = 0; i < this->used; i++) {
hwloc_bitmap_set(cpuset, this->cpus[i]);
@@ -103,7 +105,8 @@ Affinity* Affinity_get(Process* proc, ProcessList* pl) {
return affinity;
}
-bool Affinity_set(Process* proc, Affinity* this) {
+bool Affinity_set(Process* proc, Arg arg) {
+ Affinity *this = arg.v;
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
for (int i = 0; i < this->used; i++) {
diff --git a/Affinity.h b/Affinity.h
index fd2c599e..3c716034 100644
--- a/Affinity.h
+++ b/Affinity.h
@@ -5,6 +5,7 @@
/*
htop - Affinity.h
(C) 2004-2011 Hisham H. Muhammad
+(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
@@ -29,23 +30,23 @@ typedef struct Affinity_ {
} Affinity;
-Affinity* Affinity_new(ProcessList* pl);
+extern Affinity* Affinity_new(ProcessList* pl);
-void Affinity_delete(Affinity* this);
+extern void Affinity_delete(Affinity* this);
-void Affinity_add(Affinity* this, int id);
+extern void Affinity_add(Affinity* this, int id);
#ifdef HAVE_LIBHWLOC
-Affinity* Affinity_get(Process* proc, ProcessList* pl);
+extern Affinity* Affinity_get(Process* proc, ProcessList* pl);
-bool Affinity_set(Process* proc, Affinity* this);
+extern bool Affinity_set(Process* proc, Arg arg);
#elif HAVE_LINUX_AFFINITY
-Affinity* Affinity_get(Process* proc, ProcessList* pl);
+extern Affinity* Affinity_get(Process* proc, ProcessList* pl);
-bool Affinity_set(Process* proc, Affinity* this);
+extern bool Affinity_set(Process* proc, Arg arg);
#endif
diff --git a/AffinityPanel.h b/AffinityPanel.h
index 2b6059b0..3a9c7807 100644
--- a/AffinityPanel.h
+++ b/AffinityPanel.h
@@ -16,8 +16,8 @@ in the source distribution for its full text.
extern PanelClass AffinityPanel_class;
-Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity);
+extern Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity);
-Affinity* AffinityPanel_getAffinity(Panel* this, ProcessList* pl);
+extern Affinity* AffinityPanel_getAffinity(Panel* this, ProcessList* pl);
#endif
diff --git a/AvailableColumnsPanel.h b/AvailableColumnsPanel.h
index 5a8371dd..2d6daf4b 100644
--- a/AvailableColumnsPanel.h
+++ b/AvailableColumnsPanel.h
@@ -19,6 +19,6 @@ typedef struct AvailableColumnsPanel_ {
extern PanelClass AvailableColumnsPanel_class;
-AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns);
+extern AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns);
#endif
diff --git a/AvailableMetersPanel.c b/AvailableMetersPanel.c
index ddb55367..5dac10b9 100644
--- a/AvailableMetersPanel.c
+++ b/AvailableMetersPanel.c
@@ -52,7 +52,7 @@ static inline void AvailableMetersPanel_addMeter(Header* header, Panel* panel, M
static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
AvailableMetersPanel* this = (AvailableMetersPanel*) super;
Header* header = this->header;
-
+
ListItem* selected = (ListItem*) Panel_getSelected(super);
int param = selected->key & 0xff;
int type = selected->key >> 16;
@@ -104,7 +104,7 @@ AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* heade
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_newEnterEsc("Add ", "Done ");
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
-
+
this->settings = settings;
this->header = header;
this->leftPanel = leftMeters;
@@ -127,7 +127,7 @@ AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* heade
Panel_add(super, (Object*) ListItem_new("CPU average", 0));
for (int i = 1; i <= cpus; i++) {
char buffer[50];
- xSnprintf(buffer, 50, "%s %d", type->uiName, i);
+ xSnprintf(buffer, 50, "%s %d", type->uiName, Settings_cpuId(this->settings, i - 1));
Panel_add(super, (Object*) ListItem_new(buffer, i));
}
} else {
diff --git a/AvailableMetersPanel.h b/AvailableMetersPanel.h
index e9b949b0..00e0f596 100644
--- a/AvailableMetersPanel.h
+++ b/AvailableMetersPanel.h
@@ -27,6 +27,6 @@ typedef struct AvailableMetersPanel_ {
extern PanelClass AvailableMetersPanel_class;
-AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, ProcessList* pl);
+extern AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, ProcessList* pl);
#endif
diff --git a/BatteryMeter.c b/BatteryMeter.c
index 214248e2..716b7750 100644
--- a/BatteryMeter.c
+++ b/BatteryMeter.c
@@ -35,7 +35,7 @@ int BatteryMeter_attributes[] = {
static void BatteryMeter_updateValues(Meter * this, char *buffer, int len) {
ACPresence isOnAC;
double percent;
-
+
Battery_getData(&percent, &isOnAC);
if (percent == -1) {
diff --git a/CPUMeter.c b/CPUMeter.c
index de5490df..6131a09d 100644
--- a/CPUMeter.c
+++ b/CPUMeter.c
@@ -28,13 +28,14 @@ typedef enum {
CPU_METER_STEAL = 5,
CPU_METER_GUEST = 6,
CPU_METER_IOWAIT = 7,
- CPU_METER_ITEMCOUNT = 8, // number of entries in this enum
+ CPU_METER_FREQUENCY = 8,
+ CPU_METER_ITEMCOUNT = 9, // number of entries in this enum
} CPUMeterValues;
}*/
int CPUMeter_attributes[] = {
- CPU_NICE, CPU_NORMAL, CPU_KERNEL, CPU_IRQ, CPU_SOFTIRQ, CPU_STEAL, CPU_GUEST, CPU_IOWAIT
+ CPU_NICE, CPU_NORMAL, CPU_SYSTEM, CPU_IRQ, CPU_SOFTIRQ, CPU_STEAL, CPU_GUEST, CPU_IOWAIT
};
#ifndef MIN
@@ -63,7 +64,30 @@ static void CPUMeter_updateValues(Meter* this, char* buffer, int size) {
}
memset(this->values, 0, sizeof(double) * CPU_METER_ITEMCOUNT);
double percent = Platform_setCPUValues(this, cpu);
- xSnprintf(buffer, size, "%5.1f%%", percent);
+ if (this->pl->settings->showCPUFrequency) {
+ /* Initial frequency is in MHz. Emit it as GHz if it's larger than 1000MHz */
+ double cpuFrequency = this->values[CPU_METER_FREQUENCY];
+ char unit = 'M';
+ char cpuFrequencyBuffer[16];
+ if (cpuFrequency < 0) {
+ xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A");
+ } else {
+ if (cpuFrequency > 1000) {
+ cpuFrequency /= 1000;
+ unit = 'G';
+ }
+ xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%.3f%cHz", cpuFrequency, unit);
+ }
+ if (this->pl->settings->showCPUUsage) {
+ xSnprintf(buffer, size, "%5.1f%% %s", percent, cpuFrequencyBuffer);
+ } else {
+ xSnprintf(buffer, size, "%s", cpuFrequencyBuffer);
+ }
+ } else if (this->pl->settings->showCPUUsage) {
+ xSnprintf(buffer, size, "%5.1f%%", percent);
+ } else if (size > 0) {
+ buffer[0] = '\0';
+ }
}
static void CPUMeter_display(Object* cast, RichString* out) {
@@ -80,7 +104,7 @@ static void CPUMeter_display(Object* cast, RichString* out) {
if (this->pl->settings->detailedCPUTime) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
RichString_append(out, CRT_colors[METER_TEXT], "sy:");
- RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
+ RichString_append(out, CRT_colors[CPU_SYSTEM], buffer);
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
RichString_append(out, CRT_colors[METER_TEXT], "ni:");
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer);
@@ -106,7 +130,7 @@ static void CPUMeter_display(Object* cast, RichString* out) {
} else {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
RichString_append(out, CRT_colors[METER_TEXT], "sys:");
- RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
+ RichString_append(out, CRT_colors[CPU_SYSTEM], buffer);
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
RichString_append(out, CRT_colors[METER_TEXT], "low:");
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer);
@@ -137,6 +161,15 @@ static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) {
}
}
+static int MapClassnameToColumncount(Meter* this){
+ if (strchr(Meter_name(this), '4'))
+ return 4;
+ else if (strchr(Meter_name(this), '2'))
+ return 2;
+ else
+ return 1;
+}
+
static void AllCPUsMeter_init(Meter* this) {
int cpus = this->pl->cpuCount;
if (!this->drawData)
@@ -152,10 +185,8 @@ static void AllCPUsMeter_init(Meter* this) {
if (this->mode == 0)
this->mode = BAR_METERMODE;
int h = Meter_modes[this->mode]->h;
- if (strchr(Meter_name(this), '2'))
- this->h = h * ((count+1) / 2);
- else
- this->h = h * count;
+ int ncol = MapClassnameToColumncount(this);
+ this->h = h * ((count + ncol - 1)/ ncol);
}
static void AllCPUsMeter_done(Meter* this) {
@@ -175,10 +206,8 @@ static void AllCPUsMeter_updateMode(Meter* this, int mode) {
for (int i = 0; i < count; i++) {
Meter_setMode(meters[i], mode);
}
- if (strchr(Meter_name(this), '2'))
- this->h = h * ((count+1) / 2);
- else
- this->h = h * count;
+ int ncol = MapClassnameToColumncount(this);
+ this->h = h * ((count + ncol - 1)/ ncol);
}
static void DualColCPUsMeter_draw(Meter* this, int x, int y, int w) {
@@ -209,6 +238,22 @@ static void SingleColCPUsMeter_draw(Meter* this, int x, int y, int w) {
}
}
+static void MultiColCPUsMeter_draw(Meter* this, int x, int y, int w){
+ Meter** meters = (Meter**) this->drawData;
+ int start, count;
+ AllCPUsMeter_getRange(this, &start, &count);
+ int ncol = MapClassnameToColumncount(this);
+ int colwidth = (w-ncol)/ncol + 1;
+ int diff = (w - (colwidth * ncol));
+ int nrows = (count + ncol - 1) / ncol;
+ for (int i = 0; i < count; i++){
+ int d = (i/nrows) > diff ? diff : (i / nrows) ; // dynamic spacer
+ int xpos = x + ((i / nrows) * colwidth) + d;
+ int ypos = y + ((i % nrows) * meters[0]->h);
+ meters[i]->draw(meters[i], xpos, ypos, colwidth);
+ }
+}
+
MeterClass CPUMeter_class = {
.super = {
.extends = Class(Meter),
@@ -219,7 +264,7 @@ MeterClass CPUMeter_class = {
.defaultMode = BAR_METERMODE,
.maxItems = CPU_METER_ITEMCOUNT,
.total = 100.0,
- .attributes = CPUMeter_attributes,
+ .attributes = CPUMeter_attributes,
.name = "CPU",
.uiName = "CPU",
.caption = "CPU",
@@ -234,7 +279,7 @@ MeterClass AllCPUsMeter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
- .attributes = CPUMeter_attributes,
+ .attributes = CPUMeter_attributes,
.name = "AllCPUs",
.uiName = "CPUs (1/1)",
.description = "CPUs (1/1): all CPUs",
@@ -253,7 +298,7 @@ MeterClass AllCPUs2Meter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
- .attributes = CPUMeter_attributes,
+ .attributes = CPUMeter_attributes,
.name = "AllCPUs2",
.uiName = "CPUs (1&2/2)",
.description = "CPUs (1&2/2): all CPUs in 2 shorter columns",
@@ -272,7 +317,7 @@ MeterClass LeftCPUsMeter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
- .attributes = CPUMeter_attributes,
+ .attributes = CPUMeter_attributes,
.name = "LeftCPUs",
.uiName = "CPUs (1/2)",
.description = "CPUs (1/2): first half of list",
@@ -291,7 +336,7 @@ MeterClass RightCPUsMeter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
- .attributes = CPUMeter_attributes,
+ .attributes = CPUMeter_attributes,
.name = "RightCPUs",
.uiName = "CPUs (2/2)",
.description = "CPUs (2/2): second half of list",
@@ -310,7 +355,7 @@ MeterClass LeftCPUs2Meter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
- .attributes = CPUMeter_attributes,
+ .attributes = CPUMeter_attributes,
.name = "LeftCPUs2",
.uiName = "CPUs (1&2/4)",
.description = "CPUs (1&2/4): first half in 2 shorter columns",
@@ -329,7 +374,7 @@ MeterClass RightCPUs2Meter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
- .attributes = CPUMeter_attributes,
+ .attributes = CPUMeter_attributes,
.name = "RightCPUs2",
.uiName = "CPUs (3&4/4)",
.description = "CPUs (3&4/4): second half in 2 shorter columns",
@@ -340,3 +385,59 @@ MeterClass RightCPUs2Meter_class = {
.done = AllCPUsMeter_done
};
+MeterClass AllCPUs4Meter_class = {
+ .super = {
+ .extends = Class(Meter),
+ .delete = Meter_delete,
+ .display = CPUMeter_display
+ },
+ .defaultMode = CUSTOM_METERMODE,
+ .total = 100.0,
+ .attributes = CPUMeter_attributes,
+ .name = "AllCPUs4",
+ .uiName = "CPUs (1&2&3&4/4)",
+ .description = "CPUs (1&2&3&4/4): all CPUs in 4 shorter columns",
+ .caption = "CPU",
+ .draw = MultiColCPUsMeter_draw,
+ .init = AllCPUsMeter_init,
+ .updateMode = AllCPUsMeter_updateMode,
+ .done = AllCPUsMeter_done
+};
+
+MeterClass LeftCPUs4Meter_class = {
+ .super = {
+ .extends = Class(Meter),
+ .delete = Meter_delete,
+ .display = CPUMeter_display
+ },
+ .defaultMode = CUSTOM_METERMODE,
+ .total = 100.0,
+ .attributes = CPUMeter_attributes,
+ .name = "LeftCPUs4",
+ .uiName = "CPUs (1-4/8)",
+ .description = "CPUs (1-4/8): first half in 4 shorter columns",
+ .caption = "CPU",
+ .draw = MultiColCPUsMeter_draw,
+ .init = AllCPUsMeter_init,
+ .updateMode = AllCPUsMeter_updateMode,
+ .done = AllCPUsMeter_done
+};
+
+MeterClass RightCPUs4Meter_class = {
+ .super = {
+ .extends = Class(Meter),
+ .delete = Meter_delete,
+ .display = CPUMeter_display
+ },
+ .defaultMode = CUSTOM_METERMODE,
+ .total = 100.0,
+ .attributes = CPUMeter_attributes,
+ .name = "RightCPUs4",
+ .uiName = "CPUs (5-8/8)",
+ .description = "CPUs (5-8/8): second half in 4 shorter columns",
+ .caption = "CPU",
+ .draw = MultiColCPUsMeter_draw,
+ .init = AllCPUsMeter_init,
+ .updateMode = AllCPUsMeter_updateMode,
+ .done = AllCPUsMeter_done
+};
diff --git a/CPUMeter.h b/CPUMeter.h
index 2f163968..890e5dba 100644
--- a/CPUMeter.h
+++ b/CPUMeter.h
@@ -20,7 +20,8 @@ typedef enum {
CPU_METER_STEAL = 5,
CPU_METER_GUEST = 6,
CPU_METER_IOWAIT = 7,
- CPU_METER_ITEMCOUNT = 8, // number of entries in this enum
+ CPU_METER_FREQUENCY = 8,
+ CPU_METER_ITEMCOUNT = 9, // number of entries in this enum
} CPUMeterValues;
@@ -47,5 +48,10 @@ extern MeterClass LeftCPUs2Meter_class;
extern MeterClass RightCPUs2Meter_class;
+extern MeterClass AllCPUs4Meter_class;
+
+extern MeterClass LeftCPUs4Meter_class;
+
+extern MeterClass RightCPUs4Meter_class;
#endif
diff --git a/CRT.c b/CRT.c
index cb36b6c0..35b285f7 100644
--- a/CRT.c
+++ b/CRT.c
@@ -122,12 +122,15 @@ typedef enum ColorElements_ {
CPU_NICE,
CPU_NICE_TEXT,
CPU_NORMAL,
- CPU_KERNEL,
+ CPU_SYSTEM,
CPU_IOWAIT,
CPU_IRQ,
CPU_SOFTIRQ,
CPU_STEAL,
CPU_GUEST,
+ PRESSURE_STALL_TEN,
+ PRESSURE_STALL_SIXTY,
+ PRESSURE_STALL_THREEHUNDRED,
ZFS_MFU,
ZFS_MRU,
ZFS_ANON,
@@ -138,9 +141,9 @@ typedef enum ColorElements_ {
LAST_COLORELEMENT
} ColorElements;
-void CRT_fatalError(const char* note) __attribute__ ((noreturn));
+extern void CRT_fatalError(const char* note) __attribute__ ((noreturn));
-void CRT_handleSIGSEGV(int sgn);
+extern void CRT_handleSIGSEGV(int sgn);
#define KEY_ALT(x) (KEY_F(64 - 26) + (x - 'A'))
@@ -233,12 +236,15 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[CPU_NICE] = ColorPair(Blue,Black),
[CPU_NICE_TEXT] = A_BOLD | ColorPair(Blue,Black),
[CPU_NORMAL] = ColorPair(Green,Black),
- [CPU_KERNEL] = ColorPair(Red,Black),
- [CPU_IOWAIT] = A_BOLD | ColorPair(Black, Black),
+ [CPU_SYSTEM] = ColorPair(Red,Black),
+ [CPU_IOWAIT] = A_BOLD | ColorPairGrayBlack,
[CPU_IRQ] = ColorPair(Yellow,Black),
[CPU_SOFTIRQ] = ColorPair(Magenta,Black),
[CPU_STEAL] = ColorPair(Cyan,Black),
[CPU_GUEST] = ColorPair(Cyan,Black),
+ [PRESSURE_STALL_THREEHUNDRED] = ColorPair(Cyan,Black),
+ [PRESSURE_STALL_SIXTY] = A_BOLD | ColorPair(Cyan,Black),
+ [PRESSURE_STALL_TEN] = A_BOLD | ColorPair(White,Black),
[ZFS_MFU] = ColorPair(Blue,Black),
[ZFS_MRU] = ColorPair(Yellow,Black),
[ZFS_ANON] = ColorPair(Magenta,Black),
@@ -299,12 +305,15 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[CPU_NICE] = A_NORMAL,
[CPU_NICE_TEXT] = A_NORMAL,
[CPU_NORMAL] = A_BOLD,
- [CPU_KERNEL] = A_BOLD,
+ [CPU_SYSTEM] = A_BOLD,
[CPU_IOWAIT] = A_NORMAL,
[CPU_IRQ] = A_BOLD,
[CPU_SOFTIRQ] = A_BOLD,
[CPU_STEAL] = A_REVERSE,
[CPU_GUEST] = A_REVERSE,
+ [PRESSURE_STALL_THREEHUNDRED] = A_DIM,
+ [PRESSURE_STALL_SIXTY] = A_NORMAL,
+ [PRESSURE_STALL_TEN] = A_BOLD,
[ZFS_MFU] = A_NORMAL,
[ZFS_MRU] = A_NORMAL,
[ZFS_ANON] = A_DIM,
@@ -365,12 +374,15 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[CPU_NICE] = ColorPair(Cyan,White),
[CPU_NICE_TEXT] = ColorPair(Cyan,White),
[CPU_NORMAL] = ColorPair(Green,White),
- [CPU_KERNEL] = ColorPair(Red,White),
- [CPU_IOWAIT] = A_BOLD | ColorPair(Black, White),
+ [CPU_SYSTEM] = ColorPair(Red,White),
+ [CPU_IOWAIT] = A_BOLD | ColorPair(Black,White),
[CPU_IRQ] = ColorPair(Blue,White),
[CPU_SOFTIRQ] = ColorPair(Blue,White),
[CPU_STEAL] = ColorPair(Cyan,White),
[CPU_GUEST] = ColorPair(Cyan,White),
+ [PRESSURE_STALL_THREEHUNDRED] = ColorPair(Black,White),
+ [PRESSURE_STALL_SIXTY] = ColorPair(Black,White),
+ [PRESSURE_STALL_TEN] = ColorPair(Black,White),
[ZFS_MFU] = ColorPair(Cyan,White),
[ZFS_MRU] = ColorPair(Yellow,White),
[ZFS_ANON] = ColorPair(Magenta,White),
@@ -431,12 +443,15 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[CPU_NICE] = ColorPair(Cyan,Black),
[CPU_NICE_TEXT] = ColorPair(Cyan,Black),
[CPU_NORMAL] = ColorPair(Green,Black),
- [CPU_KERNEL] = ColorPair(Red,Black),
- [CPU_IOWAIT] = A_BOLD | ColorPair(Black, Black),
+ [CPU_SYSTEM] = ColorPair(Red,Black),
+ [CPU_IOWAIT] = A_BOLD | ColorPair(Black,Black),
[CPU_IRQ] = A_BOLD | ColorPair(Blue,Black),
[CPU_SOFTIRQ] = 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),
@@ -497,12 +512,15 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[CPU_NICE] = A_BOLD | ColorPair(Cyan,Blue),
[CPU_NICE_TEXT] = A_BOLD | ColorPair(Cyan,Blue),
[CPU_NORMAL] = A_BOLD | ColorPair(Green,Blue),
- [CPU_KERNEL] = A_BOLD | ColorPair(Red,Blue),
+ [CPU_SYSTEM] = A_BOLD | ColorPair(Red,Blue),
[CPU_IOWAIT] = A_BOLD | ColorPair(Blue,Blue),
[CPU_IRQ] = A_BOLD | ColorPair(Black,Blue),
[CPU_SOFTIRQ] = ColorPair(Black,Blue),
[CPU_STEAL] = ColorPair(White,Blue),
[CPU_GUEST] = ColorPair(White,Blue),
+ [PRESSURE_STALL_THREEHUNDRED] = A_BOLD | ColorPair(Black,Blue),
+ [PRESSURE_STALL_SIXTY] = A_NORMAL | ColorPair(White,Blue),
+ [PRESSURE_STALL_TEN] = A_BOLD | ColorPair(White,Blue),
[ZFS_MFU] = A_BOLD | ColorPair(White,Blue),
[ZFS_MRU] = A_BOLD | ColorPair(Yellow,Blue),
[ZFS_ANON] = A_BOLD | ColorPair(Magenta,Blue),
@@ -563,12 +581,15 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[CPU_NICE] = ColorPair(Blue,Black),
[CPU_NICE_TEXT] = A_BOLD | ColorPair(Blue,Black),
[CPU_NORMAL] = ColorPair(Green,Black),
- [CPU_KERNEL] = ColorPair(Red,Black),
+ [CPU_SYSTEM] = ColorPair(Red,Black),
[CPU_IOWAIT] = ColorPair(Yellow,Black),
[CPU_IRQ] = A_BOLD | ColorPair(Blue,Black),
[CPU_SOFTIRQ] = ColorPair(Blue,Black),
[CPU_STEAL] = ColorPair(Cyan,Black),
[CPU_GUEST] = ColorPair(Cyan,Black),
+ [PRESSURE_STALL_THREEHUNDRED] = ColorPair(Green,Black),
+ [PRESSURE_STALL_SIXTY] = ColorPair(Green,Black),
+ [PRESSURE_STALL_TEN] = A_BOLD | ColorPair(Green,Black),
[ZFS_MFU] = ColorPair(Blue,Black),
[ZFS_MRU] = ColorPair(Yellow,Black),
[ZFS_ANON] = ColorPair(Magenta,Black),
@@ -653,12 +674,12 @@ void CRT_init(int delay, int colorScheme) {
}
CRT_colors = CRT_colorSchemes[colorScheme];
CRT_colorScheme = colorScheme;
-
+
for (int i = 0; i < LAST_COLORELEMENT; i++) {
unsigned int color = CRT_colorSchemes[COLORSCHEME_DEFAULT][i];
CRT_colorSchemes[COLORSCHEME_BROKENGRAY][i] = color == (A_BOLD | ColorPairGrayBlack) ? ColorPair(White,Black) : color;
}
-
+
halfdelay(CRT_delay);
nonl();
intrflush(stdscr, false);
diff --git a/CRT.h b/CRT.h
index d9eba556..80022f70 100644
--- a/CRT.h
+++ b/CRT.h
@@ -110,12 +110,15 @@ typedef enum ColorElements_ {
CPU_NICE,
CPU_NICE_TEXT,
CPU_NORMAL,
- CPU_KERNEL,
+ CPU_SYSTEM,
CPU_IOWAIT,
CPU_IRQ,
CPU_SOFTIRQ,
CPU_STEAL,
CPU_GUEST,
+ PRESSURE_STALL_TEN,
+ PRESSURE_STALL_SIXTY,
+ PRESSURE_STALL_THREEHUNDRED,
ZFS_MFU,
ZFS_MRU,
ZFS_ANON,
@@ -126,9 +129,9 @@ typedef enum ColorElements_ {
LAST_COLORELEMENT
} ColorElements;
-void CRT_fatalError(const char* note) __attribute__ ((noreturn));
+extern void CRT_fatalError(const char* note) __attribute__ ((noreturn));
-void CRT_handleSIGSEGV(int sgn);
+extern void CRT_handleSIGSEGV(int sgn);
#define KEY_ALT(x) (KEY_F(64 - 26) + (x - 'A'))
@@ -147,7 +150,7 @@ extern const char **CRT_treeStr;
extern int CRT_delay;
-int* CRT_colors;
+extern int* CRT_colors;
extern int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT];
@@ -157,21 +160,21 @@ extern int CRT_scrollHAmount;
extern int CRT_scrollWheelVAmount;
-char* CRT_termType;
+extern char* CRT_termType;
// TODO move color scheme to Settings, perhaps?
extern int CRT_colorScheme;
-void *backtraceArray[128];
+extern void *backtraceArray[128];
#if HAVE_SETUID_ENABLED
#define DIE(msg) do { CRT_done(); fprintf(stderr, msg); exit(1); } while(0)
-void CRT_dropPrivileges();
+extern void CRT_dropPrivileges();
-void CRT_restorePrivileges();
+extern void CRT_restorePrivileges();
#else
@@ -186,18 +189,18 @@ void CRT_restorePrivileges();
// TODO: pass an instance of Settings instead.
-void CRT_init(int delay, int colorScheme);
+extern void CRT_init(int delay, int colorScheme);
-void CRT_done();
+extern void CRT_done();
-void CRT_fatalError(const char* note);
+extern void CRT_fatalError(const char* note);
-int CRT_readKey();
+extern int CRT_readKey();
-void CRT_disableDelay();
+extern void CRT_disableDelay();
-void CRT_enableDelay();
+extern void CRT_enableDelay();
-void CRT_setColors(int colorScheme);
+extern void CRT_setColors(int colorScheme);
#endif
diff --git a/CategoriesPanel.h b/CategoriesPanel.h
index ccef0fae..44c6842a 100644
--- a/CategoriesPanel.h
+++ b/CategoriesPanel.h
@@ -24,10 +24,10 @@ typedef struct CategoriesPanel_ {
} CategoriesPanel;
-void CategoriesPanel_makeMetersPage(CategoriesPanel* this);
+extern void CategoriesPanel_makeMetersPage(CategoriesPanel* this);
extern PanelClass CategoriesPanel_class;
-CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Header* header, ProcessList* pl);
+extern CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Header* header, ProcessList* pl);
#endif
diff --git a/CheckItem.c b/CheckItem.c
index b7ba6fec..910981e8 100644
--- a/CheckItem.c
+++ b/CheckItem.c
@@ -66,14 +66,14 @@ CheckItem* CheckItem_newByVal(char* text, bool value) {
}
void CheckItem_set(CheckItem* this, bool value) {
- if (this->ref)
+ if (this->ref)
*(this->ref) = value;
else
this->value = value;
}
bool CheckItem_get(CheckItem* this) {
- if (this->ref)
+ if (this->ref)
return *(this->ref);
else
return this->value;
diff --git a/CheckItem.h b/CheckItem.h
index 5847d4b2..dbd1a039 100644
--- a/CheckItem.h
+++ b/CheckItem.h
@@ -21,12 +21,12 @@ typedef struct CheckItem_ {
extern ObjectClass CheckItem_class;
-CheckItem* CheckItem_newByRef(char* text, bool* ref);
+extern CheckItem* CheckItem_newByRef(char* text, bool* ref);
-CheckItem* CheckItem_newByVal(char* text, bool value);
+extern CheckItem* CheckItem_newByVal(char* text, bool value);
-void CheckItem_set(CheckItem* this, bool value);
+extern void CheckItem_set(CheckItem* this, bool value);
-bool CheckItem_get(CheckItem* this);
+extern bool CheckItem_get(CheckItem* this);
#endif
diff --git a/ColorsPanel.c b/ColorsPanel.c
index 2028335f..b2d3500c 100644
--- a/ColorsPanel.c
+++ b/ColorsPanel.c
@@ -56,7 +56,7 @@ static void ColorsPanel_delete(Object* object) {
static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
ColorsPanel* this = (ColorsPanel*) super;
-
+
HandlerResult result = IGNORED;
int mark = Panel_getSelectedIndex(super);
diff --git a/ColorsPanel.h b/ColorsPanel.h
index ee3111e0..82b782b8 100644
--- a/ColorsPanel.h
+++ b/ColorsPanel.h
@@ -29,6 +29,6 @@ typedef struct ColorsPanel_ {
extern PanelClass ColorsPanel_class;
-ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr);
+extern ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr);
#endif
diff --git a/ColumnsPanel.c b/ColumnsPanel.c
index 8974ffdc..f982292e 100644
--- a/ColumnsPanel.c
+++ b/ColumnsPanel.c
@@ -40,7 +40,7 @@ static void ColumnsPanel_delete(Object* object) {
static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
ColumnsPanel* const this = (ColumnsPanel*) super;
-
+
int selected = Panel_getSelectedIndex(super);
HandlerResult result = IGNORED;
int size = Panel_size(super);
@@ -87,7 +87,7 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
case ']':
case '+':
{
- if (selected < size - 2)
+ if (selected < size - 2)
Panel_moveSelectedDown(super);
result = HANDLED;
break;
diff --git a/ColumnsPanel.h b/ColumnsPanel.h
index 0da674a8..46d20bbb 100644
--- a/ColumnsPanel.h
+++ b/ColumnsPanel.h
@@ -22,11 +22,11 @@ typedef struct ColumnsPanel_ {
extern PanelClass ColumnsPanel_class;
-ColumnsPanel* ColumnsPanel_new(Settings* settings);
+extern ColumnsPanel* ColumnsPanel_new(Settings* settings);
-int ColumnsPanel_fieldNameToIndex(const char* name);
+extern int ColumnsPanel_fieldNameToIndex(const char* name);
-void ColumnsPanel_update(Panel* super);
+extern void ColumnsPanel_update(Panel* super);
#endif
diff --git a/DisplayOptionsPanel.c b/DisplayOptionsPanel.c
index 0ff54e33..0f44acc2 100644
--- a/DisplayOptionsPanel.c
+++ b/DisplayOptionsPanel.c
@@ -39,7 +39,7 @@ static void DisplayOptionsPanel_delete(Object* object) {
static HandlerResult DisplayOptionsPanel_eventHandler(Panel* super, int ch) {
DisplayOptionsPanel* this = (DisplayOptionsPanel*) super;
-
+
HandlerResult result = IGNORED;
CheckItem* selected = (CheckItem*) Panel_getSelected(super);
@@ -97,5 +97,8 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Count CPUs from 0 instead of 1"), &(settings->countCPUsFromZero)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Update process names on every refresh"), &(settings->updateProcessNames)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Add guest time in CPU meter percentage"), &(settings->accountGuestInCPUMeter)));
+ Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Also show CPU percentage numerically"), &(settings->showCPUUsage)));
+ Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Also show CPU frequency"), &(settings->showCPUFrequency)));
+ Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Enable the mouse"), &(settings->enableMouse)));
return this;
}
diff --git a/DisplayOptionsPanel.h b/DisplayOptionsPanel.h
index 2a7509ae..d9de4005 100644
--- a/DisplayOptionsPanel.h
+++ b/DisplayOptionsPanel.h
@@ -23,6 +23,6 @@ typedef struct DisplayOptionsPanel_ {
extern PanelClass DisplayOptionsPanel_class;
-DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr);
+extern DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr);
#endif
diff --git a/EnvScreen.h b/EnvScreen.h
index 7cdbb865..025cb8d3 100644
--- a/EnvScreen.h
+++ b/EnvScreen.h
@@ -11,12 +11,12 @@ typedef struct EnvScreen_ {
extern InfoScreenClass EnvScreen_class;
-EnvScreen* EnvScreen_new(Process* process);
+extern EnvScreen* EnvScreen_new(Process* process);
-void EnvScreen_delete(Object* this);
+extern void EnvScreen_delete(Object* this);
-void EnvScreen_draw(InfoScreen* this);
+extern void EnvScreen_draw(InfoScreen* this);
-void EnvScreen_scan(InfoScreen* this);
+extern void EnvScreen_scan(InfoScreen* this);
#endif
diff --git a/FunctionBar.c b/FunctionBar.c
index 4e4baaf3..8661bf0c 100644
--- a/FunctionBar.c
+++ b/FunctionBar.c
@@ -52,7 +52,7 @@ FunctionBar* FunctionBar_new(const char* const* functions, const char* const* ke
this->functions[i] = xStrdup(functions[i]);
}
if (keys && events) {
- this->staticData = false;
+ this->staticData = false;
this->keys = xCalloc(15, sizeof(char*));
this->events = xCalloc(15, sizeof(int));
int i = 0;
diff --git a/FunctionBar.h b/FunctionBar.h
index b60f6582..ee5b9347 100644
--- a/FunctionBar.h
+++ b/FunctionBar.h
@@ -22,18 +22,18 @@ typedef struct FunctionBar_ {
-FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc);
+extern FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc);
-FunctionBar* FunctionBar_new(const char* const* functions, const char* const* keys, const int* events);
+extern FunctionBar* FunctionBar_new(const char* const* functions, const char* const* keys, const int* events);
-void FunctionBar_delete(FunctionBar* this);
+extern void FunctionBar_delete(FunctionBar* this);
-void FunctionBar_setLabel(FunctionBar* this, int event, const char* text);
+extern void FunctionBar_setLabel(FunctionBar* this, int event, const char* text);
-void FunctionBar_draw(const FunctionBar* this, char* buffer);
+extern void FunctionBar_draw(const FunctionBar* this, char* buffer);
-void FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr);
+extern void FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr);
-int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos);
+extern int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos);
#endif
diff --git a/Hashtable.c b/Hashtable.c
index b3eac8da..3436dad6 100644
--- a/Hashtable.c
+++ b/Hashtable.c
@@ -63,7 +63,7 @@ int Hashtable_count(Hashtable* this) {
static HashtableItem* HashtableItem_new(unsigned int key, void* value) {
HashtableItem* this;
-
+
this = xMalloc(sizeof(HashtableItem));
this->key = key;
this->value = value;
@@ -73,7 +73,7 @@ static HashtableItem* HashtableItem_new(unsigned int key, void* value) {
Hashtable* Hashtable_new(int size, bool owner) {
Hashtable* this;
-
+
this = xMalloc(sizeof(Hashtable));
this->items = 0;
this->size = size;
@@ -119,10 +119,10 @@ void Hashtable_put(Hashtable* this, unsigned int key, void* value) {
void* Hashtable_remove(Hashtable* this, unsigned int key) {
unsigned int index = key % this->size;
-
+
assert(Hashtable_isConsistent(this));
- HashtableItem** bucket;
+ HashtableItem** bucket;
for (bucket = &(this->buckets[index]); *bucket; bucket = &((*bucket)->next) ) {
if ((*bucket)->key == key) {
void* value = (*bucket)->value;
diff --git a/Hashtable.h b/Hashtable.h
index 25608961..32b02188 100644
--- a/Hashtable.h
+++ b/Hashtable.h
@@ -30,20 +30,20 @@ struct Hashtable_ {
#ifdef DEBUG
-int Hashtable_count(Hashtable* this);
+extern int Hashtable_count(Hashtable* this);
#endif
-Hashtable* Hashtable_new(int size, bool owner);
+extern Hashtable* Hashtable_new(int size, bool owner);
-void Hashtable_delete(Hashtable* this);
+extern void Hashtable_delete(Hashtable* this);
-void Hashtable_put(Hashtable* this, unsigned int key, void* value);
+extern void Hashtable_put(Hashtable* this, unsigned int key, void* value);
-void* Hashtable_remove(Hashtable* this, unsigned int key);
+extern void* Hashtable_remove(Hashtable* this, unsigned int key);
extern void* Hashtable_get(Hashtable* this, unsigned int key);
-void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData);
+extern void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData);
#endif
diff --git a/Header.c b/Header.c
index e048ee55..a4075d22 100644
--- a/Header.c
+++ b/Header.c
@@ -76,17 +76,17 @@ void Header_populateFromSettings(Header* this) {
void Header_writeBackToSettings(const Header* this) {
Header_forEachColumn(this, col) {
MeterColumnSettings* colSettings = &this->settings->columns[col];
-
+
String_freeArray(colSettings->names);
free(colSettings->modes);
-
+
Vector* vec = this->columns[col];
int len = Vector_size(vec);
-
+
colSettings->names = xCalloc(len+1, sizeof(char*));
colSettings->modes = xCalloc(len, sizeof(int));
colSettings->len = len;
-
+
for (int i = 0; i < len; i++) {
Meter* meter = (Meter*) Vector_get(vec, i);
char* name = xCalloc(64, sizeof(char));
@@ -120,6 +120,8 @@ MeterModeId Header_addMeterByName(Header* this, char* name, int column) {
break;
}
}
+ if (paren)
+ *paren = '(';
return mode;
}
@@ -186,7 +188,7 @@ void Header_draw(const Header* this) {
}
int width = COLS / this->nrColumns - (pad * this->nrColumns - 1) - 1;
int x = pad;
-
+
Header_forEachColumn(this, col) {
Vector* meters = this->columns[col];
for (int y = (pad / 2), i = 0; i < Vector_size(meters); i++) {
diff --git a/Header.h b/Header.h
index 700ad354..f5182454 100644
--- a/Header.h
+++ b/Header.h
@@ -31,30 +31,30 @@ typedef struct Header_ {
#define Header_forEachColumn(this_, i_) for (int (i_)=0; (i_) < (this_)->nrColumns; ++(i_))
#endif
-Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns);
+extern Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns);
-void Header_delete(Header* this);
+extern void Header_delete(Header* this);
-void Header_populateFromSettings(Header* this);
+extern void Header_populateFromSettings(Header* this);
-void Header_writeBackToSettings(const Header* this);
+extern void Header_writeBackToSettings(const Header* this);
-MeterModeId Header_addMeterByName(Header* this, char* name, int column);
+extern MeterModeId Header_addMeterByName(Header* this, char* name, int column);
-void Header_setMode(Header* this, int i, MeterModeId mode, int column);
+extern void Header_setMode(Header* this, int i, MeterModeId mode, int column);
-Meter* Header_addMeterByClass(Header* this, MeterClass* type, int param, int column);
+extern Meter* Header_addMeterByClass(Header* this, MeterClass* type, int param, int column);
-int Header_size(Header* this, int column);
+extern int Header_size(Header* this, int column);
-char* Header_readMeterName(Header* this, int i, int column);
+extern char* Header_readMeterName(Header* this, int i, int column);
-MeterModeId Header_readMeterMode(Header* this, int i, int column);
+extern MeterModeId Header_readMeterMode(Header* this, int i, int column);
-void Header_reinit(Header* this);
+extern void Header_reinit(Header* this);
-void Header_draw(const Header* this);
+extern void Header_draw(const Header* this);
-int Header_calculateHeight(Header* this);
+extern int Header_calculateHeight(Header* this);
#endif
diff --git a/IncSet.c b/IncSet.c
index bb9f9544..eaab549c 100644
--- a/IncSet.c
+++ b/IncSet.c
@@ -52,6 +52,10 @@ static void IncMode_reset(IncMode* mode) {
mode->buffer[0] = 0;
}
+void IncSet_reset(IncSet* this, IncType type) {
+ IncMode_reset(&this->modes[type]);
+}
+
static const char* const searchFunctions[] = {"Next ", "Cancel ", " Search: ", NULL};
static const char* const searchKeys[] = {"F3", "Esc", " "};
static int searchEvents[] = {KEY_F(3), 27, ERR};
@@ -132,6 +136,30 @@ static bool search(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelVa
return found;
}
+static bool IncMode_find(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelValue, int step) {
+ int size = Panel_size(panel);
+ int here = Panel_getSelectedIndex(panel);
+ int i = here;
+ for(;;) {
+ i+=step;
+ if (i == size) i = 0;
+ if (i == -1) i = size - 1;
+ if (i == here) return false;
+ if (String_contains_i(getPanelValue(panel, i), mode->buffer)) {
+ Panel_setSelected(panel, i);
+ return true;
+ }
+ }
+}
+
+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;
@@ -141,17 +169,7 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
bool doSearch = true;
if (ch == KEY_F(3)) {
if (size == 0) return true;
- int here = Panel_getSelectedIndex(panel);
- int i = here;
- for(;;) {
- i++;
- if (i == size) i = 0;
- if (i == here) break;
- if (String_contains_i(getPanelValue(panel, i), mode->buffer)) {
- Panel_setSelected(panel, i);
- break;
- }
- }
+ IncMode_find(mode, panel, getPanelValue, 1);
doSearch = false;
} else if (ch < 255 && isprint((char)ch)) {
if (mode->index < INCMODE_MAX) {
@@ -187,7 +205,9 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
IncMode_reset(mode);
}
} else {
- IncMode_reset(mode);
+ if (ch == 27) {
+ IncMode_reset(mode);
+ }
}
this->active = NULL;
Panel_setDefaultBar(panel);
diff --git a/IncSet.h b/IncSet.h
index 27538f4b..136436e2 100644
--- a/IncSet.h
+++ b/IncSet.h
@@ -41,18 +41,24 @@ typedef struct IncSet_ {
typedef const char* (*IncMode_GetPanelValue)(Panel*, int);
-IncSet* IncSet_new(FunctionBar* bar);
+extern void IncSet_reset(IncSet* this, IncType type);
-void IncSet_delete(IncSet* this);
+extern IncSet* IncSet_new(FunctionBar* bar);
-bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines);
+extern void IncSet_delete(IncSet* this);
-const char* IncSet_getListItemValue(Panel* panel, int i);
+extern bool IncSet_next(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue);
-void IncSet_activate(IncSet* this, IncType type, Panel* panel);
+extern bool IncSet_prev(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue);
-void IncSet_drawBar(IncSet* this);
+extern bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines);
-int IncSet_synthesizeEvent(IncSet* this, int x);
+extern const char* IncSet_getListItemValue(Panel* panel, int i);
+
+extern void IncSet_activate(IncSet* this, IncType type, Panel* panel);
+
+extern void IncSet_drawBar(IncSet* this);
+
+extern int IncSet_synthesizeEvent(IncSet* this, int x);
#endif
diff --git a/InfoScreen.c b/InfoScreen.c
index fab8daea..0b919932 100644
--- a/InfoScreen.c
+++ b/InfoScreen.c
@@ -120,7 +120,7 @@ void InfoScreen_run(InfoScreen* this) {
}
set_escdelay(25);
int ch = getch();
-
+
if (ch == ERR) {
if (As_InfoScreen(this)->onErr) {
InfoScreen_onErr(this);
@@ -131,19 +131,21 @@ void InfoScreen_run(InfoScreen* this) {
if (ch == KEY_MOUSE) {
MEVENT mevent;
int ok = getmouse(&mevent);
- if (ok == OK)
+ if (ok == OK) {
if (mevent.y >= panel->y && mevent.y < LINES - 1) {
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV);
ch = 0;
- } if (mevent.y == LINES - 1)
+ } else if (mevent.y == LINES - 1) {
ch = IncSet_synthesizeEvent(this->inc, mevent.x);
+ }
+ }
}
if (this->inc->active) {
IncSet_handleKey(this->inc, ch, panel, IncSet_getListItemValue, this->lines);
continue;
}
-
+
switch(ch) {
case ERR:
continue;
diff --git a/InfoScreen.h b/InfoScreen.h
index 2e1599f9..b9387cda 100644
--- a/InfoScreen.h
+++ b/InfoScreen.h
@@ -38,16 +38,16 @@ struct InfoScreen_ {
Vector* lines;
};
-InfoScreen* InfoScreen_init(InfoScreen* this, Process* process, FunctionBar* bar, int height, char* panelHeader);
+extern InfoScreen* InfoScreen_init(InfoScreen* this, Process* process, FunctionBar* bar, int height, char* panelHeader);
-InfoScreen* InfoScreen_done(InfoScreen* this);
+extern InfoScreen* InfoScreen_done(InfoScreen* this);
-void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...);
+extern void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...);
-void InfoScreen_addLine(InfoScreen* this, const char* line);
+extern void InfoScreen_addLine(InfoScreen* this, const char* line);
-void InfoScreen_appendLine(InfoScreen* this, const char* line);
+extern void InfoScreen_appendLine(InfoScreen* this, const char* line);
-void InfoScreen_run(InfoScreen* this);
+extern void InfoScreen_run(InfoScreen* this);
#endif
diff --git a/ListItem.h b/ListItem.h
index b48f0acd..7fed9237 100644
--- a/ListItem.h
+++ b/ListItem.h
@@ -21,13 +21,13 @@ typedef struct ListItem_ {
extern ObjectClass ListItem_class;
-ListItem* ListItem_new(const char* value, int key);
+extern ListItem* ListItem_new(const char* value, int key);
-void ListItem_append(ListItem* this, const char* text);
+extern void ListItem_append(ListItem* this, const char* text);
-const char* ListItem_getRef(ListItem* this);
+extern const char* ListItem_getRef(ListItem* this);
-long ListItem_compare(const void* cast1, const void* cast2);
+extern long ListItem_compare(const void* cast1, const void* cast2);
#endif
diff --git a/MainPanel.c b/MainPanel.c
index 25023367..55be17bf 100644
--- a/MainPanel.c
+++ b/MainPanel.c
@@ -1,6 +1,7 @@
/*
htop - ColumnsPanel.c
(C) 2004-2015 Hisham H. Muhammad
+(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
@@ -25,18 +26,13 @@ typedef struct MainPanel_ {
pid_t pidSearch;
} MainPanel;
-typedef union {
- int i;
- void* v;
-} Arg;
-
typedef bool(*MainPanel_ForeachProcessFn)(Process*, Arg);
#define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar)
}*/
-static const char* const MainFunctions[] = {"Help ", "Setup ", "Search", "Filter", "Tree ", "SortBy", "Nice -", "Nice +", "Kill ", "Quit ", NULL};
+static const char* const MainFunctions[] = {"Help ", "Setup ", "Search ", "Filter ", "Tree ", "SortBy ", "Nice - ", "Nice + ", "Kill ", "Quit ", NULL};
void MainPanel_updateTreeFunctions(MainPanel* this, bool mode) {
FunctionBar* bar = MainPanel_getFunctionBar(this);
@@ -69,7 +65,7 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
MainPanel* this = (MainPanel*) super;
HandlerResult result = IGNORED;
-
+
Htop_Reaction reaction = HTOP_OK;
if (EVENT_IS_HEADER_CLICK(ch)) {
@@ -84,7 +80,7 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
} else {
reaction |= Action_setSortKey(settings, field);
}
- reaction |= HTOP_RECALCULATE | HTOP_REDRAW_BAR | HTOP_SAVE_SETTINGS;
+ 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);
@@ -121,7 +117,7 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
}
if (reaction & HTOP_REFRESH) {
result |= REDRAW;
- }
+ }
if (reaction & HTOP_RECALCULATE) {
result |= RESCAN;
}
diff --git a/MainPanel.h b/MainPanel.h
index 88496597..6162d8e9 100644
--- a/MainPanel.h
+++ b/MainPanel.h
@@ -5,6 +5,7 @@
/*
htop - ColumnsPanel.h
(C) 2004-2015 Hisham H. Muhammad
+(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
@@ -21,32 +22,27 @@ typedef struct MainPanel_ {
pid_t pidSearch;
} MainPanel;
-typedef union {
- int i;
- void* v;
-} Arg;
-
typedef bool(*MainPanel_ForeachProcessFn)(Process*, Arg);
#define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar)
-void MainPanel_updateTreeFunctions(MainPanel* this, bool mode);
+extern void MainPanel_updateTreeFunctions(MainPanel* this, bool mode);
-void MainPanel_pidSearch(MainPanel* this, int ch);
+extern void MainPanel_pidSearch(MainPanel* this, int ch);
-int MainPanel_selectedPid(MainPanel* this);
+extern int MainPanel_selectedPid(MainPanel* this);
-const char* MainPanel_getValue(MainPanel* this, int i);
+extern const char* MainPanel_getValue(MainPanel* this, int i);
-bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged);
+extern bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged);
extern PanelClass MainPanel_class;
-MainPanel* MainPanel_new();
+extern MainPanel* MainPanel_new();
-void MainPanel_setState(MainPanel* this, State* state);
+extern void MainPanel_setState(MainPanel* this, State* state);
-void MainPanel_delete(Object* object);
+extern void MainPanel_delete(Object* object);
#endif
diff --git a/Makefile.am b/Makefile.am
index 2d159f02..159e22a7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -49,6 +49,7 @@ linux_platform_headers = \
linux/LinuxProcessList.h \
linux/LinuxCRT.h \
linux/Battery.h \
+ linux/PressureStallMeter.h \
zfs/ZfsArcMeter.h \
zfs/ZfsCompressedArcMeter.h \
zfs/ZfsArcStats.h
@@ -56,9 +57,10 @@ linux_platform_headers = \
all_platform_headers += $(linux_platform_headers)
if HTOP_LINUX
-AM_CFLAGS += -rdynamic
+AM_LDFLAGS += -rdynamic
myhtopplatsources = linux/Platform.c linux/IOPriorityPanel.c linux/IOPriority.c \
linux/LinuxProcess.c linux/LinuxProcessList.c linux/LinuxCRT.c linux/Battery.c \
+linux/PressureStallMeter.c \
zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c
myhtopplatheaders = $(linux_platform_headers)
diff --git a/MemoryMeter.c b/MemoryMeter.c
index fbf5330c..8d5d809e 100644
--- a/MemoryMeter.c
+++ b/MemoryMeter.c
@@ -60,7 +60,7 @@ MeterClass MemoryMeter_class = {
.delete = Meter_delete,
.display = MemoryMeter_display,
},
- .updateValues = MemoryMeter_updateValues,
+ .updateValues = MemoryMeter_updateValues,
.defaultMode = BAR_METERMODE,
.maxItems = 3,
.total = 100.0,
diff --git a/Meter.c b/Meter.c
index 05a4eb23..699a7881 100644
--- a/Meter.c
+++ b/Meter.c
@@ -78,7 +78,7 @@ typedef struct MeterClass_ {
struct Meter_ {
Object super;
Meter_Draw draw;
-
+
char* caption;
int mode;
int param;
@@ -275,7 +275,7 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
attrset(CRT_colors[BAR_BORDER]);
mvaddch(y, x, '[');
mvaddch(y, x + w, ']');
-
+
w--;
x++;
@@ -284,7 +284,7 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
return;
}
char bar[w + 1];
-
+
int blockSizes[10];
xSnprintf(bar, w + 1, "%*.*s", w, w, buffer);
@@ -378,7 +378,7 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
mvaddnstr(y, x, this->caption, captionLen);
x += captionLen;
w -= captionLen;
-
+
struct timeval now;
gettimeofday(&now, NULL);
if (!timercmp(&now, &(data->time), <)) {
@@ -387,10 +387,10 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
for (int i = 0; i < nValues - 1; i++)
data->values[i] = data->values[i+1];
-
+
char buffer[nValues];
Meter_updateValues(this, buffer, nValues - 1);
-
+
double value = 0.0;
int items = Meter_getItems(this);
for (int i = 0; i < items; i++)
@@ -398,7 +398,7 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
value /= this->total;
data->values[nValues - 1] = value;
}
-
+
int i = nValues - (w*2) + 2, k = 0;
if (i < 0) {
k = -i/2;
@@ -459,7 +459,7 @@ static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
char buffer[METER_BUFFER_LEN];
Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
-
+
RichString_begin(out);
Meter_displayBuffer(this, buffer, &out);
@@ -523,6 +523,9 @@ MeterMode* Meter_modes[] = {
static void BlankMeter_updateValues(Meter* this, char* buffer, int size) {
(void) this; (void) buffer; (void) size;
+ if (size > 0) {
+ *buffer = 0;
+ }
}
static void BlankMeter_display(Object* cast, RichString* out) {
diff --git a/Meter.h b/Meter.h
index d98c910e..56d46f23 100644
--- a/Meter.h
+++ b/Meter.h
@@ -65,7 +65,7 @@ typedef struct MeterClass_ {
struct Meter_ {
Object super;
Meter_Draw draw;
-
+
char* caption;
int mode;
int param;
@@ -109,17 +109,17 @@ typedef struct GraphData_ {
extern MeterClass Meter_class;
-Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type);
+extern Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type);
-int Meter_humanUnit(char* buffer, unsigned long int value, int size);
+extern int Meter_humanUnit(char* buffer, unsigned long int value, int size);
-void Meter_delete(Object* cast);
+extern void Meter_delete(Object* cast);
-void Meter_setCaption(Meter* this, const char* caption);
+extern void Meter_setCaption(Meter* this, const char* caption);
-void Meter_setMode(Meter* this, int modeIndex);
+extern void Meter_setMode(Meter* this, int modeIndex);
-ListItem* Meter_toListItem(Meter* this, bool moving);
+extern ListItem* Meter_toListItem(Meter* this, bool moving);
/* ---------- TextMeterMode ---------- */
diff --git a/MetersPanel.c b/MetersPanel.c
index 3cf3e075..397a6c7d 100644
--- a/MetersPanel.c
+++ b/MetersPanel.c
@@ -93,7 +93,7 @@ static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int
static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
MetersPanel* this = (MetersPanel*) super;
-
+
int selected = Panel_getSelectedIndex(super);
HandlerResult result = IGNORED;
bool sideMove = false;
diff --git a/MetersPanel.h b/MetersPanel.h
index e00169c8..12eabbe6 100644
--- a/MetersPanel.h
+++ b/MetersPanel.h
@@ -34,10 +34,10 @@ struct MetersPanel_ {
// In <http://unicode.org/reports/tr11/>, arrows (U+2019..U+2199) are
// considered "Ambiguous characters".
-void MetersPanel_setMoving(MetersPanel* this, bool moving);
+extern void MetersPanel_setMoving(MetersPanel* this, bool moving);
extern PanelClass MetersPanel_class;
-MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* meters, ScreenManager* scr);
+extern MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* meters, ScreenManager* scr);
#endif
diff --git a/Object.c b/Object.c
index 120d28c1..5edcc603 100644
--- a/Object.c
+++ b/Object.c
@@ -1,6 +1,7 @@
/*
htop - Object.c
(C) 2004-2012 Hisham H. Muhammad
+(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
@@ -28,7 +29,7 @@ typedef void(*Object_Delete)(Object*);
#define Class(class_) ((ObjectClass*)(&(class_ ## _class)))
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_));
-
+
typedef struct ObjectClass_ {
const void* extends;
const Object_Display display;
@@ -40,6 +41,11 @@ struct Object_ {
ObjectClass* klass;
};
+typedef union {
+ int i;
+ void* v;
+} Arg;
+
}*/
ObjectClass Object_class = {
diff --git a/Object.h b/Object.h
index 19a667c8..9be948f8 100644
--- a/Object.h
+++ b/Object.h
@@ -5,6 +5,7 @@
/*
htop - Object.h
(C) 2004-2012 Hisham H. Muhammad
+(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
@@ -29,7 +30,7 @@ typedef void(*Object_Delete)(Object*);
#define Class(class_) ((ObjectClass*)(&(class_ ## _class)))
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_));
-
+
typedef struct ObjectClass_ {
const void* extends;
const Object_Display display;
@@ -41,12 +42,17 @@ struct Object_ {
ObjectClass* klass;
};
+typedef union {
+ int i;
+ void* v;
+} Arg;
+
extern ObjectClass Object_class;
#ifdef DEBUG
-bool Object_isA(Object* o, const ObjectClass* klass);
+extern bool Object_isA(Object* o, const ObjectClass* klass);
#endif
diff --git a/OpenFilesScreen.c b/OpenFilesScreen.c
index 9ea333bf..658b1866 100644
--- a/OpenFilesScreen.c
+++ b/OpenFilesScreen.c
@@ -124,6 +124,7 @@ static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
item->data[cmd] = xStrdup(line + 1);
free(line);
}
+ fclose(fd);
int wstatus;
if (waitpid(child, &wstatus, 0) == -1) {
pdata->error = 1;
diff --git a/OpenFilesScreen.h b/OpenFilesScreen.h
index 8160cfe2..39c71d5b 100644
--- a/OpenFilesScreen.h
+++ b/OpenFilesScreen.h
@@ -34,12 +34,12 @@ typedef struct OpenFilesScreen_ {
extern InfoScreenClass OpenFilesScreen_class;
-OpenFilesScreen* OpenFilesScreen_new(Process* process);
+extern OpenFilesScreen* OpenFilesScreen_new(Process* process);
-void OpenFilesScreen_delete(Object* this);
+extern void OpenFilesScreen_delete(Object* this);
-void OpenFilesScreen_draw(InfoScreen* this);
+extern void OpenFilesScreen_draw(InfoScreen* this);
-void OpenFilesScreen_scan(InfoScreen* this);
+extern void OpenFilesScreen_scan(InfoScreen* this);
#endif
diff --git a/Panel.c b/Panel.c
index 1e53b4a4..fc4fa3c2 100644
--- a/Panel.c
+++ b/Panel.c
@@ -372,7 +372,7 @@ void Panel_draw(Panel* this, bool focus) {
bool Panel_onKey(Panel* this, int key) {
assert (this != NULL);
-
+
int size = Vector_size(this->items);
switch (key) {
case KEY_DOWN:
@@ -455,7 +455,7 @@ bool Panel_onKey(Panel* this, int key) {
if (this->selected < 0 || size == 0) {
this->selected = 0;
this->needsRedraw = true;
- } else if (this->selected >= size) {
+ } else if (this->selected >= size) {
this->selected = size - 1;
this->needsRedraw = true;
}
diff --git a/Panel.h b/Panel.h
index 5253fc2e..b7480c6b 100644
--- a/Panel.h
+++ b/Panel.h
@@ -75,52 +75,52 @@ struct Panel_ {
extern PanelClass Panel_class;
-Panel* Panel_new(int x, int y, int w, int h, bool owner, ObjectClass* type, FunctionBar* fuBar);
+extern Panel* Panel_new(int x, int y, int w, int h, bool owner, ObjectClass* type, FunctionBar* fuBar);
-void Panel_delete(Object* cast);
+extern void Panel_delete(Object* cast);
-void Panel_init(Panel* this, int x, int y, int w, int h, ObjectClass* type, bool owner, FunctionBar* fuBar);
+extern void Panel_init(Panel* this, int x, int y, int w, int h, ObjectClass* type, bool owner, FunctionBar* fuBar);
-void Panel_done(Panel* this);
+extern void Panel_done(Panel* this);
-void Panel_setSelectionColor(Panel* this, int color);
+extern void Panel_setSelectionColor(Panel* this, int color);
-RichString* Panel_getHeader(Panel* this);
+extern RichString* Panel_getHeader(Panel* this);
extern void Panel_setHeader(Panel* this, const char* header);
-void Panel_move(Panel* this, int x, int y);
+extern void Panel_move(Panel* this, int x, int y);
-void Panel_resize(Panel* this, int w, int h);
+extern void Panel_resize(Panel* this, int w, int h);
-void Panel_prune(Panel* this);
+extern void Panel_prune(Panel* this);
-void Panel_add(Panel* this, Object* o);
+extern void Panel_add(Panel* this, Object* o);
-void Panel_insert(Panel* this, int i, Object* o);
+extern void Panel_insert(Panel* this, int i, Object* o);
-void Panel_set(Panel* this, int i, Object* o);
+extern void Panel_set(Panel* this, int i, Object* o);
-Object* Panel_get(Panel* this, int i);
+extern Object* Panel_get(Panel* this, int i);
-Object* Panel_remove(Panel* this, int i);
+extern Object* Panel_remove(Panel* this, int i);
-Object* Panel_getSelected(Panel* this);
+extern Object* Panel_getSelected(Panel* this);
-void Panel_moveSelectedUp(Panel* this);
+extern void Panel_moveSelectedUp(Panel* this);
-void Panel_moveSelectedDown(Panel* this);
+extern void Panel_moveSelectedDown(Panel* this);
-int Panel_getSelectedIndex(Panel* this);
+extern int Panel_getSelectedIndex(Panel* this);
-int Panel_size(Panel* this);
+extern int Panel_size(Panel* this);
-void Panel_setSelected(Panel* this, int selected);
+extern void Panel_setSelected(Panel* this, int selected);
-void Panel_draw(Panel* this, bool focus);
+extern void Panel_draw(Panel* this, bool focus);
-bool Panel_onKey(Panel* this, int key);
+extern bool Panel_onKey(Panel* this, int key);
-HandlerResult Panel_selectByTyping(Panel* this, int ch);
+extern HandlerResult Panel_selectByTyping(Panel* this, int ch);
#endif
diff --git a/Process.c b/Process.c
index 54c41af4..7bcaf19a 100644
--- a/Process.c
+++ b/Process.c
@@ -1,6 +1,7 @@
/*
htop - Process.c
(C) 2004-2015 Hisham H. Muhammad
+(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
@@ -8,6 +9,8 @@ in the source distribution for its full text.
#include "Process.h"
#include "Settings.h"
+#include "config.h"
+
#include "CRT.h"
#include "StringUtils.h"
#include "RichString.h"
@@ -30,8 +33,7 @@ in the source distribution for its full text.
#include <math.h>
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
-#elif defined(MAJOR_IN_SYSMACROS) || \
- (defined(HAVE_SYS_SYSMACROS_H) && HAVE_SYS_SYSMACROS_H)
+#elif defined(MAJOR_IN_SYSMACROS)
#include <sys/sysmacros.h>
#endif
@@ -191,10 +193,12 @@ static int Process_getuid = -1;
#define ONE_K 1024L
#define ONE_M (ONE_K * ONE_K)
#define ONE_G (ONE_M * ONE_K)
+#define ONE_T ((long long)ONE_G * ONE_K)
#define ONE_DECIMAL_K 1000L
#define ONE_DECIMAL_M (ONE_DECIMAL_K * ONE_DECIMAL_K)
#define ONE_DECIMAL_G (ONE_DECIMAL_M * ONE_DECIMAL_K)
+#define ONE_DECIMAL_T ((long long)ONE_DECIMAL_G * ONE_DECIMAL_K)
char Process_pidFormat[20] = "%7d ";
@@ -216,7 +220,7 @@ void Process_setupColumnWidths() {
void Process_humanNumber(RichString* str, unsigned long number, bool coloring) {
char buffer[11];
int len;
-
+
int largeNumberColor = CRT_colors[LARGE_NUMBER];
int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES];
int processColor = CRT_colors[PROCESS];
@@ -224,7 +228,7 @@ void Process_humanNumber(RichString* str, unsigned long number, bool coloring) {
largeNumberColor = CRT_colors[PROCESS];
processMegabytesColor = CRT_colors[PROCESS];
}
-
+
if(number >= (10 * ONE_DECIMAL_M)) {
#ifdef __LP64__
if(number >= (100 * ONE_DECIMAL_G)) {
@@ -277,8 +281,15 @@ void Process_colorNumber(RichString* str, unsigned long long number, bool colori
if ((long long) number == -1LL) {
int len = snprintf(buffer, 13, " no perm ");
RichString_appendn(str, CRT_colors[PROCESS_SHADOW], buffer, len);
- } else if (number > 10000000000) {
- xSnprintf(buffer, 13, "%11llu ", number / 1000);
+ } else if (number >= 100000LL * ONE_DECIMAL_T) {
+ xSnprintf(buffer, 13, "%11llu ", number / ONE_DECIMAL_G);
+ RichString_appendn(str, largeNumberColor, buffer, 12);
+ } else if (number >= 100LL * ONE_DECIMAL_T) {
+ xSnprintf(buffer, 13, "%11llu ", number / ONE_DECIMAL_M);
+ RichString_appendn(str, largeNumberColor, buffer, 8);
+ RichString_appendn(str, processMegabytesColor, buffer+8, 4);
+ } else if (number >= 10LL * ONE_DECIMAL_G) {
+ xSnprintf(buffer, 13, "%11llu ", number / ONE_DECIMAL_K);
RichString_appendn(str, largeNumberColor, buffer, 5);
RichString_appendn(str, processMegabytesColor, buffer+5, 3);
RichString_appendn(str, processColor, buffer+8, 4);
@@ -358,14 +369,17 @@ void Process_outputRate(RichString* str, char* buffer, int n, double rate, int c
} else if (rate < ONE_K) {
int len = snprintf(buffer, n, "%7.2f B/s ", rate);
RichString_appendn(str, processColor, buffer, len);
- } else if (rate < ONE_K * ONE_K) {
+ } else if (rate < ONE_M) {
int len = snprintf(buffer, n, "%7.2f K/s ", rate / ONE_K);
RichString_appendn(str, processColor, buffer, len);
- } else if (rate < ONE_K * ONE_K * ONE_K) {
- int len = snprintf(buffer, n, "%7.2f M/s ", rate / ONE_K / ONE_K);
+ } else if (rate < ONE_G) {
+ int len = snprintf(buffer, n, "%7.2f M/s ", rate / ONE_M);
RichString_appendn(str, processMegabytesColor, buffer, len);
+ } else if (rate < ONE_T) {
+ int len = snprintf(buffer, n, "%7.2f G/s ", rate / ONE_G);
+ RichString_appendn(str, largeNumberColor, buffer, len);
} else {
- int len = snprintf(buffer, n, "%7.2f G/s ", rate / ONE_K / ONE_K / ONE_K);
+ int len = snprintf(buffer, n, "%7.2f T/s ", rate / ONE_T);
RichString_appendn(str, largeNumberColor, buffer, len);
}
}
@@ -380,9 +394,9 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
switch (field) {
case PERCENT_CPU: {
if (this->percent_cpu > 999.9) {
- xSnprintf(buffer, n, "%4u ", (unsigned int)this->percent_cpu);
+ xSnprintf(buffer, n, "%4u ", (unsigned int)this->percent_cpu);
} else if (this->percent_cpu > 99.9) {
- xSnprintf(buffer, n, "%3u. ", (unsigned int)this->percent_cpu);
+ xSnprintf(buffer, n, "%3u. ", (unsigned int)this->percent_cpu);
} else {
xSnprintf(buffer, n, "%4.1f ", this->percent_cpu);
}
@@ -390,7 +404,7 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
}
case PERCENT_MEM: {
if (this->percent_mem > 99.9) {
- xSnprintf(buffer, n, "100. ");
+ xSnprintf(buffer, n, "100. ");
} else {
xSnprintf(buffer, n, "%4.1f ", this->percent_mem);
}
@@ -471,7 +485,7 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
}
break;
}
- case ST_UID: xSnprintf(buffer, n, "%4d ", this->st_uid); break;
+ case ST_UID: xSnprintf(buffer, n, "%5d ", this->st_uid); break;
case TIME: Process_printTime(str, this->time); return;
case TGID: xSnprintf(buffer, n, Process_pidFormat, this->tgid); break;
case TPGID: xSnprintf(buffer, n, Process_pidFormat, this->tpgid); break;
@@ -549,14 +563,15 @@ bool Process_setPriority(Process* this, int priority) {
return (err == 0);
}
-bool Process_changePriorityBy(Process* this, int delta) {
- return Process_setPriority(this, this->nice + delta);
+bool Process_changePriorityBy(Process* this, Arg delta) {
+ return Process_setPriority(this, this->nice + delta.i);
}
-void Process_sendSignal(Process* this, int sgn) {
+bool Process_sendSignal(Process* this, Arg sgn) {
CRT_dropPrivileges();
- kill(this->pid, (int) sgn);
+ bool ok = (kill(this->pid, sgn.i) == 0);
CRT_restorePrivileges();
+ return ok;
}
long Process_pidCompare(const void* v1, const void* v2) {
diff --git a/Process.h b/Process.h
index f702ca00..56a4dba1 100644
--- a/Process.h
+++ b/Process.h
@@ -5,13 +5,13 @@
/*
htop - Process.h
(C) 2004-2015 Hisham H. Muhammad
+(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#ifdef MAJOR_IN_MKDEV
-#elif defined(MAJOR_IN_SYSMACROS) || \
- (defined(HAVE_SYS_SYSMACROS_H) && HAVE_SYS_SYSMACROS_H)
+#elif defined(MAJOR_IN_SYSMACROS)
#endif
#ifdef __ANDROID__
@@ -166,43 +166,45 @@ typedef struct ProcessClass_ {
#define ONE_K 1024L
#define ONE_M (ONE_K * ONE_K)
#define ONE_G (ONE_M * ONE_K)
+#define ONE_T ((long long)ONE_G * ONE_K)
#define ONE_DECIMAL_K 1000L
#define ONE_DECIMAL_M (ONE_DECIMAL_K * ONE_DECIMAL_K)
#define ONE_DECIMAL_G (ONE_DECIMAL_M * ONE_DECIMAL_K)
+#define ONE_DECIMAL_T ((long long)ONE_DECIMAL_G * ONE_DECIMAL_K)
extern char Process_pidFormat[20];
-void Process_setupColumnWidths();
+extern void Process_setupColumnWidths();
-void Process_humanNumber(RichString* str, unsigned long number, bool coloring);
+extern void Process_humanNumber(RichString* str, unsigned long number, bool coloring);
-void Process_colorNumber(RichString* str, unsigned long long number, bool coloring);
+extern void Process_colorNumber(RichString* str, unsigned long long number, bool coloring);
-void Process_printTime(RichString* str, unsigned long long totalHundredths);
+extern void Process_printTime(RichString* str, unsigned long long totalHundredths);
-void Process_outputRate(RichString* str, char* buffer, int n, double rate, int coloring);
+extern void Process_outputRate(RichString* str, char* buffer, int n, double rate, int coloring);
-void Process_writeField(Process* this, RichString* str, ProcessField field);
+extern void Process_writeField(Process* this, RichString* str, ProcessField field);
-void Process_display(Object* cast, RichString* out);
+extern void Process_display(Object* cast, RichString* out);
-void Process_done(Process* this);
+extern void Process_done(Process* this);
extern ProcessClass Process_class;
-void Process_init(Process* this, struct Settings_* settings);
+extern void Process_init(Process* this, struct Settings_* settings);
-void Process_toggleTag(Process* this);
+extern void Process_toggleTag(Process* this);
-bool Process_setPriority(Process* this, int priority);
+extern bool Process_setPriority(Process* this, int priority);
-bool Process_changePriorityBy(Process* this, int delta);
+extern bool Process_changePriorityBy(Process* this, Arg delta);
-void Process_sendSignal(Process* this, int sgn);
+extern bool Process_sendSignal(Process* this, Arg sgn);
-long Process_pidCompare(const void* v1, const void* v2);
+extern long Process_pidCompare(const void* v1, const void* v2);
-long Process_compare(const void* v1, const void* v2);
+extern long Process_compare(const void* v1, const void* v2);
#endif
diff --git a/ProcessList.c b/ProcessList.c
index 7482b037..edbc114c 100644
--- a/ProcessList.c
+++ b/ProcessList.c
@@ -84,10 +84,10 @@ ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable*
this->usersTable = usersTable;
this->pidWhiteList = pidWhiteList;
this->userId = userId;
-
+
// tree-view auxiliary buffer
this->processes2 = Vector_new(klass, true, DEFAULT_SIZE);
-
+
// set later by platform-specific code
this->cpuCount = 0;
@@ -138,10 +138,10 @@ void ProcessList_printHeader(ProcessList* this, RichString* header) {
void ProcessList_add(ProcessList* this, Process* p) {
assert(Vector_indexOf(this->processes, p, Process_pidCompare) == -1);
assert(Hashtable_get(this->processTable, p->pid) == NULL);
-
+
Vector_add(this->processes, p);
Hashtable_put(this->processTable, p->pid, p);
-
+
assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1);
assert(Hashtable_get(this->processTable, p->pid) != NULL);
assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
@@ -353,7 +353,7 @@ void ProcessList_scan(ProcessList* this) {
this->runningTasks = 0;
ProcessList_goThroughEntries(this);
-
+
for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
Process* p = (Process*) Vector_get(this->processes, i);
if (p->updated == false)
diff --git a/ProcessList.h b/ProcessList.h
index 572d4843..ddc6f3fa 100644
--- a/ProcessList.h
+++ b/ProcessList.h
@@ -71,32 +71,32 @@ void ProcessList_delete(ProcessList* pl);
void ProcessList_goThroughEntries(ProcessList* pl);
-ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId);
+extern ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId);
-void ProcessList_done(ProcessList* this);
+extern void ProcessList_done(ProcessList* this);
-void ProcessList_setPanel(ProcessList* this, Panel* panel);
+extern void ProcessList_setPanel(ProcessList* this, Panel* panel);
-void ProcessList_printHeader(ProcessList* this, RichString* header);
+extern void ProcessList_printHeader(ProcessList* this, RichString* header);
-void ProcessList_add(ProcessList* this, Process* p);
+extern void ProcessList_add(ProcessList* this, Process* p);
-void ProcessList_remove(ProcessList* this, Process* p);
+extern void ProcessList_remove(ProcessList* this, Process* p);
-Process* ProcessList_get(ProcessList* this, int idx);
+extern Process* ProcessList_get(ProcessList* this, int idx);
-int ProcessList_size(ProcessList* this);
+extern int ProcessList_size(ProcessList* this);
-void ProcessList_sort(ProcessList* this);
+extern void ProcessList_sort(ProcessList* this);
-ProcessField ProcessList_keyAt(ProcessList* this, int at);
+extern ProcessField ProcessList_keyAt(ProcessList* this, int at);
-void ProcessList_expandTree(ProcessList* this);
+extern void ProcessList_expandTree(ProcessList* this);
-void ProcessList_rebuildPanel(ProcessList* this);
+extern void ProcessList_rebuildPanel(ProcessList* this);
-Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_New constructor);
+extern Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_New constructor);
-void ProcessList_scan(ProcessList* this);
+extern void ProcessList_scan(ProcessList* this);
#endif
diff --git a/README b/README
index 33a8739e..5e657546 100644
--- a/README
+++ b/README
@@ -1,46 +1,28 @@
-[![Build Status](https://travis-ci.org/hishamhm/htop.svg?branch=master)](https://travis-ci.org/hishamhm/htop)
-[![PayPal donate](https://img.shields.io/badge/paypal-donate-green.svg)](http://hisham.hm/htop/index.php?page=donate)
+![htop](https://htop.dev)
-[htop](http://hisham.hm/htop/)
-====
-
-by Hisham Muhammad <hisham@gobolinux.org> (2004 - 2016)
+[![CI](https://github.com/htop-dev/htop/workflows/CI/badge.svg)](https://github.com/htop-dev/htop/actions)
+[![Coverity Scan Build Status](https://scan.coverity.com/projects/21617/badge.svg)](https://scan.coverity.com/projects/21617)
+[![Mailing List](https://img.shields.io/badge/Mailing%20List-htop-blue.svg)](https://groups.io/g/htop)
+[![IRC #htop](https://img.shields.io/badge/IRC-htop-blue.svg)](https://webchat.freenode.net/#htop)
+[![Github Release](https://img.shields.io/github/release/htop-dev/htop.svg)](https://github.com/htop-dev/htop/releases/latest)
Introduction
------------
-This is `htop`, an interactive process viewer.
-It requires `ncurses`. It is developed primarily on Linux,
-but we also have code for running under FreeBSD and Mac OS X
-(help and testing are wanted for these platforms!)
-
-This software has evolved considerably over the years,
-and is reasonably complete, but there is always room for improvement.
-
-Comparison between `htop` and classic `top`
--------------------------------------------
-
-* In `htop` you can scroll the list vertically and horizontally
- to see all processes and full command lines.
-* In `top` you are subject to a delay for each unassigned
- key you press (especially annoying when multi-key escape
- sequences are triggered by accident).
-* `htop` starts faster (`top` seems to collect data for a while
- before displaying anything).
-* In `htop` you don't need to type the process number to
- kill a process, in `top` you do.
-* In `htop` you don't need to type the process number or
- the priority value to renice a process, in `top` you do.
-* In `htop` you can kill multiple processes at once.
-* `top` is older, hence, more tested.
-
-Compilation instructions
-------------------------
+`htop` is a cross-platform interactive process viewer.
+It requires `ncurses`.
+
+For more information and details on how to contribute to `htop`
+visit [htop.dev](https://htop.dev).
+
+Build instructions
+------------------
This program is distributed as a standard autotools-based package.
-See the [INSTALL](/INSTALL) file for detailed instructions.
+For detailed instructions see the [INSTALL](/INSTALL) file, which
+is created after `./autogen.sh` is run.
-When compiling from a [release tarball](https://hisham.hm/htop/releases/), run:
+When compiling from a [release tarball](https://github.com/htop-dev/htop/releases/), run:
./configure && make
@@ -54,8 +36,6 @@ the path use `./configure --prefix=/some/path`.
See the manual page (`man htop`) or the on-line help ('F1' or 'h'
inside `htop`) for a list of supported key commands.
-If not all keys work check your curses configuration.
-
## License
GNU General Public License, version 2 (GPL-2.0)
diff --git a/RichString.c b/RichString.c
index 370566a8..d246f1e1 100644
--- a/RichString.c
+++ b/RichString.c
@@ -67,7 +67,7 @@ typedef struct RichString_ {
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
-#define charBytes(n) (sizeof(CharType) * (n))
+#define charBytes(n) (sizeof(CharType) * (n))
static void RichString_extendLen(RichString* this, int len) {
if (this->chlen <= RICHSTRING_MAXLEN) {
diff --git a/RichString.h b/RichString.h
index f5b5cba1..d6fa6354 100644
--- a/RichString.h
+++ b/RichString.h
@@ -63,7 +63,7 @@ typedef struct RichString_ {
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
-#define charBytes(n) (sizeof(CharType) * (n))
+#define charBytes(n) (sizeof(CharType) * (n))
#define RichString_setLen(this, len) do{ if(len < RICHSTRING_MAXLEN && this->chlen < RICHSTRING_MAXLEN) { RichString_setChar(this,len,0); this->chlen=len; } else RichString_extendLen(this,len); }while(0)
@@ -71,24 +71,24 @@ typedef struct RichString_ {
extern void RichString_setAttrn(RichString* this, int attrs, int start, int finish);
-int RichString_findChar(RichString* this, char c, int start);
+extern int RichString_findChar(RichString* this, char c, int start);
#else
-void RichString_setAttrn(RichString* this, int attrs, int start, int finish);
+extern void RichString_setAttrn(RichString* this, int attrs, int start, int finish);
-int RichString_findChar(RichString* this, char c, int start);
+extern int RichString_findChar(RichString* this, char c, int start);
#endif
-void RichString_prune(RichString* this);
+extern void RichString_prune(RichString* this);
-void RichString_setAttr(RichString* this, int attrs);
+extern void RichString_setAttr(RichString* this, int attrs);
-void RichString_append(RichString* this, int attrs, const char* data);
+extern void RichString_append(RichString* this, int attrs, const char* data);
-void RichString_appendn(RichString* this, int attrs, const char* data, int len);
+extern void RichString_appendn(RichString* this, int attrs, const char* data, int len);
-void RichString_write(RichString* this, int attrs, const char* data);
+extern void RichString_write(RichString* this, int attrs, const char* data);
#endif
diff --git a/ScreenManager.c b/ScreenManager.c
index 06e90193..8e5f697f 100644
--- a/ScreenManager.c
+++ b/ScreenManager.c
@@ -163,7 +163,7 @@ static Panel* setCurrentPanel(Panel* panel) {
void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
bool quit = false;
int focus = 0;
-
+
Panel* panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus));
double oldTime = 0.0;
@@ -181,7 +181,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
if (this->header) {
checkRecalculation(this, &oldTime, &sortTimeout, &redraw, &rescan, &timedOut);
}
-
+
if (redraw) {
ScreenManager_drawPanels(this, focus);
}
@@ -190,8 +190,24 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
set_escdelay(25);
ch = getch();
+ if (this->settings->vimMode) {
+ switch (ch) {
+ case 'h': ch = KEY_LEFT; break;
+ case 'j': ch = KEY_DOWN; break;
+ case 'k': ch = KEY_UP; break;
+ case 'l': ch = KEY_RIGHT; break;
+ case KEY_LEFT: ch = 'h'; break;
+ case KEY_DOWN: ch = 'j'; break;
+ case KEY_UP: ch = 'k'; break;
+ case KEY_RIGHT: ch = 'l'; break;
+ case 'K': ch = 'k'; break;
+ case 'J': ch = 'K'; break;
+ case 'L': ch = 'l'; break;
+ }
+ }
+
HandlerResult result = IGNORED;
- if (ch == KEY_MOUSE) {
+ if (ch == KEY_MOUSE && this->settings->enableMouse) {
ch = ERR;
MEVENT mevent;
int ok = getmouse(&mevent);
@@ -269,7 +285,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
quit = true;
continue;
}
-
+
switch (ch) {
case KEY_RESIZE:
{
diff --git a/ScreenManager.h b/ScreenManager.h
index 3d02a883..b7b5617b 100644
--- a/ScreenManager.h
+++ b/ScreenManager.h
@@ -35,18 +35,18 @@ typedef struct ScreenManager_ {
} ScreenManager;
-ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, const Header* header, const Settings* settings, bool owner);
+extern ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, const Header* header, const Settings* settings, bool owner);
-void ScreenManager_delete(ScreenManager* this);
+extern void ScreenManager_delete(ScreenManager* this);
extern int ScreenManager_size(ScreenManager* this);
-void ScreenManager_add(ScreenManager* this, Panel* item, int size);
+extern void ScreenManager_add(ScreenManager* this, Panel* item, int size);
-Panel* ScreenManager_remove(ScreenManager* this, int idx);
+extern Panel* ScreenManager_remove(ScreenManager* this, int idx);
-void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2);
+extern void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2);
-void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey);
+extern void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey);
#endif
diff --git a/Settings.c b/Settings.c
index db2fa066..6197241f 100644
--- a/Settings.c
+++ b/Settings.c
@@ -31,7 +31,7 @@ typedef struct {
typedef struct Settings_ {
char* filename;
-
+
MeterColumnSettings columns[2];
ProcessField* fields;
@@ -45,6 +45,8 @@ typedef struct Settings_ {
bool countCPUsFromZero;
bool detailedCPUTime;
+ bool showCPUUsage;
+ bool showCPUFrequency;
bool treeView;
bool showProgramPath;
bool hideThreads;
@@ -58,6 +60,8 @@ typedef struct Settings_ {
bool updateProcessNames;
bool accountGuestInCPUMeter;
bool headerMargin;
+ bool enableMouse;
+ bool vimMode;
bool changed;
} Settings;
@@ -114,7 +118,7 @@ static void Settings_defaultMeters(Settings* this) {
this->columns[i].modes = xCalloc(sizes[i], sizeof(int));
this->columns[i].len = sizes[i];
}
-
+
int r = 0;
if (this->cpuCount > 8) {
this->columns[0].names[0] = xStrdup("LeftCPUs2");
@@ -134,7 +138,7 @@ static void Settings_defaultMeters(Settings* this) {
this->columns[0].modes[1] = BAR_METERMODE;
this->columns[0].names[2] = xStrdup("Swap");
this->columns[0].modes[2] = BAR_METERMODE;
-
+
this->columns[1].names[r] = xStrdup("Tasks");
this->columns[1].modes[r++] = TEXT_METERMODE;
this->columns[1].names[r] = xStrdup("LoadAverage");
@@ -165,13 +169,13 @@ static void readFields(ProcessField* fields, int* flags, const char* line) {
static bool Settings_read(Settings* this, const char* fileName) {
FILE* fd;
-
+
CRT_dropPrivileges();
fd = fopen(fileName, "r");
CRT_restorePrivileges();
if (!fd)
return false;
-
+
bool didReadMeters = false;
bool didReadFields = false;
for (;;) {
@@ -223,6 +227,10 @@ static bool Settings_read(Settings* this, const char* fileName) {
this->detailedCPUTime = atoi(option[1]);
} else if (String_eq(option[0], "cpu_count_from_zero")) {
this->countCPUsFromZero = atoi(option[1]);
+ } else if (String_eq(option[0], "show_cpu_usage")) {
+ this->showCPUUsage = atoi(option[1]);
+ } else if (String_eq(option[0], "show_cpu_frequency")) {
+ this->showCPUFrequency = atoi(option[1]);
} else if (String_eq(option[0], "update_process_names")) {
this->updateProcessNames = atoi(option[1]);
} else if (String_eq(option[0], "account_guest_in_cpu_meter")) {
@@ -232,6 +240,8 @@ static bool Settings_read(Settings* this, const char* fileName) {
} else if (String_eq(option[0], "color_scheme")) {
this->colorScheme = atoi(option[1]);
if (this->colorScheme < 0 || this->colorScheme >= LAST_COLORSCHEME) this->colorScheme = 0;
+ } else if (String_eq(option[0], "enable_mouse")) {
+ this->enableMouse = atoi(option[1]);
} else if (String_eq(option[0], "left_meters")) {
Settings_readMeters(this, option[1], 0);
didReadMeters = true;
@@ -244,6 +254,8 @@ static bool Settings_read(Settings* this, const char* fileName) {
} else if (String_eq(option[0], "right_meter_modes")) {
Settings_readMeterModes(this, option[1], 1);
didReadMeters = true;
+ } else if (String_eq(option[0], "vim_mode")) {
+ this->vimMode = atoi(option[1]);
}
String_freeArray(option);
}
@@ -312,20 +324,24 @@ bool Settings_write(Settings* this) {
fprintf(fd, "header_margin=%d\n", (int) this->headerMargin);
fprintf(fd, "detailed_cpu_time=%d\n", (int) this->detailedCPUTime);
fprintf(fd, "cpu_count_from_zero=%d\n", (int) this->countCPUsFromZero);
+ fprintf(fd, "show_cpu_usage=%d\n", (int) this->showCPUUsage);
+ fprintf(fd, "show_cpu_frequency=%d\n", (int) this->showCPUFrequency);
fprintf(fd, "update_process_names=%d\n", (int) this->updateProcessNames);
fprintf(fd, "account_guest_in_cpu_meter=%d\n", (int) this->accountGuestInCPUMeter);
fprintf(fd, "color_scheme=%d\n", (int) this->colorScheme);
+ fprintf(fd, "enable_mouse=%d\n", (int) this->enableMouse);
fprintf(fd, "delay=%d\n", (int) this->delay);
fprintf(fd, "left_meters="); writeMeters(this, fd, 0);
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, "vim_mode=%d\n", (int) this->vimMode);
fclose(fd);
return true;
}
Settings* Settings_new(int cpuCount) {
-
+
Settings* this = xCalloc(1, sizeof(Settings));
this->sortKey = PERCENT_CPU;
@@ -340,11 +356,13 @@ Settings* Settings_new(int cpuCount) {
this->highlightMegabytes = false;
this->detailedCPUTime = false;
this->countCPUsFromZero = false;
+ this->showCPUUsage = true;
+ this->showCPUFrequency = false;
this->updateProcessNames = false;
this->cpuCount = cpuCount;
this->showProgramPath = true;
this->highlightThreads = true;
-
+
this->fields = xCalloc(Platform_numberOfFields+1, sizeof(ProcessField));
// TODO: turn 'fields' into a Vector,
// (and ProcessFields into proper objects).
@@ -375,7 +393,7 @@ Settings* Settings_new(int cpuCount) {
htopDir = String_cat(home, "/.config/htop");
}
legacyDotfile = String_cat(home, "/.htoprc");
-
+
CRT_dropPrivileges();
(void) mkdir(configDir, 0700);
(void) mkdir(htopDir, 0700);
@@ -390,6 +408,7 @@ Settings* Settings_new(int cpuCount) {
CRT_restorePrivileges();
}
this->colorScheme = 0;
+ this->enableMouse = true;
this->changed = false;
this->delay = DEFAULT_DELAY;
bool ok = false;
diff --git a/Settings.h b/Settings.h
index d9dc0683..89300951 100644
--- a/Settings.h
+++ b/Settings.h
@@ -22,7 +22,7 @@ typedef struct {
typedef struct Settings_ {
char* filename;
-
+
MeterColumnSettings columns[2];
ProcessField* fields;
@@ -36,6 +36,8 @@ typedef struct Settings_ {
bool countCPUsFromZero;
bool detailedCPUTime;
+ bool showCPUUsage;
+ bool showCPUFrequency;
bool treeView;
bool showProgramPath;
bool hideThreads;
@@ -49,6 +51,8 @@ typedef struct Settings_ {
bool updateProcessNames;
bool accountGuestInCPUMeter;
bool headerMargin;
+ bool enableMouse;
+ bool vimMode;
bool changed;
} Settings;
@@ -58,12 +62,12 @@ typedef struct Settings_ {
#endif
-void Settings_delete(Settings* this);
+extern void Settings_delete(Settings* this);
-bool Settings_write(Settings* this);
+extern bool Settings_write(Settings* this);
-Settings* Settings_new(int cpuCount);
+extern Settings* Settings_new(int cpuCount);
-void Settings_invertSortOrder(Settings* this);
+extern void Settings_invertSortOrder(Settings* this);
#endif
diff --git a/SignalsPanel.h b/SignalsPanel.h
index da753546..8720376a 100644
--- a/SignalsPanel.h
+++ b/SignalsPanel.h
@@ -16,6 +16,6 @@ typedef struct SignalItem_ {
} SignalItem;
-Panel* SignalsPanel_new();
+extern Panel* SignalsPanel_new();
#endif
diff --git a/StringUtils.c b/StringUtils.c
index 0578cdea..0ac54b12 100644
--- a/StringUtils.c
+++ b/StringUtils.c
@@ -30,8 +30,9 @@ char* String_cat(const char* s1, const char* s2) {
int l1 = strlen(s1);
int l2 = strlen(s2);
char* out = xMalloc(l1 + l2 + 1);
- strncpy(out, s1, l1);
- strncpy(out+l1, s2, l2+1);
+ memcpy(out, s1, l1);
+ memcpy(out+l1, s2, l2+1);
+ out[l1 + l2] = '\0';
return out;
}
@@ -116,7 +117,7 @@ char* String_getToken(const char* line, const unsigned short int numMatch) {
if (lastState == 0 && inWord == 1)
count++;
-
+
if(inWord == 1){
if (count == numMatch && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != (char)EOF) {
match[foundCount] = line[i];
diff --git a/StringUtils.h b/StringUtils.h
index d3378b38..c1070d4f 100644
--- a/StringUtils.h
+++ b/StringUtils.h
@@ -19,18 +19,18 @@ in the source distribution for its full text.
* at compile time (e.g. when they are immutable string literals). :)
*/
-char* String_cat(const char* s1, const char* s2);
+extern char* String_cat(const char* s1, const char* s2);
-char* String_trim(const char* in);
+extern char* String_trim(const char* in);
extern int String_eq(const char* s1, const char* s2);
-char** String_split(const char* s, char sep, int* n);
+extern char** String_split(const char* s, char sep, int* n);
-void String_freeArray(char** s);
+extern void String_freeArray(char** s);
-char* String_getToken(const char* line, const unsigned short int numMatch);
+extern char* String_getToken(const char* line, const unsigned short int numMatch);
-char* String_readLine(FILE* fd);
+extern char* String_readLine(FILE* fd);
#endif
diff --git a/TasksMeter.c b/TasksMeter.c
index f56c8613..8a913ec0 100644
--- a/TasksMeter.c
+++ b/TasksMeter.c
@@ -15,7 +15,7 @@ in the source distribution for its full text.
}*/
int TasksMeter_attributes[] = {
- CPU_KERNEL, PROCESS_THREAD, PROCESS, TASKS_RUNNING
+ CPU_SYSTEM, PROCESS_THREAD, PROCESS, TASKS_RUNNING
};
static void TasksMeter_updateValues(Meter* this, char* buffer, int len) {
@@ -37,9 +37,9 @@ static void TasksMeter_display(Object* cast, RichString* out) {
Meter* this = (Meter*)cast;
Settings* settings = this->pl->settings;
char buffer[20];
-
+
int processes = (int) this->values[2];
-
+
xSnprintf(buffer, sizeof(buffer), "%d", processes);
RichString_write(out, CRT_colors[METER_VALUE], buffer);
int threadValueColor = CRT_colors[METER_VALUE];
@@ -76,7 +76,7 @@ MeterClass TasksMeter_class = {
.defaultMode = TEXT_METERMODE,
.maxItems = 4,
.total = 100.0,
- .attributes = TasksMeter_attributes,
+ .attributes = TasksMeter_attributes,
.name = "Tasks",
.uiName = "Task counter",
.caption = "Tasks: "
diff --git a/TraceScreen.c b/TraceScreen.c
index 91f71ae8..b4b8436b 100644
--- a/TraceScreen.c
+++ b/TraceScreen.c
@@ -101,7 +101,7 @@ bool TraceScreen_forkTracer(TraceScreen* this) {
int ok = fcntl(this->fdpair[1], F_SETFL, O_NONBLOCK);
if (ok != -1) {
xSnprintf(buffer, sizeof(buffer), "%d", this->super.process->pid);
- execlp("strace", "strace", "-s", "512", "-p", buffer, NULL);
+ execlp("strace", "strace", "-T", "-tt", "-s", "512", "-p", buffer, NULL);
}
const char* message = "Could not execute 'strace'. Please make sure it is available in your $PATH.";
ssize_t written = write(this->fdpair[1], message, strlen(message));
diff --git a/TraceScreen.h b/TraceScreen.h
index 8845c51a..d43281d9 100644
--- a/TraceScreen.h
+++ b/TraceScreen.h
@@ -25,16 +25,16 @@ typedef struct TraceScreen_ {
extern InfoScreenClass TraceScreen_class;
-TraceScreen* TraceScreen_new(Process* process);
+extern TraceScreen* TraceScreen_new(Process* process);
-void TraceScreen_delete(Object* cast);
+extern void TraceScreen_delete(Object* cast);
-void TraceScreen_draw(InfoScreen* this);
+extern void TraceScreen_draw(InfoScreen* this);
-bool TraceScreen_forkTracer(TraceScreen* this);
+extern bool TraceScreen_forkTracer(TraceScreen* this);
-void TraceScreen_updateTrace(InfoScreen* super);
+extern void TraceScreen_updateTrace(InfoScreen* super);
-bool TraceScreen_onKey(InfoScreen* super, int ch);
+extern bool TraceScreen_onKey(InfoScreen* super, int ch);
#endif
diff --git a/UsersTable.h b/UsersTable.h
index 93ece0dc..9eba59ad 100644
--- a/UsersTable.h
+++ b/UsersTable.h
@@ -15,11 +15,11 @@ typedef struct UsersTable_ {
Hashtable* users;
} UsersTable;
-UsersTable* UsersTable_new();
+extern UsersTable* UsersTable_new();
-void UsersTable_delete(UsersTable* this);
+extern void UsersTable_delete(UsersTable* this);
-char* UsersTable_getRef(UsersTable* this, unsigned int uid);
+extern char* UsersTable_getRef(UsersTable* this, unsigned int uid);
extern void UsersTable_foreach(UsersTable* this, Hashtable_PairFunction f, void* userData);
diff --git a/Vector.c b/Vector.c
index 6eb91ae6..819d9863 100644
--- a/Vector.c
+++ b/Vector.c
@@ -195,7 +195,7 @@ void Vector_insert(Vector* this, int idx, void* data_) {
if (idx > this->items) {
idx = this->items;
}
-
+
Vector_checkArraySize(this);
//assert(this->array[this->items] == NULL);
for (int i = this->items; i > idx; i--) {
@@ -302,7 +302,7 @@ inline int Vector_size(Vector* this) {
static void Vector_merge(Vector* this, Vector* v2) {
int i;
assert(Vector_isConsistent(this));
-
+
for (i = 0; i < v2->items; i++)
Vector_add(this, v2->array[i]);
v2->items = 0;
diff --git a/Vector.h b/Vector.h
index 85939bf1..b48c8363 100644
--- a/Vector.h
+++ b/Vector.h
@@ -27,38 +27,38 @@ typedef struct Vector_ {
} Vector;
-Vector* Vector_new(ObjectClass* type, bool owner, int size);
+extern Vector* Vector_new(ObjectClass* type, bool owner, int size);
-void Vector_delete(Vector* this);
+extern void Vector_delete(Vector* this);
#ifdef DEBUG
-int Vector_count(Vector* this);
+extern int Vector_count(Vector* this);
#endif
-void Vector_prune(Vector* this);
+extern void Vector_prune(Vector* this);
// If I were to use only one sorting algorithm for both cases, it would probably be this one:
/*
*/
-void Vector_quickSort(Vector* this);
+extern void Vector_quickSort(Vector* this);
-void Vector_insertionSort(Vector* this);
+extern void Vector_insertionSort(Vector* this);
-void Vector_insert(Vector* this, int idx, void* data_);
+extern void Vector_insert(Vector* this, int idx, void* data_);
-Object* Vector_take(Vector* this, int idx);
+extern Object* Vector_take(Vector* this, int idx);
-Object* Vector_remove(Vector* this, int idx);
+extern Object* Vector_remove(Vector* this, int idx);
-void Vector_moveUp(Vector* this, int idx);
+extern void Vector_moveUp(Vector* this, int idx);
-void Vector_moveDown(Vector* this, int idx);
+extern void Vector_moveDown(Vector* this, int idx);
-void Vector_set(Vector* this, int idx, void* data_);
+extern void Vector_set(Vector* this, int idx, void* data_);
#ifdef DEBUG
@@ -84,7 +84,7 @@ extern int Vector_size(Vector* this);
*/
-void Vector_add(Vector* this, void* data_);
+extern void Vector_add(Vector* this, void* data_);
extern int Vector_indexOf(Vector* this, void* search_, Object_Compare compare);
diff --git a/XAlloc.h b/XAlloc.h
index 2ebee1a8..97a1c0d0 100644
--- a/XAlloc.h
+++ b/XAlloc.h
@@ -11,11 +11,11 @@
#include <assert.h>
#include <stdlib.h>
-void* xMalloc(size_t size);
+extern void* xMalloc(size_t size);
-void* xCalloc(size_t nmemb, size_t size);
+extern void* xCalloc(size_t nmemb, size_t size);
-void* xRealloc(void* ptr, size_t size);
+extern void* xRealloc(void* ptr, size_t size);
#define xSnprintf(fmt, len, ...) do { int _l=len; int _n=snprintf(fmt, _l, __VA_ARGS__); if (!(_n > -1 && _n < _l)) { curs_set(1); endwin(); err(1, NULL); } } while(0)
@@ -32,9 +32,9 @@ void* xRealloc(void* ptr, size_t size);
#endif
#if (__has_attribute(nonnull) || \
((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)))
-char* xStrdup_(const char* str) __attribute__((nonnull));
+extern char* xStrdup_(const char* str) __attribute__((nonnull));
#endif // __has_attribute(nonnull) || GNU C 3.3 or later
-char* xStrdup_(const char* str);
+extern char* xStrdup_(const char* str);
#endif
diff --git a/configure.ac b/configure.ac
index ffd8fede..71a4f799 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,10 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.65)
-AC_INIT([htop],[2.2.0],[hisham@gobolinux.org])
-
-SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(date +%s)}"
-year=$(date -u -d "@$SOURCE_DATE_EPOCH" "+%Y" 2>/dev/null || date -u -r "$SOURCE_DATE_EPOCH" "+%Y" 2>/dev/null || date -u "+%Y")
+AC_INIT([htop],[3.0.0],[htop@groups.io])
AC_CONFIG_SRCDIR([htop.c])
AC_CONFIG_AUX_DIR([.])
@@ -69,7 +66,7 @@ dnl glibc 2.25 deprecates 'major' and 'minor' in <sys/types.h> and requires to
dnl include <sys/sysmacros.h>. However the logic in AC_HEADER_MAJOR has not yet
dnl been updated in Autoconf 2.69, so use a workaround:
m4_version_prereq([2.70], [],
-[if test "x$ac_cv_header_sys_mkdev_h" = xno; then
+[if test "x$ac_cv_header_sys_mkdev_h" != xyes; then
AC_CHECK_HEADER(sys/sysmacros.h, [AC_DEFINE(MAJOR_IN_SYSMACROS, 1,
[Define to 1 if `major', `minor', and `makedev' are declared in <sys/sysmacros.h>.])])
fi])
@@ -308,7 +305,7 @@ if test ! -z "$missing_headers"; then
AC_MSG_ERROR([missing headers: $missing_headers])
fi
-AC_DEFINE_UNQUOTED(COPYRIGHT, "(C) 2004-$year Hisham Muhammad", [Copyright message.])
+AC_DEFINE_UNQUOTED(COPYRIGHT, "(C) 2004-2018 Hisham Muhammad", [Copyright message.])
# We're done, let's go!
# ----------------------------------------------------------------------
diff --git a/darwin/DarwinProcess.c b/darwin/DarwinProcess.c
index e1a16f9c..bf5fd577 100644
--- a/darwin/DarwinProcess.c
+++ b/darwin/DarwinProcess.c
@@ -212,7 +212,7 @@ ERROR_B:
ERROR_A:
retval = xStrdup(k->kp_proc.p_comm);
*basenameOffset = strlen(retval);
-
+
return retval;
}
@@ -302,11 +302,11 @@ void DarwinProcess_setFromLibprocPidinfo(DarwinProcess *proc, DarwinProcessList
void DarwinProcess_scanThreads(DarwinProcess *dp) {
Process* proc = (Process*) dp;
kern_return_t ret;
-
+
if (!dp->taskAccess) {
return;
}
-
+
if (proc->state == 'Z') {
return;
}
@@ -317,7 +317,7 @@ void DarwinProcess_scanThreads(DarwinProcess *dp) {
dp->taskAccess = false;
return;
}
-
+
task_info_data_t tinfo;
mach_msg_type_number_t task_info_count = TASK_INFO_MAX;
ret = task_info(port, TASK_BASIC_INFO, (task_info_t) tinfo, &task_info_count);
@@ -325,7 +325,7 @@ void DarwinProcess_scanThreads(DarwinProcess *dp) {
dp->taskAccess = false;
return;
}
-
+
thread_array_t thread_list;
mach_msg_type_number_t thread_count;
ret = task_threads(port, &thread_list, &thread_count);
@@ -334,7 +334,7 @@ void DarwinProcess_scanThreads(DarwinProcess *dp) {
mach_port_deallocate(mach_task_self(), port);
return;
}
-
+
integer_t run_state = 999;
for (unsigned int i = 0; i < thread_count; i++) {
thread_info_data_t thinfo;
diff --git a/darwin/Platform.c b/darwin/Platform.c
index 286ff16b..26e84112 100644
--- a/darwin/Platform.c
+++ b/darwin/Platform.c
@@ -92,7 +92,7 @@ ProcessFieldData Process_fields[] = {
[PROCESSOR] = { .name = "PROCESSOR", .title = "CPU ", .description = "Id of the CPU the process last executed on", .flags = 0, },
[M_SIZE] = { .name = "M_SIZE", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, },
[M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, },
- [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
+ [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
[PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, },
[PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, },
[USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
@@ -221,6 +221,8 @@ double Platform_setCPUValues(Meter* mtr, int cpu) {
/* Convert to percent and return */
total = mtr->values[CPU_METER_NICE] + mtr->values[CPU_METER_NORMAL] + mtr->values[CPU_METER_KERNEL];
+ mtr->values[CPU_METER_FREQUENCY] = -1;
+
return CLAMP(total, 0.0, 100.0);
}
diff --git a/dragonflybsd/DragonFlyBSDProcess.c b/dragonflybsd/DragonFlyBSDProcess.c
index dade106d..ffaf5eb6 100644
--- a/dragonflybsd/DragonFlyBSDProcess.c
+++ b/dragonflybsd/DragonFlyBSDProcess.c
@@ -74,7 +74,7 @@ ProcessFieldData Process_fields[] = {
[PROCESSOR] = { .name = "PROCESSOR", .title = "CPU ", .description = "Id of the CPU the process last executed on", .flags = 0, },
[M_SIZE] = { .name = "M_SIZE", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, },
[M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, },
- [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
+ [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
[PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, },
[PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, },
[USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
@@ -121,7 +121,7 @@ void DragonFlyBSDProcess_writeField(Process* this, RichString* str, ProcessField
case PID: xSnprintf(buffer, n, Process_pidFormat, (fp->kernel ? -1 : this->pid)); break;
case JID: xSnprintf(buffer, n, Process_pidFormat, fp->jid); break;
case JAIL:{
- xSnprintf(buffer, n, "%-11s ", fp->jname); break;
+ xSnprintf(buffer, n, "%-11s ", fp->jname);
if (buffer[11] != '\0') {
buffer[11] = ' ';
buffer[12] = '\0';
diff --git a/dragonflybsd/DragonFlyBSDProcessList.c b/dragonflybsd/DragonFlyBSDProcessList.c
index a41af854..5bc4b384 100644
--- a/dragonflybsd/DragonFlyBSDProcessList.c
+++ b/dragonflybsd/DragonFlyBSDProcessList.c
@@ -565,7 +565,7 @@ void ProcessList_goThroughEntries(ProcessList* this) {
if (kproc->kp_flags & P_JAILED) {
proc->state = 'J';
}
-
+
if (Process_isKernelThread(dfp)) {
this->kernelThreads++;
}
diff --git a/dragonflybsd/Platform.c b/dragonflybsd/Platform.c
index 370943d7..250e50e7 100644
--- a/dragonflybsd/Platform.c
+++ b/dragonflybsd/Platform.c
@@ -179,6 +179,9 @@ double Platform_setCPUValues(Meter* this, int cpu) {
percent = CLAMP(percent, 0.0, 100.0);
if (isnan(percent)) percent = 0.0;
+
+ v[CPU_METER_FREQUENCY] = -1;
+
return percent;
}
diff --git a/freebsd/FreeBSDProcess.c b/freebsd/FreeBSDProcess.c
index f81fadf5..c8d30f69 100644
--- a/freebsd/FreeBSDProcess.c
+++ b/freebsd/FreeBSDProcess.c
@@ -73,7 +73,7 @@ ProcessFieldData Process_fields[] = {
[PROCESSOR] = { .name = "PROCESSOR", .title = "CPU ", .description = "Id of the CPU the process last executed on", .flags = 0, },
[M_SIZE] = { .name = "M_SIZE", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, },
[M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, },
- [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
+ [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
[PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, },
[PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, },
[USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
@@ -119,7 +119,7 @@ void FreeBSDProcess_writeField(Process* this, RichString* str, ProcessField fiel
// add FreeBSD-specific fields here
case JID: xSnprintf(buffer, n, Process_pidFormat, fp->jid); break;
case JAIL:{
- xSnprintf(buffer, n, "%-11s ", fp->jname); break;
+ xSnprintf(buffer, n, "%-11s ", fp->jname);
if (buffer[11] != '\0') {
buffer[11] = ' ';
buffer[12] = '\0';
diff --git a/freebsd/FreeBSDProcessList.c b/freebsd/FreeBSDProcessList.c
index fd694198..7bc42db6 100644
--- a/freebsd/FreeBSDProcessList.c
+++ b/freebsd/FreeBSDProcessList.c
@@ -20,6 +20,7 @@ in the source distribution for its full text.
#include <fcntl.h>
#include <limits.h>
#include <string.h>
+#include <time.h>
/*{
@@ -289,26 +290,51 @@ static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) {
//
// htop_used = active + (wired - arc)
// htop_cache = buffers + cache + arc
- size_t len = sizeof(pl->totalMem);
+ u_long totalMem;
+ u_int memActive, memWire, cachedMem;
+ long buffersMem;
+ uint64_t memZfsArc;
+ size_t len;
//disabled for now, as it is always smaller than phycal amount of memory...
//...to avoid "where is my memory?" questions
//sysctl(MIB_vm_stats_vm_v_page_count, 4, &(pl->totalMem), &len, NULL, 0);
//pl->totalMem *= pageSizeKb;
- sysctl(MIB_hw_physmem, 2, &(pl->totalMem), &len, NULL, 0);
- pl->totalMem /= 1024;
-
- sysctl(MIB_vm_stats_vm_v_active_count, 4, &(fpl->memActive), &len, NULL, 0);
- fpl->memActive *= pageSizeKb;
-
- sysctl(MIB_vm_stats_vm_v_wire_count, 4, &(fpl->memWire), &len, NULL, 0);
- fpl->memWire *= pageSizeKb;
-
- sysctl(MIB_vfs_bufspace, 2, &(pl->buffersMem), &len, NULL, 0);
- pl->buffersMem /= 1024;
-
- sysctl(MIB_vm_stats_vm_v_cache_count, 4, &(pl->cachedMem), &len, NULL, 0);
- pl->cachedMem *= pageSizeKb;
+ len = sizeof(totalMem);
+ sysctl(MIB_hw_physmem, 2, &(totalMem), &len, NULL, 0);
+ totalMem /= 1024;
+ pl->totalMem = totalMem;
+
+ len = sizeof(memActive);
+ sysctl(MIB_vm_stats_vm_v_active_count, 4, &(memActive), &len, NULL, 0);
+ memActive *= pageSizeKb;
+ fpl->memActive = memActive;
+
+ len = sizeof(memWire);
+ sysctl(MIB_vm_stats_vm_v_wire_count, 4, &(memWire), &len, NULL, 0);
+ memWire *= pageSizeKb;
+ fpl->memWire = memWire;
+
+ len = sizeof(buffersMem);
+ sysctl(MIB_vfs_bufspace, 2, &(buffersMem), &len, NULL, 0);
+ buffersMem /= 1024;
+ pl->buffersMem = buffersMem;
+
+ len = sizeof(cachedMem);
+ sysctl(MIB_vm_stats_vm_v_cache_count, 4, &(cachedMem), &len, NULL, 0);
+ cachedMem *= pageSizeKb;
+ pl->cachedMem = cachedMem;
+
+ if (fpl->zfsArcEnabled) {
+ len = sizeof(memZfsArc);
+ sysctl(MIB_kstat_zfs_misc_arcstats_size, 5, &(memZfsArc), &len , NULL, 0);
+ memZfsArc /= 1024;
+ fpl->memZfsArc = memZfsArc;
+ fpl->memWire -= fpl->memZfsArc;
+ pl->cachedMem += fpl->memZfsArc;
+ // maybe when we learn how to make custom memory meter
+ // we could do custom arc breakdown?
+ }
if (fpl->zfs.enabled) {
fpl->memWire -= fpl->zfs.size;
@@ -418,10 +444,14 @@ void ProcessList_goThroughEntries(ProcessList* this) {
int count = 0;
struct kinfo_proc* kprocs = kvm_getprocs(fpl->kd, KERN_PROC_PROC, 0, &count);
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
for (int i = 0; i < count; i++) {
struct kinfo_proc* kproc = &kprocs[i];
bool preExisting = false;
bool isIdleProcess = false;
+ struct tm date;
Process* proc = ProcessList_getProcess(this, kproc->ki_pid, &preExisting, (Process_New) FreeBSDProcess_new);
FreeBSDProcess* fp = (FreeBSDProcess*) proc;
@@ -512,6 +542,9 @@ void ProcessList_goThroughEntries(ProcessList* this) {
this->kernelThreads++;
}
+ (void) localtime_r((time_t*) &proc->starttime_ctime, &date);
+ strftime(proc->starttime_show, 7, ((proc->starttime_ctime > tv.tv_sec - 86400) ? "%R " : "%b%d "), &date);
+
this->totalTasks++;
if (proc->state == 'R')
this->runningTasks++;
diff --git a/freebsd/Platform.c b/freebsd/Platform.c
index 0986a3dd..e6acebdb 100644
--- a/freebsd/Platform.c
+++ b/freebsd/Platform.c
@@ -182,6 +182,9 @@ double Platform_setCPUValues(Meter* this, int cpu) {
percent = CLAMP(percent, 0.0, 100.0);
if (isnan(percent)) percent = 0.0;
+
+ v[CPU_METER_FREQUENCY] = -1;
+
return percent;
}
diff --git a/htop.1.in b/htop.1.in
index 149b1465..c9e6e829 100644
--- a/htop.1.in
+++ b/htop.1.in
@@ -1,17 +1,22 @@
-.TH "HTOP" "1" "2015" "@PACKAGE_STRING@" "Utils"
+.TH "HTOP" "1" "2020" "@PACKAGE_STRING@" "User Commands"
.SH "NAME"
htop \- interactive process viewer
.SH "SYNOPSIS"
.LP
-.B htop [\fI\-dChustv\fR]
+.B htop
+.RB [ \-dChpustv ]
.SH "DESCRIPTION"
.LP
-Htop is a free (GPL) ncurses-based process viewer for Linux.
+.B htop
+is a cross-platform ncurses-based process viewer.
.LP
-It is similar to top, but allows you to scroll vertically and horizontally,
-so you can see all the processes running on the system, along with their full
-command lines, as well as viewing them as a process tree, selecting multiple
-processes and acting on them all at once.
+It is similar to
+.BR top ,
+but allows you to scroll vertically and horizontally, and interact using
+a pointing device (mouse).
+You can observe all processes running on the system, along with their
+command line arguments, as well as view them in a tree format, select
+multiple processes and acting on them all at once.
.LP
Tasks related to processes (killing, renicing) can be done without
entering their PIDs.
@@ -22,10 +27,14 @@ Mandatory arguments to long options are mandatory for short options too.
.LP
.TP
\fB\-d \-\-delay=DELAY\fR
-Delay between updates, in tenths of seconds
+Delay between updates, in tenths of seconds. If the delay value is
+less than 1 it is increased to 1, i.e. 1/10 second. If the delay value
+is greater than 100, it is decreased to 100, i.e. 10 seconds.
.TP
\fB\-C \-\-no-color \-\-no-colour\fR
-Start htop in monochrome mode
+Start
+.B htop
+in monochrome mode
.TP
\fB\-h \-\-help
Display a help message and exit
@@ -44,11 +53,10 @@ Output version information and exit
.TP
\fB\-t \-\-tree
Show processes in tree view
-.PP
-.br
.SH "INTERACTIVE COMMANDS"
.LP
-The following commands are supported while in htop:
+The following commands are supported while in
+.BR htop :
.LP
.TP 5
.B Up, Alt-k
@@ -194,14 +202,17 @@ Refresh: redraw screen and recalculate values.
.B Numbers
PID search: type in process ID and the selection highlight will be moved to it.
.PD
-
.SH "COLUMNS"
.LP
The following columns can display data about each process. A value of '\-' in
all the rows indicates that a column is unsupported on your system, or
-currently unimplemented in htop. The names below are the ones used in the
+currently unimplemented in
+.BR htop .
+The names below are the ones used in the
"Available Columns" section of the setup screen. If a different name is
-shown in htop's main screen, it is shown below in parenthesis.
+shown in
+.BR htop 's
+main screen, it is shown below in parenthesis.
.LP
.TP 5
.B Command
@@ -389,36 +400,44 @@ The percentage of time spent swapping in pages. Requires CAP_NET_ADMIN.
.TP
.B All other flags
Currently unsupported (always displays '-').
-
.SH "CONFIG FILE"
.LP
-By default htop reads its configuration from the XDG-compliant path
-~/.config/htop/htoprc -- the configuration file is overwritten by htop's
-in-program Setup configuration, so it should not be hand-edited. If no
-user configuration exists htop tries to read the system-wide configuration
-from @sysconfdir@/htoprc and as a last resort, falls back to its
-hard coded defaults.
+By default
+.B htop
+reads its configuration from the XDG-compliant path
+.IR ~/.config/htop/htoprc .
+The configuration file is overwritten by
+.BR htop 's
+in-program Setup configuration, so it should not be hand-edited.
+If no user configuration exists
+.B htop
+tries to read the system-wide configuration from
+.I @sysconfdir@/htoprc
+and as a last resort, falls back to its hard coded defaults.
.LP
You may override the location of the configuration file using the $HTOPRC
environment variable (so you can have multiple configurations for different
machines that share the same home directory, for example).
-
.SH "MEMORY SIZES"
.LP
-Memory sizes in htop are displayed as they are in tools from the GNU Coreutils
-(when ran with the --human-readable option). This means that sizes are printed
-in powers of 1024. (e.g., 1023M = 1072693248 Bytes)
+Memory sizes in
+.B htop
+are displayed in a human-readable form.
+Sizes are printed in powers of 1024. (e.g., 1023M = 1072693248 Bytes)
.LP
-The decision to use this convention was made in order to conserve screen space
-and make memory size representations consistent throughout htop.
-
+The decision to use this convention was made in order to conserve screen
+space and make memory size representations consistent throughout
+.BR htop .
.SH "SEE ALSO"
-proc(5), top(1), free(1), ps(1), uptime(1), limits.conf(5)
-
+.BR proc (5),
+.BR top (1),
+.BR free (1),
+.BR ps (1),
+.BR uptime (1)
+and
+.BR limits.conf (5).
.SH "AUTHORS"
.LP
-htop is developed by Hisham Muhammad <hisham@gobolinux.org>.
-.LP
-This man page was written by Bartosz Fenski <fenio@o2.pl> for the Debian
-GNU/Linux distribution (but it may be used by others). It was updated by Hisham
-Muhammad, and later by Vincent Launchbury, who wrote the 'Columns' section.
+.B htop
+was originally developed by Hisham Muhammad.
+Nowadays it is maintained by the community at <htop@groups.io>.
diff --git a/htop.c b/htop.c
index 8c88c782..7cdf4e42 100644
--- a/htop.c
+++ b/htop.c
@@ -34,16 +34,17 @@ static void printVersionFlag() {
stdout);
exit(0);
}
-
+
static void printHelpFlag() {
fputs("htop " VERSION " - " COPYRIGHT "\n"
"Released under the GNU GPL.\n\n"
"-C --no-color Use a monochrome color scheme\n"
+ "-m --no-mouse Disable the mouse\n"
"-d --delay=DELAY Set the delay between updates, in tenths of seconds\n"
"-h --help Print this help screen\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"
- "-u --user=USERNAME Show only processes of a given user\n"
+ "-u --user[=USERNAME] Show only processes for a given user (or $USER)\n"
"-p --pid=PID,[,PID,PID...] Show only the given PIDs\n"
"-v --version Print version info\n"
"\n"
@@ -62,6 +63,7 @@ typedef struct CommandLineSettings_ {
int sortKey;
int delay;
bool useColors;
+ bool enableMouse;
bool treeView;
} CommandLineSettings;
@@ -73,6 +75,7 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
.sortKey = 0,
.delay = -1,
.useColors = true,
+ .enableMouse = true,
.treeView = false,
};
@@ -82,9 +85,10 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
{"version", no_argument, 0, 'v'},
{"delay", required_argument, 0, 'd'},
{"sort-key", required_argument, 0, 's'},
- {"user", required_argument, 0, 'u'},
+ {"user", optional_argument, 0, 'u'},
{"no-color", no_argument, 0, 'C'},
{"no-colour",no_argument, 0, 'C'},
+ {"no-mouse", no_argument, 0, 'm'},
{"tree", no_argument, 0, 't'},
{"pid", required_argument, 0, 'p'},
{0,0,0,0}
@@ -92,7 +96,7 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
int opt, opti=0;
/* Parse arguments */
- while ((opt = getopt_long(argc, argv, "hvCs:td:u:p:", long_opts, &opti))) {
+ while ((opt = getopt_long(argc, argv, "hvmCs:td:u::p:", long_opts, &opti))) {
if (opt == EOF) break;
switch (opt) {
case 'h':
@@ -112,6 +116,7 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
flags.sortKey = ColumnsPanel_fieldNameToIndex(optarg);
if (flags.sortKey == -1) {
fprintf(stderr, "Error: invalid column \"%s\".\n", optarg);
+ exit(1);
}
break;
case 'd':
@@ -120,16 +125,31 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
if (flags.delay > 100) flags.delay = 100;
} else {
fprintf(stderr, "Error: invalid delay value \"%s\".\n", optarg);
+ exit(1);
}
break;
case 'u':
+ if (!optarg && optind < argc && argv[optind] != NULL &&
+ (argv[optind][0] != '\0' && argv[optind][0] != '-')) {
+ optarg = argv[optind++];
+ }
+
+ if (!optarg) {
+ optarg = getenv("USER");
+ flags.userId = geteuid();
+ }
+
if (!Action_setUserOnly(optarg, &(flags.userId))) {
fprintf(stderr, "Error: invalid user \"%s\".\n", optarg);
+ exit(1);
}
break;
case 'C':
flags.useColors = false;
break;
+ case 'm':
+ flags.enableMouse = false;
+ break;
case 't':
flags.treeView = true;
break;
@@ -186,12 +206,12 @@ int main(int argc, char** argv) {
exit(1);
}
#endif
-
+
Process_setupColumnWidths();
-
+
UsersTable* ut = UsersTable_new();
ProcessList* pl = ProcessList_new(ut, flags.pidWhiteList, flags.userId);
-
+
Settings* settings = Settings_new(pl->cpuCount);
pl->settings = settings;
@@ -201,18 +221,20 @@ int main(int argc, char** argv) {
if (flags.delay != -1)
settings->delay = flags.delay;
- if (!flags.useColors)
+ if (!flags.useColors)
settings->colorScheme = COLORSCHEME_MONOCHROME;
+ if (!flags.enableMouse)
+ settings->enableMouse = false;
if (flags.treeView)
settings->treeView = true;
CRT_init(settings->delay, settings->colorScheme);
-
+
MainPanel* panel = MainPanel_new();
ProcessList_setPanel(pl, (Panel*) panel);
MainPanel_updateTreeFunctions(panel, settings->treeView);
-
+
if (flags.sortKey > 0) {
settings->sortKey = flags.sortKey;
settings->treeView = false;
@@ -228,7 +250,7 @@ int main(int argc, char** argv) {
.header = header,
};
MainPanel_setState(panel, &state);
-
+
ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, true);
ScreenManager_add(scr, (Panel*) panel, -1);
@@ -236,13 +258,13 @@ int main(int argc, char** argv) {
millisleep(75);
ProcessList_scan(pl);
- ScreenManager_run(scr, NULL, NULL);
-
+ ScreenManager_run(scr, NULL, NULL);
+
attron(CRT_colors[RESET_COLOR]);
mvhline(LINES-1, 0, ' ', COLS);
attroff(CRT_colors[RESET_COLOR]);
refresh();
-
+
CRT_done();
if (settings->changed)
Settings_write(settings);
@@ -250,10 +272,10 @@ int main(int argc, char** argv) {
ProcessList_delete(pl);
ScreenManager_delete(scr);
-
+
UsersTable_delete(ut);
Settings_delete(settings);
-
+
if(flags.pidWhiteList) {
Hashtable_delete(flags.pidWhiteList);
}
diff --git a/htop.desktop b/htop.desktop
index d59a2650..20bed490 100644
--- a/htop.desktop
+++ b/htop.desktop
@@ -4,6 +4,7 @@ Version=1.0
Name=Htop
GenericName=Process Viewer
GenericName[ca]=Visualitzador de processos
+GenericName[da]=Procesfremviser
GenericName[de]=Prozessanzeige
GenericName[en_GB]=Process Viewer
GenericName[es]=Visor de procesos
@@ -32,6 +33,7 @@ GenericName[zh_CN]=进程查看器
GenericName[zh_TW]=行程檢視器
Comment=Show System Processes
Comment[ca]=Visualitzeu els processos del sistema
+Comment[da]=Vis systemprocesser
Comment[de]=Systemprozesse anzeigen
Comment[en_GB]=Show System Processes
Comment[es]=Mostrar procesos del sistema
diff --git a/htop.h b/htop.h
index 7faa6c64..26c19180 100644
--- a/htop.h
+++ b/htop.h
@@ -14,6 +14,6 @@ in the source distribution for its full text.
// ----------------------------------------
-int main(int argc, char** argv);
+extern int main(int argc, char** argv);
#endif
diff --git a/linux/Battery.c b/linux/Battery.c
index aedacabc..7a1c8163 100644
--- a/linux/Battery.c
+++ b/linux/Battery.c
@@ -78,7 +78,7 @@ static unsigned long int parseBatInfo(const char *fileName, const unsigned short
const unsigned long int foundNum = atoi(foundNumStr);
free(foundNumStr);
free(line);
-
+
total += foundNum;
}
@@ -175,7 +175,7 @@ static inline ssize_t xread(int fd, void *buf, size_t count) {
}
static void Battery_getSysData(double* level, ACPresence* isOnAC) {
-
+
*level = 0;
*isOnAC = AC_ERROR;
@@ -193,8 +193,18 @@ static void Battery_getSysData(double* level, ACPresence* isOnAC) {
char* entryName = (char *) dirEntry->d_name;
const char filePath[50];
- if (entryName[0] == 'B' && entryName[1] == 'A' && entryName[2] == 'T') {
-
+ xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/type", entryName);
+ int fd = open(filePath, O_RDONLY);
+ if (fd == -1)
+ continue;
+
+ char type[8];
+ ssize_t typelen = xread(fd, type, 7);
+ close(fd);
+ if (typelen < 1)
+ continue;
+
+ if (type[0] == 'B' && type[1] == 'a' && type[2] == 't') {
xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/uevent", entryName);
int fd = open(filePath, O_RDONLY);
if (fd == -1) {
@@ -247,7 +257,7 @@ static void Battery_getSysData(double* level, ACPresence* isOnAC) {
if (*isOnAC != AC_ERROR) {
continue;
}
-
+
xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/online", entryName);
int fd = open(filePath, O_RDONLY);
if (fd == -1) {
diff --git a/linux/Battery.h b/linux/Battery.h
index cfb6c324..261cff05 100644
--- a/linux/Battery.h
+++ b/linux/Battery.h
@@ -29,6 +29,6 @@ Linux battery readings written by Ian P. Hands (iphands@gmail.com, ihands@redhat
// READ FROM /sys
// ----------------------------------------
-void Battery_getData(double* level, ACPresence* isOnAC);
+extern void Battery_getData(double* level, ACPresence* isOnAC);
#endif
diff --git a/linux/IOPriority.c b/linux/IOPriority.c
index dd7c84a1..80007df0 100644
--- a/linux/IOPriority.c
+++ b/linux/IOPriority.c
@@ -4,7 +4,7 @@ htop - IOPriority.c
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
-Based on ionice,
+Based on ionice,
Copyright (C) 2005 Jens Axboe <jens@axboe.dk>
Released under the terms of the GNU General Public License version 2
*/
diff --git a/linux/IOPriority.h b/linux/IOPriority.h
index 148e344c..1c9ca95b 100644
--- a/linux/IOPriority.h
+++ b/linux/IOPriority.h
@@ -8,7 +8,7 @@ htop - IOPriority.h
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
-Based on ionice,
+Based on ionice,
Copyright (C) 2005 Jens Axboe <jens@axboe.dk>
Released under the terms of the GNU General Public License version 2
*/
diff --git a/linux/IOPriorityPanel.h b/linux/IOPriorityPanel.h
index 9f77a4d9..0bf74f50 100644
--- a/linux/IOPriorityPanel.h
+++ b/linux/IOPriorityPanel.h
@@ -13,9 +13,9 @@ in the source distribution for its full text.
#include "IOPriority.h"
#include "ListItem.h"
-Panel* IOPriorityPanel_new(IOPriority currPrio);
+extern Panel* IOPriorityPanel_new(IOPriority currPrio);
-IOPriority IOPriorityPanel_getIOPriority(Panel* this);
+extern IOPriority IOPriorityPanel_getIOPriority(Panel* this);
#endif
diff --git a/linux/LinuxCRT.h b/linux/LinuxCRT.h
index f8c43e4d..966dfecf 100644
--- a/linux/LinuxCRT.h
+++ b/linux/LinuxCRT.h
@@ -12,6 +12,6 @@ in the source distribution for its full text.
#ifdef HAVE_EXECINFO_H
#endif
-void CRT_handleSIGSEGV(int sgn);
+extern void CRT_handleSIGSEGV(int sgn);
#endif
diff --git a/linux/LinuxProcess.c b/linux/LinuxProcess.c
index 5f697078..50b4d220 100644
--- a/linux/LinuxProcess.c
+++ b/linux/LinuxProcess.c
@@ -1,6 +1,7 @@
/*
htop - LinuxProcess.c
(C) 2014 Hisham H. Muhammad
+(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
@@ -24,6 +25,7 @@ in the source distribution for its full text.
#define PROCESS_FLAG_LINUX_VSERVER 0x0400
#define PROCESS_FLAG_LINUX_CGROUP 0x0800
#define PROCESS_FLAG_LINUX_OOM 0x1000
+#define PROCESS_FLAG_LINUX_SMAPS 0x2000
typedef enum UnsupportedProcessFields {
FLAGS = 9,
@@ -87,7 +89,10 @@ typedef enum LinuxProcessFields {
PERCENT_IO_DELAY = 117,
PERCENT_SWAP_DELAY = 118,
#endif
- LAST_PROCESSFIELD = 119,
+ M_PSS = 119,
+ M_SWAP = 120,
+ M_PSSWP = 121,
+ LAST_PROCESSFIELD = 122,
} LinuxProcessField;
#include "IOPriority.h"
@@ -103,6 +108,9 @@ typedef struct LinuxProcess_ {
unsigned long long int cutime;
unsigned long long int cstime;
long m_share;
+ long m_pss;
+ long m_swap;
+ long m_psswp;
long m_trs;
long m_drs;
long m_lrs;
@@ -117,7 +125,7 @@ typedef struct LinuxProcess_ {
unsigned long long io_write_bytes;
unsigned long long io_cancelled_write_bytes;
unsigned long long io_rate_read_time;
- unsigned long long io_rate_write_time;
+ unsigned long long io_rate_write_time;
double io_rate_read_bps;
double io_rate_write_bps;
#endif
@@ -154,7 +162,8 @@ typedef struct LinuxProcess_ {
}*/
-long long btime; /* semi-global */
+/* semi-global */
+long long btime;
ProcessFieldData Process_fields[] = {
[0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
@@ -203,7 +212,7 @@ ProcessFieldData Process_fields[] = {
[M_DRS] = { .name = "M_DRS", .title = " DATA ", .description = "Size of the data segment plus stack usage of the process", .flags = 0, },
[M_LRS] = { .name = "M_LRS", .title = " LIB ", .description = "The library size of the process", .flags = 0, },
[M_DT] = { .name = "M_DT", .title = " DIRTY ", .description = "Size of the dirty pages of the process", .flags = 0, },
- [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
+ [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
[PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, },
[PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, },
[USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
@@ -239,6 +248,9 @@ ProcessFieldData Process_fields[] = {
[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, },
#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, },
+ [M_PSSWP] = { .name = "M_PSSWP", .title = " PSSWP ", .description = "shows proportional swap share of this mapping, Unlike \"Swap\", this does not take into account swapped out page of underlying shmem objects.", .flags = PROCESS_FLAG_LINUX_SMAPS, },
[LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
};
@@ -303,12 +315,12 @@ IOPriority LinuxProcess_updateIOPriority(LinuxProcess* this) {
return ioprio;
}
-bool LinuxProcess_setIOPriority(LinuxProcess* this, IOPriority ioprio) {
+bool LinuxProcess_setIOPriority(LinuxProcess* this, Arg ioprio) {
// Other OSes masquerading as Linux (NetBSD?) don't have this syscall
#ifdef SYS_ioprio_set
- syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, this->super.pid, ioprio);
+ syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, this->super.pid, ioprio.i);
#endif
- return (LinuxProcess_updateIOPriority(this) == ioprio);
+ return (LinuxProcess_updateIOPriority(this) == ioprio.i);
}
#ifdef HAVE_DELAYACCT
@@ -344,6 +356,9 @@ void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field)
case M_LRS: Process_humanNumber(str, lp->m_lrs * PAGE_SIZE_KB, coloring); return;
case M_TRS: Process_humanNumber(str, lp->m_trs * PAGE_SIZE_KB, coloring); return;
case M_SHARE: Process_humanNumber(str, lp->m_share * PAGE_SIZE_KB, coloring); return;
+ case M_PSS: Process_humanNumber(str, lp->m_pss, coloring); return;
+ case M_SWAP: Process_humanNumber(str, lp->m_swap, coloring); return;
+ case M_PSSWP: Process_humanNumber(str, lp->m_psswp, coloring); return;
case UTIME: Process_printTime(str, lp->utime); return;
case STIME: Process_printTime(str, lp->stime); return;
case CUTIME: Process_printTime(str, lp->cutime); return;
@@ -394,7 +409,7 @@ void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field)
attr = CRT_colors[PROCESS_HIGH_PRIORITY];
xSnprintf(buffer, n, "R%1d ", IOPriority_data(lp->ioPriority));
} else if (klass == IOPRIO_CLASS_IDLE) {
- attr = CRT_colors[PROCESS_LOW_PRIORITY];
+ attr = CRT_colors[PROCESS_LOW_PRIORITY];
xSnprintf(buffer, n, "id ");
} else {
xSnprintf(buffer, n, "?? ");
@@ -435,6 +450,12 @@ long LinuxProcess_compare(const void* v1, const void* v2) {
return (p2->m_trs - p1->m_trs);
case M_SHARE:
return (p2->m_share - p1->m_share);
+ case M_PSS:
+ return (p2->m_pss - p1->m_pss);
+ case M_SWAP:
+ return (p2->m_swap - p1->m_swap);
+ case M_PSSWP:
+ return (p2->m_psswp - p1->m_psswp);
case UTIME: diff = p2->utime - p1->utime; goto test_diff;
case CUTIME: diff = p2->cutime - p1->cutime; goto test_diff;
case STIME: diff = p2->stime - p1->stime; goto test_diff;
diff --git a/linux/LinuxProcess.h b/linux/LinuxProcess.h
index 6ce3037d..1e47ba28 100644
--- a/linux/LinuxProcess.h
+++ b/linux/LinuxProcess.h
@@ -5,6 +5,7 @@
/*
htop - LinuxProcess.h
(C) 2014 Hisham H. Muhammad
+(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
@@ -15,6 +16,7 @@ in the source distribution for its full text.
#define PROCESS_FLAG_LINUX_VSERVER 0x0400
#define PROCESS_FLAG_LINUX_CGROUP 0x0800
#define PROCESS_FLAG_LINUX_OOM 0x1000
+#define PROCESS_FLAG_LINUX_SMAPS 0x2000
typedef enum UnsupportedProcessFields {
FLAGS = 9,
@@ -78,7 +80,10 @@ typedef enum LinuxProcessFields {
PERCENT_IO_DELAY = 117,
PERCENT_SWAP_DELAY = 118,
#endif
- LAST_PROCESSFIELD = 119,
+ M_PSS = 119,
+ M_SWAP = 120,
+ M_PSSWP = 121,
+ LAST_PROCESSFIELD = 122,
} LinuxProcessField;
#include "IOPriority.h"
@@ -94,6 +99,9 @@ typedef struct LinuxProcess_ {
unsigned long long int cutime;
unsigned long long int cstime;
long m_share;
+ long m_pss;
+ long m_swap;
+ long m_psswp;
long m_trs;
long m_drs;
long m_lrs;
@@ -108,7 +116,7 @@ typedef struct LinuxProcess_ {
unsigned long long io_write_bytes;
unsigned long long io_cancelled_write_bytes;
unsigned long long io_rate_read_time;
- unsigned long long io_rate_write_time;
+ unsigned long long io_rate_write_time;
double io_rate_read_bps;
double io_rate_write_bps;
#endif
@@ -144,7 +152,8 @@ typedef struct LinuxProcess_ {
#endif
-long long btime; /* semi-global */
+/* semi-global */
+extern long long btime;
extern ProcessFieldData Process_fields[];
@@ -152,9 +161,9 @@ extern ProcessPidColumn Process_pidColumns[];
extern ProcessClass LinuxProcess_class;
-LinuxProcess* LinuxProcess_new(Settings* settings);
+extern LinuxProcess* LinuxProcess_new(Settings* settings);
-void Process_delete(Object* cast);
+extern void Process_delete(Object* cast);
/*
[1] Note that before kernel 2.6.26 a process that has not asked for
@@ -166,19 +175,19 @@ extern io_priority;
*/
#define LinuxProcess_effectiveIOPriority(p_) (IOPriority_class(p_->ioPriority) == IOPRIO_CLASS_NONE ? IOPriority_tuple(IOPRIO_CLASS_BE, (p_->super.nice + 20) / 5) : p_->ioPriority)
-IOPriority LinuxProcess_updateIOPriority(LinuxProcess* this);
+extern IOPriority LinuxProcess_updateIOPriority(LinuxProcess* this);
-bool LinuxProcess_setIOPriority(LinuxProcess* this, IOPriority ioprio);
+extern bool LinuxProcess_setIOPriority(LinuxProcess* this, Arg ioprio);
#ifdef HAVE_DELAYACCT
-void LinuxProcess_printDelay(float delay_percent, char* buffer, int n);
+extern void LinuxProcess_printDelay(float delay_percent, char* buffer, int n);
#endif
-void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field);
+extern void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field);
-long LinuxProcess_compare(const void* v1, const void* v2);
+extern long LinuxProcess_compare(const void* v1, const void* v2);
-bool Process_isThread(Process* this);
+extern bool Process_isThread(Process* this);
#endif
diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c
index 1d5700e5..bcdd5515 100644
--- a/linux/LinuxProcessList.c
+++ b/linux/LinuxProcessList.c
@@ -28,8 +28,7 @@ in the source distribution for its full text.
#include <fcntl.h>
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
-#elif defined(MAJOR_IN_SYSMACROS) || \
- (defined(HAVE_SYS_SYSMACROS_H) && HAVE_SYS_SYSMACROS_H)
+#elif defined(MAJOR_IN_SYSMACROS)
#include <sys/sysmacros.h>
#endif
@@ -63,7 +62,7 @@ typedef struct CPUData_ {
unsigned long long int softIrqTime;
unsigned long long int stealTime;
unsigned long long int guestTime;
-
+
unsigned long long int totalPeriod;
unsigned long long int userPeriod;
unsigned long long int systemPeriod;
@@ -76,6 +75,8 @@ typedef struct CPUData_ {
unsigned long long int softIrqPeriod;
unsigned long long int stealPeriod;
unsigned long long int guestPeriod;
+
+ double frequency;
} CPUData;
typedef struct TtyDriver_ {
@@ -87,10 +88,11 @@ typedef struct TtyDriver_ {
typedef struct LinuxProcessList_ {
ProcessList super;
-
+
CPUData* cpus;
TtyDriver* ttyDrivers;
-
+ bool haveSmapsRollup;
+
#ifdef HAVE_DELAYACCT
struct nl_sock *netlink_socket;
int netlink_family;
@@ -103,6 +105,10 @@ typedef struct LinuxProcessList_ {
#define PROCDIR "/proc"
#endif
+#ifndef PROCCPUINFOFILE
+#define PROCCPUINFOFILE PROCDIR "/cpuinfo"
+#endif
+
#ifndef PROCSTATFILE
#define PROCSTATFILE PROCDIR "/stat"
#endif
@@ -247,8 +253,17 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui
LinuxProcessList_initNetlinkSocket(this);
#endif
+ // Check for /proc/*/smaps_rollup availability (improves smaps parsing speed, Linux 4.14+)
+ FILE* file = fopen(PROCDIR "/self/smaps_rollup", "r");
+ if(file != NULL) {
+ this->haveSmapsRollup = true;
+ fclose(file);
+ } else {
+ this->haveSmapsRollup = false;
+ }
+
// Update CPU count:
- FILE* file = fopen(PROCSTATFILE, "r");
+ file = fopen(PROCSTATFILE, "r");
if (file == NULL) {
CRT_fatalError("Cannot open " PROCSTATFILE);
}
@@ -326,7 +341,7 @@ static bool LinuxProcessList_readStatFile(Process *process, const char* dirname,
location += 2;
char *end = strrchr(location, ')');
if (!end) return false;
-
+
int commsize = end - location;
memcpy(command, location, commsize);
command[commsize] = '\0';
@@ -377,9 +392,9 @@ static bool LinuxProcessList_readStatFile(Process *process, const char* dirname,
location += 1;
assert(location != NULL);
process->processor = strtol(location, &location, 10);
-
+
process->time = lp->utime + lp->stime;
-
+
return true;
}
@@ -419,7 +434,7 @@ static void LinuxProcessList_readIoFile(LinuxProcess* process, const char* dirna
process->io_rate_write_time = -1LL;
return;
}
-
+
char buffer[1024];
ssize_t buflen = xread(fd, buffer, 1023);
close(fd);
@@ -436,7 +451,7 @@ static void LinuxProcessList_readIoFile(LinuxProcess* process, const char* dirna
process->io_rchar = strtoull(line+7, NULL, 10);
else if (strncmp(line+1, "ead_bytes: ", 11) == 0) {
process->io_read_bytes = strtoull(line+12, NULL, 10);
- process->io_rate_read_bps =
+ process->io_rate_read_bps =
((double)(process->io_read_bytes - last_read))/(((double)(now - process->io_rate_read_time))/1000);
process->io_rate_read_time = now;
}
@@ -446,7 +461,7 @@ static void LinuxProcessList_readIoFile(LinuxProcess* process, const char* dirna
process->io_wchar = strtoull(line+7, NULL, 10);
else if (strncmp(line+1, "rite_bytes: ", 12) == 0) {
process->io_write_bytes = strtoull(line+13, NULL, 10);
- process->io_rate_write_bps =
+ process->io_rate_write_bps =
((double)(process->io_write_bytes - last_write))/(((double)(now - process->io_rate_write_time))/1000);
process->io_rate_write_time = now;
}
@@ -493,6 +508,62 @@ static bool LinuxProcessList_readStatmFile(LinuxProcess* process, const char* di
return (errno == 0);
}
+static bool LinuxProcessList_readSmapsFile(LinuxProcess* process, const char* dirname, const char* name, bool haveSmapsRollup) {
+ //http://elixir.free-electrons.com/linux/v4.10/source/fs/proc/task_mmu.c#L719
+ //kernel will return data in chunks of size PAGE_SIZE or less.
+
+ char buffer[PAGE_SIZE];// 4k
+ char *start,*end;
+ ssize_t nread=0;
+ int tmp=0;
+ if(haveSmapsRollup) {// only available in Linux 4.14+
+ snprintf(buffer, PAGE_SIZE-1, "%s/%s/smaps_rollup", dirname, name);
+ } else {
+ snprintf(buffer, PAGE_SIZE-1, "%s/%s/smaps", dirname, name);
+ }
+ int fd = open(buffer, O_RDONLY);
+ if (fd == -1)
+ return false;
+
+ process->m_pss = 0;
+ process->m_swap = 0;
+ process->m_psswp = 0;
+
+ while ( ( nread = read(fd,buffer, sizeof(buffer)) ) > 0 ){
+ start = (char *)&buffer;
+ end = start + nread;
+ do{//parse 4k block
+
+ if( (tmp = (end - start)) > 0 &&
+ (start = memmem(start,tmp,"\nPss:",5)) != NULL )
+ {
+ process->m_pss += strtol(start+5, &start, 10);
+ start += 3;//now we must be at the end of line "Pss: 0 kB"
+ }else
+ break; //read next 4k block
+
+ if( (tmp = (end - start)) > 0 &&
+ (start = memmem(start,tmp,"\nSwap:",6)) != NULL )
+ {
+ process->m_swap += strtol(start+6, &start, 10);
+ start += 3;
+ }else
+ break;
+
+ if( (tmp = (end - start)) > 0 &&
+ (start = memmem(start,tmp,"\nSwapPss:",9)) != NULL )
+ {
+ process->m_psswp += strtol(start+9, &start, 10);
+ start += 3;
+ }else
+ break;
+
+ }while(1);
+ }//while read
+ close(fd);
+ return true;
+}
+
#ifdef HAVE_OPENVZ
static void LinuxProcessList_readOpenVZData(LinuxProcess* process, const char* dirname, const char* name) {
@@ -668,7 +739,7 @@ static void LinuxProcessList_readDelayAcctData(LinuxProcessList* this, LinuxProc
process->cpu_delay_percent = -1LL;
return;
}
-
+
if (nl_recvmsgs_default(this->netlink_socket) < 0) {
return;
}
@@ -692,14 +763,18 @@ static bool LinuxProcessList_readCmdlineFile(Process* process, const char* dirna
int fd = open(filename, O_RDONLY);
if (fd == -1)
return false;
-
+
char command[4096+1]; // max cmdline length on Linux
int amtRead = xread(fd, command, sizeof(command) - 1);
close(fd);
- int tokenEnd = 0;
+ int tokenEnd = 0;
int lastChar = 0;
if (amtRead == 0) {
- ((LinuxProcess*)process)->isKernelThread = true;
+ if (process->state == 'Z') {
+ process->basenameOffset = 0;
+ } else {
+ ((LinuxProcess*)process)->isKernelThread = true;
+ }
return true;
} else if (amtRead < 0) {
return false;
@@ -733,13 +808,13 @@ static char* LinuxProcessList_updateTtyDevice(TtyDriver* ttyDrivers, unsigned in
i++;
if ((!ttyDrivers[i].path) || maj < ttyDrivers[i].major) {
break;
- }
+ }
if (maj > ttyDrivers[i].major) {
continue;
}
if (min < ttyDrivers[i].minorFrom) {
break;
- }
+ }
if (min > ttyDrivers[i].minorTo) {
continue;
}
@@ -797,17 +872,17 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
// filename is a number: process directory
int pid = atoi(name);
-
+
if (parent && pid == parent->pid)
continue;
- if (pid <= 0)
+ if (pid <= 0)
continue;
bool preExisting = false;
Process* proc = ProcessList_getProcess(pl, pid, &preExisting, (Process_New) LinuxProcess_new);
proc->tgid = parent ? parent->pid : pid;
-
+
LinuxProcess* lp = (LinuxProcess*) proc;
char subdirname[MAX_NAME+1];
@@ -822,6 +897,21 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
if (! LinuxProcessList_readStatmFile(lp, dirname, name))
goto errorReadingProcess;
+ if ((settings->flags & PROCESS_FLAG_LINUX_SMAPS) && !Process_isKernelThread(proc)){
+ if (!parent){
+ // Read smaps file of each process only every second pass to improve performance
+ static int smaps_flag = 0;
+ if ((pid & 1) == smaps_flag){
+ LinuxProcessList_readSmapsFile(lp, dirname, name, this->haveSmapsRollup);
+ }
+ if (pid == 1) {
+ smaps_flag = !smaps_flag;
+ }
+ } else {
+ lp->m_pss = ((LinuxProcess*)parent)->m_pss;
+ }
+ }
+
proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
char command[MAX_NAME+1];
@@ -853,7 +943,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
LinuxProcessList_readOpenVZData(lp, dirname, name);
}
#endif
-
+
#ifdef HAVE_VSERVER
if (settings->flags & PROCESS_FLAG_LINUX_VSERVER) {
LinuxProcessList_readVServerData(lp, dirname, name);
@@ -881,7 +971,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
if (settings->flags & PROCESS_FLAG_LINUX_CGROUP)
LinuxProcessList_readCGroupFile(lp, dirname, name);
#endif
-
+
if (settings->flags & PROCESS_FLAG_LINUX_OOM)
LinuxProcessList_readOomData(lp, dirname, name);
@@ -1097,12 +1187,78 @@ static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this) {
cpuData->stealTime = steal;
cpuData->guestTime = virtalltime;
cpuData->totalTime = totaltime;
+
}
double period = (double)this->cpus[0].totalPeriod / cpus;
fclose(file);
return period;
}
+static inline double LinuxProcessList_scanCPUFrequency(LinuxProcessList* this) {
+ ProcessList* pl = (ProcessList*) this;
+ Settings* settings = pl->settings;
+
+ int cpus = this->super.cpuCount;
+ assert(cpus > 0);
+
+ for (int i = 0; i <= cpus; i++) {
+ CPUData* cpuData = &(this->cpus[i]);
+ cpuData->frequency = -1;
+ }
+
+ int numCPUsWithFrequency = 0;
+ double totalFrequency = 0;
+
+ if (settings->showCPUFrequency) {
+ FILE* file = fopen(PROCCPUINFOFILE, "r");
+ if (file == NULL) {
+ CRT_fatalError("Cannot open " PROCCPUINFOFILE);
+ }
+
+ int cpuid = -1;
+ double frequency;
+ while (!feof(file)) {
+ char buffer[PROC_LINE_LENGTH];
+ char *ok = fgets(buffer, PROC_LINE_LENGTH, file);
+ if (!ok) break;
+
+ if (
+ (sscanf(buffer, "processor : %d", &cpuid) == 1) ||
+ (sscanf(buffer, "processor: %d", &cpuid) == 1)
+ ) {
+ if (cpuid < 0 || cpuid > (cpus - 1)) {
+ char buffer[64];
+ xSnprintf(buffer, sizeof(buffer), PROCCPUINFOFILE " contains out-of-range CPU number %d", cpuid);
+ CRT_fatalError(buffer);
+ }
+ } else if (
+ (sscanf(buffer, "cpu MHz : %lf", &frequency) == 1) ||
+ (sscanf(buffer, "cpu MHz: %lf", &frequency) == 1)
+ ) {
+ if (cpuid < 0) {
+ CRT_fatalError(PROCCPUINFOFILE " is malformed: cpu MHz line without corresponding processor line");
+ }
+
+ int cpu = cpuid + 1;
+ CPUData* cpuData = &(this->cpus[cpu]);
+ cpuData->frequency = frequency;
+ numCPUsWithFrequency++;
+ totalFrequency += frequency;
+ } else if (buffer[0] == '\n') {
+ cpuid = -1;
+ }
+ }
+ fclose(file);
+
+ if (numCPUsWithFrequency > 0) {
+ this->cpus[0].frequency = totalFrequency / numCPUsWithFrequency;
+ }
+ }
+
+ double period = (double)this->cpus[0].totalPeriod / cpus;
+ return period;
+}
+
void ProcessList_goThroughEntries(ProcessList* super) {
LinuxProcessList* this = (LinuxProcessList*) super;
@@ -1110,6 +1266,8 @@ void ProcessList_goThroughEntries(ProcessList* super) {
LinuxProcessList_scanZfsArcstats(this);
double period = LinuxProcessList_scanCPUTime(this);
+ LinuxProcessList_scanCPUFrequency(this);
+
struct timeval tv;
gettimeofday(&tv, NULL);
LinuxProcessList_recurseProcTree(this, PROCDIR, NULL, period, tv);
diff --git a/linux/LinuxProcessList.h b/linux/LinuxProcessList.h
index 353fe603..86e9d3fd 100644
--- a/linux/LinuxProcessList.h
+++ b/linux/LinuxProcessList.h
@@ -10,8 +10,7 @@ in the source distribution for its full text.
*/
#ifdef MAJOR_IN_MKDEV
-#elif defined(MAJOR_IN_SYSMACROS) || \
- (defined(HAVE_SYS_SYSMACROS_H) && HAVE_SYS_SYSMACROS_H)
+#elif defined(MAJOR_IN_SYSMACROS)
#endif
#ifdef HAVE_DELAYACCT
@@ -36,7 +35,7 @@ typedef struct CPUData_ {
unsigned long long int softIrqTime;
unsigned long long int stealTime;
unsigned long long int guestTime;
-
+
unsigned long long int totalPeriod;
unsigned long long int userPeriod;
unsigned long long int systemPeriod;
@@ -49,6 +48,8 @@ typedef struct CPUData_ {
unsigned long long int softIrqPeriod;
unsigned long long int stealPeriod;
unsigned long long int guestPeriod;
+
+ double frequency;
} CPUData;
typedef struct TtyDriver_ {
@@ -60,10 +61,11 @@ typedef struct TtyDriver_ {
typedef struct LinuxProcessList_ {
ProcessList super;
-
+
CPUData* cpus;
TtyDriver* ttyDrivers;
-
+ bool haveSmapsRollup;
+
#ifdef HAVE_DELAYACCT
struct nl_sock *netlink_socket;
int netlink_family;
@@ -76,6 +78,10 @@ typedef struct LinuxProcessList_ {
#define PROCDIR "/proc"
#endif
+#ifndef PROCCPUINFOFILE
+#define PROCCPUINFOFILE PROCDIR "/cpuinfo"
+#endif
+
#ifndef PROCSTATFILE
#define PROCSTATFILE PROCDIR "/stat"
#endif
@@ -105,9 +111,9 @@ typedef struct LinuxProcessList_ {
#endif
-ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId);
+extern ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId);
-void ProcessList_delete(ProcessList* pl);
+extern void ProcessList_delete(ProcessList* pl);
#ifdef HAVE_TASKSTATS
@@ -130,6 +136,6 @@ void ProcessList_delete(ProcessList* pl);
#endif
-void ProcessList_goThroughEntries(ProcessList* super);
+extern void ProcessList_goThroughEntries(ProcessList* super);
#endif
diff --git a/linux/Platform.c b/linux/Platform.c
index f7088cf4..1725eea9 100644
--- a/linux/Platform.c
+++ b/linux/Platform.c
@@ -19,6 +19,7 @@ in the source distribution for its full text.
#include "TasksMeter.h"
#include "LoadAverageMeter.h"
#include "UptimeMeter.h"
+#include "PressureStallMeter.h"
#include "ClockMeter.h"
#include "HostnameMeter.h"
#include "zfs/ZfsArcMeter.h"
@@ -95,7 +96,7 @@ static Htop_Reaction Platform_actionSetIOPriority(State* st) {
if (!p) return HTOP_OK;
IOPriority ioprio = p->ioPriority;
Panel* ioprioPanel = IOPriorityPanel_new(ioprio);
- void* set = Action_pickFromVector(st, ioprioPanel, 21);
+ void* set = Action_pickFromVector(st, ioprioPanel, 21, true);
if (set) {
IOPriority ioprio = IOPriorityPanel_getIOPriority(ioprioPanel);
bool ok = MainPanel_foreachProcess((MainPanel*)panel, (MainPanel_ForeachProcessFn) LinuxProcess_setIOPriority, (Arg){ .i = ioprio }, NULL);
@@ -123,11 +124,19 @@ MeterClass* Platform_meterTypes[] = {
&HostnameMeter_class,
&AllCPUsMeter_class,
&AllCPUs2Meter_class,
+ &AllCPUs4Meter_class,
&LeftCPUsMeter_class,
&RightCPUsMeter_class,
&LeftCPUs2Meter_class,
&RightCPUs2Meter_class,
+ &LeftCPUs4Meter_class,
+ &RightCPUs4Meter_class,
&BlankMeter_class,
+ &PressureStallCPUSomeMeter_class,
+ &PressureStallIOSomeMeter_class,
+ &PressureStallIOFullMeter_class,
+ &PressureStallMemorySomeMeter_class,
+ &PressureStallMemoryFullMeter_class,
&ZfsArcMeter_class,
&ZfsCompressedArcMeter_class,
NULL
@@ -196,6 +205,9 @@ double Platform_setCPUValues(Meter* this, int cpu) {
}
percent = CLAMP(percent, 0.0, 100.0);
if (isnan(percent)) percent = 0.0;
+
+ v[CPU_METER_FREQUENCY] = cpuData->frequency;
+
return percent;
}
@@ -252,3 +264,21 @@ char* Platform_getProcessEnv(pid_t pid) {
}
return env;
}
+
+void Platform_getPressureStall(const char *file, bool some, double* ten, double* sixty, double* threehundred) {
+ *ten = *sixty = *threehundred = 0;
+ char procname[128+1];
+ xSnprintf(procname, 128, PROCDIR "/pressure/%s", file);
+ FILE *fd = fopen(procname, "r");
+ if (!fd) {
+ *ten = *sixty = *threehundred = NAN;
+ return;
+ }
+ int total = fscanf(fd, "some avg10=%32lf avg60=%32lf avg300=%32lf total=%*f ", ten, sixty, threehundred);
+ if (!some) {
+ total = fscanf(fd, "full avg10=%32lf avg60=%32lf avg300=%32lf total=%*f ", ten, sixty, threehundred);
+ }
+ (void) total;
+ assert(total == 3);
+ fclose(fd);
+}
diff --git a/linux/Platform.h b/linux/Platform.h
index 5d85eb36..bf163a54 100644
--- a/linux/Platform.h
+++ b/linux/Platform.h
@@ -27,26 +27,27 @@ extern const SignalItem Platform_signals[];
extern const unsigned int Platform_numberOfSignals;
-void Platform_setBindings(Htop_Action* keys);
+extern void Platform_setBindings(Htop_Action* keys);
extern MeterClass* Platform_meterTypes[];
-int Platform_getUptime();
+extern int Platform_getUptime();
-void Platform_getLoadAverage(double* one, double* five, double* fifteen);
+extern void Platform_getLoadAverage(double* one, double* five, double* fifteen);
-int Platform_getMaxPid();
+extern int Platform_getMaxPid();
-double Platform_setCPUValues(Meter* this, int cpu);
+extern double Platform_setCPUValues(Meter* this, int cpu);
-void Platform_setMemoryValues(Meter* this);
+extern void Platform_setMemoryValues(Meter* this);
-void Platform_setSwapValues(Meter* this);
+extern void Platform_setSwapValues(Meter* this);
-void Platform_setZfsArcValues(Meter* this);
+extern void Platform_setZfsArcValues(Meter* this);
-void Platform_setZfsCompressedArcValues(Meter* this);
+extern void Platform_setZfsCompressedArcValues(Meter* this);
+extern char* Platform_getProcessEnv(pid_t pid);
-char* Platform_getProcessEnv(pid_t pid);
+extern void Platform_getPressureStall(const char *file, bool some, double* ten, double* sixty, double* threehundred);
#endif
diff --git a/linux/PressureStallMeter.c b/linux/PressureStallMeter.c
new file mode 100644
index 00000000..56055bff
--- /dev/null
+++ b/linux/PressureStallMeter.c
@@ -0,0 +1,133 @@
+/*
+htop - PressureStallMeter.c
+(C) 2004-2011 Hisham H. Muhammad
+(C) 2019 Ran Benita
+Released under the GNU GPL, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "PressureStallMeter.h"
+#include "Platform.h"
+#include "CRT.h"
+
+#include <string.h>
+
+/*{
+#include "Meter.h"
+}*/
+
+static int PressureStallMeter_attributes[] = {
+ PRESSURE_STALL_TEN, PRESSURE_STALL_SIXTY, PRESSURE_STALL_THREEHUNDRED
+};
+
+static void PressureStallMeter_updateValues(Meter* this, char* buffer, int len) {
+ const char *file;
+ if (strstr(Meter_name(this), "CPU")) {
+ file = "cpu";
+ } else if (strstr(Meter_name(this), "IO")) {
+ file = "io";
+ } else {
+ file = "memory";
+ }
+
+ bool some;
+ if (strstr(Meter_name(this), "Some")) {
+ some = true;
+ } else {
+ some = false;
+ }
+
+ Platform_getPressureStall(file, some, &this->values[0], &this->values[1], &this->values[2]);
+ xSnprintf(buffer, len, "xxxx %.2lf%% %.2lf%% %.2lf%%", this->values[0], this->values[1], this->values[2]);
+}
+
+static void PressureStallMeter_display(Object* cast, RichString* out) {
+ Meter* this = (Meter*)cast;
+ char buffer[20];
+ xSnprintf(buffer, sizeof(buffer), "%.2lf%% ", this->values[0]);
+ RichString_write(out, CRT_colors[PRESSURE_STALL_TEN], buffer);
+ xSnprintf(buffer, sizeof(buffer), "%.2lf%% ", this->values[1]);
+ RichString_append(out, CRT_colors[PRESSURE_STALL_SIXTY], buffer);
+ xSnprintf(buffer, sizeof(buffer), "%.2lf%% ", this->values[2]);
+ RichString_append(out, CRT_colors[PRESSURE_STALL_THREEHUNDRED], buffer);
+}
+
+MeterClass PressureStallCPUSomeMeter_class = {
+ .super = {
+ .extends = Class(Meter),
+ .delete = Meter_delete,
+ .display = PressureStallMeter_display,
+ },
+ .updateValues = PressureStallMeter_updateValues,
+ .defaultMode = TEXT_METERMODE,
+ .maxItems = 3,
+ .total = 100.0,
+ .attributes = PressureStallMeter_attributes,
+ .name = "PressureStallCPUSome",
+ .uiName = "Pressure Stall Information, some CPU",
+ .caption = "Some CPU pressure: "
+};
+
+MeterClass PressureStallIOSomeMeter_class = {
+ .super = {
+ .extends = Class(Meter),
+ .delete = Meter_delete,
+ .display = PressureStallMeter_display,
+ },
+ .updateValues = PressureStallMeter_updateValues,
+ .defaultMode = TEXT_METERMODE,
+ .maxItems = 3,
+ .total = 100.0,
+ .attributes = PressureStallMeter_attributes,
+ .name = "PressureStallIOSome",
+ .uiName = "Pressure Stall Information, some IO",
+ .caption = "Some IO pressure: "
+};
+
+MeterClass PressureStallIOFullMeter_class = {
+ .super = {
+ .extends = Class(Meter),
+ .delete = Meter_delete,
+ .display = PressureStallMeter_display,
+ },
+ .updateValues = PressureStallMeter_updateValues,
+ .defaultMode = TEXT_METERMODE,
+ .maxItems = 3,
+ .total = 100.0,
+ .attributes = PressureStallMeter_attributes,
+ .name = "PressureStallIOFull",
+ .uiName = "Pressure Stall Information, full IO",
+ .caption = "Full IO pressure: "
+};
+
+MeterClass PressureStallMemorySomeMeter_class = {
+ .super = {
+ .extends = Class(Meter),
+ .delete = Meter_delete,
+ .display = PressureStallMeter_display,
+ },
+ .updateValues = PressureStallMeter_updateValues,
+ .defaultMode = TEXT_METERMODE,
+ .maxItems = 3,
+ .total = 100.0,
+ .attributes = PressureStallMeter_attributes,
+ .name = "PressureStallMemorySome",
+ .uiName = "Pressure Stall Information, some memory",
+ .caption = "Some Mem pressure: "
+};
+
+MeterClass PressureStallMemoryFullMeter_class = {
+ .super = {
+ .extends = Class(Meter),
+ .delete = Meter_delete,
+ .display = PressureStallMeter_display,
+ },
+ .updateValues = PressureStallMeter_updateValues,
+ .defaultMode = TEXT_METERMODE,
+ .maxItems = 3,
+ .total = 100.0,
+ .attributes = PressureStallMeter_attributes,
+ .name = "PressureStallMemoryFull",
+ .uiName = "Pressure Stall Information, full memory",
+ .caption = "Full Mem pressure: "
+};
diff --git a/linux/PressureStallMeter.h b/linux/PressureStallMeter.h
new file mode 100644
index 00000000..22b8b972
--- /dev/null
+++ b/linux/PressureStallMeter.h
@@ -0,0 +1,25 @@
+/* Do not edit this file. It was automatically generated. */
+
+#ifndef HEADER_PressureStallMeter
+#define HEADER_PressureStallMeter
+/*
+htop - PressureStallMeter.h
+(C) 2004-2011 Hisham H. Muhammad
+(C) 2019 Ran Benita
+Released under the GNU GPL, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "Meter.h"
+
+extern MeterClass PressureStallCPUSomeMeter_class;
+
+extern MeterClass PressureStallIOSomeMeter_class;
+
+extern MeterClass PressureStallIOFullMeter_class;
+
+extern MeterClass PressureStallMemorySomeMeter_class;
+
+extern MeterClass PressureStallMemoryFullMeter_class;
+
+#endif
diff --git a/openbsd/Battery.c b/openbsd/Battery.c
index 3a0bae14..c215e418 100644
--- a/openbsd/Battery.c
+++ b/openbsd/Battery.c
@@ -10,6 +10,7 @@ in the source distribution for its full text.
#include <sys/sysctl.h>
#include <sys/sensors.h>
#include <errno.h>
+#include <string.h>
static bool findDevice(const char* name, int* mib, struct sensordev* snsrdev, size_t* sdlen) {
for (int devn = 0;; devn++) {
@@ -34,7 +35,7 @@ void Battery_getData(double* level, ACPresence* isOnAC) {
size_t sdlen = sizeof(struct sensordev);
bool found = findDevice("acpibat0", mib, &snsrdev, &sdlen);
-
+
*level = -1;
if (found) {
/* last full capacity */
@@ -57,9 +58,9 @@ void Battery_getData(double* level, ACPresence* isOnAC) {
}
}
}
-
+
found = findDevice("acpiac0", mib, &snsrdev, &sdlen);
-
+
*isOnAC = AC_ERROR;
if (found) {
mib[3] = 9;
diff --git a/openbsd/Battery.h b/openbsd/Battery.h
index b1a4982e..0f05af3a 100644
--- a/openbsd/Battery.h
+++ b/openbsd/Battery.h
@@ -12,5 +12,4 @@ in the source distribution for its full text.
void Battery_getData(double* level, ACPresence* isOnAC);
-
#endif
diff --git a/openbsd/OpenBSDProcess.c b/openbsd/OpenBSDProcess.c
index 70f9653b..f54c9111 100644
--- a/openbsd/OpenBSDProcess.c
+++ b/openbsd/OpenBSDProcess.c
@@ -135,7 +135,7 @@ ProcessFieldData Process_fields[] = {
.flags = 0, },
[ST_UID] = {
.name = "ST_UID",
- .title = " UID ",
+ .title = " UID ",
.description = "User ID of the process owner",
.flags = 0, },
[PERCENT_CPU] = {
diff --git a/openbsd/OpenBSDProcessList.c b/openbsd/OpenBSDProcessList.c
index e49cbd71..2d8951c3 100644
--- a/openbsd/OpenBSDProcessList.c
+++ b/openbsd/OpenBSDProcessList.c
@@ -6,6 +6,7 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
+#include "CRT.h"
#include "ProcessList.h"
#include "OpenBSDProcessList.h"
#include "OpenBSDProcess.h"
@@ -17,6 +18,7 @@ in the source distribution for its full text.
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/resource.h>
+#include <sys/sched.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/user.h>
@@ -31,7 +33,22 @@ in the source distribution for its full text.
typedef struct CPUData_ {
unsigned long long int totalTime;
+ unsigned long long int userTime;
+ unsigned long long int niceTime;
+ unsigned long long int sysTime;
+ unsigned long long int sysAllTime;
+ unsigned long long int spinTime;
+ unsigned long long int intrTime;
+ unsigned long long int idleTime;
+
unsigned long long int totalPeriod;
+ unsigned long long int userPeriod;
+ unsigned long long int nicePeriod;
+ unsigned long long int sysPeriod;
+ unsigned long long int sysAllPeriod;
+ unsigned long long int spinPeriod;
+ unsigned long long int intrPeriod;
+ unsigned long long int idlePeriod;
} CPUData;
typedef struct OpenBSDProcessList_ {
@@ -79,16 +96,17 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui
if (e == -1 || pl->cpuCount < 1) {
pl->cpuCount = 1;
}
- opl->cpus = xRealloc(opl->cpus, pl->cpuCount * sizeof(CPUData));
+ opl->cpus = xCalloc(pl->cpuCount + 1, sizeof(CPUData));
size = sizeof(fscale);
if (sysctl(fmib, 2, &fscale, &size, NULL, 0) < 0) {
err(1, "fscale sysctl call failed");
}
- for (i = 0; i < pl->cpuCount; i++) {
- opl->cpus[i].totalTime = 1;
- opl->cpus[i].totalPeriod = 1;
+ for (i = 0; i <= pl->cpuCount; i++) {
+ CPUData *d = opl->cpus + i;
+ d->totalTime = 1;
+ d->totalPeriod = 1;
}
opl->kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
@@ -205,7 +223,7 @@ char *OpenBSDProcessList_readProcessName(kvm_t* kd, struct kinfo_proc* kproc, in
/*
* Taken from OpenBSD's ps(1).
*/
-double getpcpu(const struct kinfo_proc *kp) {
+static double getpcpu(const struct kinfo_proc *kp) {
if (fscale == 0)
return (0.0);
@@ -214,9 +232,8 @@ double getpcpu(const struct kinfo_proc *kp) {
return (100.0 * fxtofl(kp->p_pctcpu));
}
-void ProcessList_goThroughEntries(ProcessList* this) {
- OpenBSDProcessList* opl = (OpenBSDProcessList*) this;
- Settings* settings = this->settings;
+static inline void OpenBSDProcessList_scanProcs(OpenBSDProcessList* this) {
+ Settings* settings = this->super.settings;
bool hideKernelThreads = settings->hideKernelThreads;
bool hideUserlandThreads = settings->hideUserlandThreads;
struct kinfo_proc* kproc;
@@ -228,10 +245,8 @@ void ProcessList_goThroughEntries(ProcessList* this) {
int count = 0;
int i;
- OpenBSDProcessList_scanMemoryInfo(this);
-
// use KERN_PROC_KTHREAD to also include kernel threads
- struct kinfo_proc* kprocs = kvm_getprocs(opl->kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &count);
+ struct kinfo_proc* kprocs = kvm_getprocs(this->kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &count);
//struct kinfo_proc* kprocs = getprocs(KERN_PROC_ALL, 0, &count);
gettimeofday(&tv, NULL);
@@ -240,7 +255,7 @@ void ProcessList_goThroughEntries(ProcessList* this) {
kproc = &kprocs[i];
preExisting = false;
- proc = ProcessList_getProcess(this, kproc->p_pid, &preExisting, (Process_New) OpenBSDProcess_new);
+ proc = ProcessList_getProcess(&this->super, kproc->p_pid, &preExisting, (Process_New) OpenBSDProcess_new);
fp = (OpenBSDProcess*) proc;
proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc))
@@ -255,22 +270,22 @@ void ProcessList_goThroughEntries(ProcessList* this) {
proc->pgrp = kproc->p__pgid;
proc->st_uid = kproc->p_uid;
proc->starttime_ctime = kproc->p_ustart_sec;
- proc->user = UsersTable_getRef(this->usersTable, proc->st_uid);
- ProcessList_add((ProcessList*)this, proc);
- proc->comm = OpenBSDProcessList_readProcessName(opl->kd, kproc, &proc->basenameOffset);
+ proc->user = UsersTable_getRef(this->super.usersTable, proc->st_uid);
+ ProcessList_add(&this->super, proc);
+ proc->comm = OpenBSDProcessList_readProcessName(this->kd, kproc, &proc->basenameOffset);
(void) localtime_r((time_t*) &kproc->p_ustart_sec, &date);
strftime(proc->starttime_show, 7, ((proc->starttime_ctime > tv.tv_sec - 86400) ? "%R " : "%b%d "), &date);
} else {
if (settings->updateProcessNames) {
free(proc->comm);
- proc->comm = OpenBSDProcessList_readProcessName(opl->kd, kproc, &proc->basenameOffset);
+ proc->comm = OpenBSDProcessList_readProcessName(this->kd, kproc, &proc->basenameOffset);
}
}
proc->m_size = kproc->p_vm_dsize;
proc->m_resident = kproc->p_vm_rssize;
- proc->percent_mem = (proc->m_resident * PAGE_SIZE_KB) / (double)(this->totalMem) * 100.0;
- proc->percent_cpu = CLAMP(getpcpu(kproc), 0.0, this->cpuCount*100.0);
+ proc->percent_mem = (proc->m_resident * PAGE_SIZE_KB) / (double)(this->super.totalMem) * 100.0;
+ proc->percent_cpu = CLAMP(getpcpu(kproc), 0.0, this->super.cpuCount*100.0);
//proc->nlwp = kproc->p_numthreads;
//proc->time = kproc->p_rtime_sec + ((kproc->p_rtime_usec + 500000) / 10);
proc->nice = kproc->p_nice - 20;
@@ -290,14 +305,99 @@ void ProcessList_goThroughEntries(ProcessList* this) {
}
if (Process_isKernelThread(proc)) {
- this->kernelThreads++;
+ this->super.kernelThreads++;
}
- this->totalTasks++;
+ this->super.totalTasks++;
// SRUN ('R') means runnable, not running
if (proc->state == 'P') {
- this->runningTasks++;
+ this->super.runningTasks++;
}
proc->updated = true;
}
}
+
+static unsigned long long saturatingSub(unsigned long long a, unsigned long long b) {
+ return a > b ? a - b : 0;
+}
+
+static void getKernelCPUTimes(int cpuId, u_int64_t* times) {
+ int mib[] = { CTL_KERN, KERN_CPTIME2, cpuId };
+ size_t length = sizeof(u_int64_t) * CPUSTATES;
+ if (sysctl(mib, 3, times, &length, NULL, 0) == -1 ||
+ length != sizeof(u_int64_t) * CPUSTATES) {
+ CRT_fatalError("sysctl kern.cp_time2 failed");
+ }
+}
+
+static void kernelCPUTimesToHtop(const u_int64_t* times, CPUData* cpu) {
+ unsigned long long totalTime = 0;
+ for (int i = 0; i < CPUSTATES; i++) {
+ totalTime += times[i];
+ }
+
+ unsigned long long sysAllTime = times[CP_INTR] + times[CP_SYS];
+
+ // XXX Not sure if CP_SPIN should be added to sysAllTime.
+ // See https://github.com/openbsd/src/commit/531d8034253fb82282f0f353c086e9ad827e031c
+ #ifdef CP_SPIN
+ sysAllTime += times[CP_SPIN];
+ #endif
+
+ cpu->totalPeriod = saturatingSub(totalTime, cpu->totalTime);
+ cpu->userPeriod = saturatingSub(times[CP_USER], cpu->userTime);
+ cpu->nicePeriod = saturatingSub(times[CP_NICE], cpu->niceTime);
+ cpu->sysPeriod = saturatingSub(times[CP_SYS], cpu->sysTime);
+ cpu->sysAllPeriod = saturatingSub(sysAllTime, cpu->sysAllTime);
+ #ifdef CP_SPIN
+ cpu->spinPeriod = saturatingSub(times[CP_SPIN], cpu->spinTime);
+ #endif
+ cpu->intrPeriod = saturatingSub(times[CP_INTR], cpu->intrTime);
+ cpu->idlePeriod = saturatingSub(times[CP_IDLE], cpu->idleTime);
+
+ cpu->totalTime = totalTime;
+ cpu->userTime = times[CP_USER];
+ cpu->niceTime = times[CP_NICE];
+ cpu->sysTime = times[CP_SYS];
+ cpu->sysAllTime = sysAllTime;
+ #ifdef CP_SPIN
+ cpu->spinTime = times[CP_SPIN];
+ #endif
+ cpu->intrTime = times[CP_INTR];
+ cpu->idleTime = times[CP_IDLE];
+}
+
+static void OpenBSDProcessList_scanCPUTime(OpenBSDProcessList* this) {
+ u_int64_t kernelTimes[CPUSTATES] = {0};
+ u_int64_t avg[CPUSTATES] = {0};
+
+ for (int i = 0; i < this->super.cpuCount; i++) {
+ getKernelCPUTimes(i, kernelTimes);
+ CPUData* cpu = this->cpus + i + 1;
+ kernelCPUTimesToHtop(kernelTimes, cpu);
+
+ avg[CP_USER] += cpu->userTime;
+ avg[CP_NICE] += cpu->niceTime;
+ avg[CP_SYS] += cpu->sysTime;
+ #ifdef CP_SPIN
+ avg[CP_SPIN] += cpu->spinTime;
+ #endif
+ avg[CP_INTR] += cpu->intrTime;
+ avg[CP_IDLE] += cpu->idleTime;
+ }
+
+ for (int i = 0; i < CPUSTATES; i++) {
+ avg[i] /= this->super.cpuCount;
+ }
+
+ kernelCPUTimesToHtop(avg, this->cpus);
+}
+
+void ProcessList_goThroughEntries(ProcessList* this) {
+ OpenBSDProcessList* opl = (OpenBSDProcessList*) this;
+
+ OpenBSDProcessList_scanMemoryInfo(this);
+ OpenBSDProcessList_scanProcs(opl);
+ OpenBSDProcessList_scanCPUTime(opl);
+}
+
diff --git a/openbsd/OpenBSDProcessList.h b/openbsd/OpenBSDProcessList.h
index ba9e6d14..ec9fab27 100644
--- a/openbsd/OpenBSDProcessList.h
+++ b/openbsd/OpenBSDProcessList.h
@@ -15,7 +15,22 @@ in the source distribution for its full text.
typedef struct CPUData_ {
unsigned long long int totalTime;
+ unsigned long long int userTime;
+ unsigned long long int niceTime;
+ unsigned long long int sysTime;
+ unsigned long long int sysAllTime;
+ unsigned long long int spinTime;
+ unsigned long long int intrTime;
+ unsigned long long int idleTime;
+
unsigned long long int totalPeriod;
+ unsigned long long int userPeriod;
+ unsigned long long int nicePeriod;
+ unsigned long long int sysPeriod;
+ unsigned long long int sysAllPeriod;
+ unsigned long long int spinPeriod;
+ unsigned long long int intrPeriod;
+ unsigned long long int idlePeriod;
} CPUData;
typedef struct OpenBSDProcessList_ {
@@ -51,8 +66,7 @@ char *OpenBSDProcessList_readProcessName(kvm_t* kd, struct kinfo_proc* kproc, in
/*
* Taken from OpenBSD's ps(1).
*/
-double getpcpu(const struct kinfo_proc *kp);
-
void ProcessList_goThroughEntries(ProcessList* this);
+
#endif
diff --git a/openbsd/Platform.c b/openbsd/Platform.c
index 4bb2e35e..0f5279e8 100644
--- a/openbsd/Platform.c
+++ b/openbsd/Platform.c
@@ -20,8 +20,6 @@ in the source distribution for its full text.
#include "OpenBSDProcess.h"
#include "OpenBSDProcessList.h"
-#include <sys/sched.h>
-#include <uvm/uvmexp.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/swap.h>
@@ -31,13 +29,13 @@ in the source distribution for its full text.
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
-#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <time.h>
#include <fcntl.h>
#include <kvm.h>
#include <limits.h>
+#include <math.h>
/*{
#include "Action.h"
@@ -48,54 +46,6 @@ extern ProcessFieldData Process_fields[];
}*/
-#define MAXCPU 256
-// XXX: probably should be a struct member
-static int64_t old_v[MAXCPU][5];
-
-/*
- * Copyright (c) 1984, 1989, William LeFebvre, Rice University
- * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
- *
- * Taken directly from OpenBSD's top(1).
- *
- * percentages(cnt, out, new, old, diffs) - calculate percentage change
- * between array "old" and "new", putting the percentages in "out".
- * "cnt" is size of each array and "diffs" is used for scratch space.
- * The array "old" is updated on each call.
- * The routine assumes modulo arithmetic. This function is especially
- * useful on BSD machines for calculating cpu state percentages.
- */
-static int percentages(int cnt, int64_t *out, int64_t *new, int64_t *old, int64_t *diffs) {
- int64_t change, total_change, *dp, half_total;
- int i;
-
- /* initialization */
- total_change = 0;
- dp = diffs;
-
- /* calculate changes for each state and the overall change */
- for (i = 0; i < cnt; i++) {
- if ((change = *new - *old) < 0) {
- /* this only happens when the counter wraps */
- change = INT64_MAX - *old + *new;
- }
- total_change += (*dp++ = change);
- *old++ = *new++;
- }
-
- /* avoid divide by zero potential */
- if (total_change == 0)
- total_change = 1;
-
- /* calculate percentages based on overall change, rounding up */
- half_total = total_change / 2l;
- for (i = 0; i < cnt; i++)
- *out++ = ((*diffs++ * 1000 + half_total) / total_change);
-
- /* return the total in case the caller wants to use it */
- return (total_change);
-}
-
ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
int Platform_numberOfFields = LAST_PROCESSFIELD;
@@ -201,43 +151,38 @@ void Platform_getLoadAverage(double* one, double* five, double* fifteen) {
int Platform_getMaxPid() {
// this is hard-coded in sys/sys/proc.h - no sysctl exists
- return 32766;
+ return 99999;
}
double Platform_setCPUValues(Meter* this, int cpu) {
- int i;
- double perc;
-
- OpenBSDProcessList* pl = (OpenBSDProcessList*) this->pl;
- CPUData* cpuData = &(pl->cpus[cpu]);
- int64_t new_v[CPUSTATES], diff_v[CPUSTATES], scratch_v[CPUSTATES];
+ const OpenBSDProcessList* pl = (OpenBSDProcessList*) this->pl;
+ const CPUData* cpuData = &(pl->cpus[cpu]);
+ double total = cpuData->totalPeriod == 0 ? 1 : cpuData->totalPeriod;
+ double totalPercent;
double *v = this->values;
- size_t size = sizeof(double) * CPUSTATES;
- int mib[] = { CTL_KERN, KERN_CPTIME2, cpu-1 };
- if (sysctl(mib, 3, new_v, &size, NULL, 0) == -1) {
- return 0.;
- }
-
- // XXX: why?
- cpuData->totalPeriod = 1;
-
- percentages(CPUSTATES, diff_v, new_v,
- (int64_t *)old_v[cpu-1], scratch_v);
- for (i = 0; i < CPUSTATES; i++) {
- old_v[cpu-1][i] = new_v[i];
- v[i] = diff_v[i] / 10.;
- }
-
- Meter_setItems(this, 4);
-
- perc = v[0] + v[1] + v[2] + v[3];
-
- if (perc <= 100. && perc >= 0.) {
- return perc;
+ v[CPU_METER_NICE] = cpuData->nicePeriod / total * 100.0;
+ v[CPU_METER_NORMAL] = cpuData->userPeriod / total * 100.0;
+ if (this->pl->settings->detailedCPUTime) {
+ v[CPU_METER_KERNEL] = cpuData->sysPeriod / total * 100.0;
+ v[CPU_METER_IRQ] = cpuData->intrPeriod / total * 100.0;
+ v[CPU_METER_SOFTIRQ] = 0.0;
+ v[CPU_METER_STEAL] = 0.0;
+ v[CPU_METER_GUEST] = 0.0;
+ v[CPU_METER_IOWAIT] = 0.0;
+ v[CPU_METER_FREQUENCY] = -1;
+ Meter_setItems(this, 8);
+ totalPercent = v[0]+v[1]+v[2]+v[3];
} else {
- return 0.;
+ v[2] = cpuData->sysAllPeriod / total * 100.0;
+ v[3] = 0.0; // No steal nor guest on OpenBSD
+ totalPercent = v[0]+v[1]+v[2];
+ Meter_setItems(this, 4);
}
+
+ totalPercent = CLAMP(totalPercent, 0.0, 100.0);
+ if (isnan(totalPercent)) totalPercent = 0.0;
+ return totalPercent;
}
void Platform_setMemoryValues(Meter* this) {
diff --git a/openbsd/Platform.h b/openbsd/Platform.h
index e0da7b9f..56e4c400 100644
--- a/openbsd/Platform.h
+++ b/openbsd/Platform.h
@@ -17,21 +17,6 @@ in the source distribution for its full text.
extern ProcessFieldData Process_fields[];
-#define MAXCPU 256
-// XXX: probably should be a struct member
-/*
- * Copyright (c) 1984, 1989, William LeFebvre, Rice University
- * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
- *
- * Taken directly from OpenBSD's top(1).
- *
- * percentages(cnt, out, new, old, diffs) - calculate percentage change
- * between array "old" and "new", putting the percentages in "out".
- * "cnt" is size of each array and "diffs" is used for scratch space.
- * The array "old" is updated on each call.
- * The routine assumes modulo arithmetic. This function is especially
- * useful on BSD machines for calculating cpu state percentages.
- */
extern ProcessField Platform_defaultFields[];
extern int Platform_numberOfFields;
diff --git a/scripts/MakeHeader.py b/scripts/MakeHeader.py
index 349531b8..3ef34b88 100755
--- a/scripts/MakeHeader.py
+++ b/scripts/MakeHeader.py
@@ -54,8 +54,10 @@ for line in file.readlines():
elif line.startswith("typedef struct"):
state = SKIP
elif line[-1] == "{":
- out.write( line[:-2].replace("inline", "extern") + ";\n" )
+ out.write("extern " + line[:-2].replace("inline ", "") + ";\n")
state = SKIP
+ elif line[-1] == ";":
+ out.write("extern " + line + "\n")
else:
out.write( line + "\n")
is_blank = False
diff --git a/solaris/Platform.c b/solaris/Platform.c
index 7dcfe323..092f4507 100644
--- a/solaris/Platform.c
+++ b/solaris/Platform.c
@@ -50,7 +50,7 @@ typedef struct var kvar_t;
typedef struct envAccum_ {
size_t capacity;
size_t size;
- size_t bytes;
+ size_t bytes;
char *env;
} envAccum;
@@ -140,7 +140,7 @@ extern char Process_pidFormat[20];
int Platform_getUptime() {
int boot_time = 0;
- int curr_time = time(NULL);
+ int curr_time = time(NULL);
struct utmpx * ent;
while (( ent = getutxent() )) {
@@ -174,7 +174,7 @@ int Platform_getMaxPid() {
vproc = ksvar->v_proc;
}
if (kc != NULL) { kstat_close(kc); }
- return vproc;
+ return vproc;
}
double Platform_setCPUValues(Meter* this, int cpu) {
@@ -207,6 +207,9 @@ double Platform_setCPUValues(Meter* this, int cpu) {
percent = CLAMP(percent, 0.0, 100.0);
if (isnan(percent)) percent = 0.0;
+
+ v[CPU_METER_FREQUENCY] = -1;
+
return percent;
}
@@ -239,7 +242,7 @@ void Platform_setZfsCompressedArcValues(Meter* this) {
static int Platform_buildenv(void *accum, struct ps_prochandle *Phandle, uintptr_t addr, const char *str) {
envAccum *accump = accum;
(void) Phandle;
- (void) addr;
+ (void) addr;
size_t thissz = strlen(str);
if ((thissz + 2) > (accump->capacity - accump->size))
accump->env = xRealloc(accump->env, accump->capacity *= 2);
@@ -248,7 +251,7 @@ static int Platform_buildenv(void *accum, struct ps_prochandle *Phandle, uintptr
strlcpy( accump->env + accump->size, str, (accump->capacity - accump->size));
strncpy( accump->env + accump->size + thissz + 1, "\n", 1);
accump->size = accump->size + thissz + 1;
- return 0;
+ return 0;
}
char* Platform_getProcessEnv(pid_t pid) {
@@ -256,7 +259,7 @@ char* Platform_getProcessEnv(pid_t pid) {
pid_t realpid = pid / 1024;
int graberr;
struct ps_prochandle *Phandle;
-
+
if ((Phandle = Pgrab(realpid,PGRAB_RDONLY,&graberr)) == NULL)
return "Unable to read process environment.";
@@ -264,7 +267,7 @@ char* Platform_getProcessEnv(pid_t pid) {
envBuilder.size = 0;
envBuilder.env = xMalloc(envBuilder.capacity);
- (void) Penv_iter(Phandle,Platform_buildenv,&envBuilder);
+ (void) Penv_iter(Phandle,Platform_buildenv,&envBuilder);
Prelease(Phandle, 0);
diff --git a/solaris/Platform.h b/solaris/Platform.h
index 3b5aef86..dd1962dd 100644
--- a/solaris/Platform.h
+++ b/solaris/Platform.h
@@ -27,7 +27,7 @@ typedef struct var kvar_t;
typedef struct envAccum_ {
size_t capacity;
size_t size;
- size_t bytes;
+ size_t bytes;
char *env;
} envAccum;
diff --git a/solaris/SolarisProcess.c b/solaris/SolarisProcess.c
index 31f488ef..514453fd 100644
--- a/solaris/SolarisProcess.c
+++ b/solaris/SolarisProcess.c
@@ -90,7 +90,7 @@ ProcessFieldData Process_fields[] = {
[PROCESSOR] = { .name = "PROCESSOR", .title = "CPU ", .description = "Id of the CPU the process last executed on", .flags = 0, },
[M_SIZE] = { .name = "M_SIZE", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, },
[M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, },
- [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
+ [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
[PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, },
[PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, },
[USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
diff --git a/solaris/SolarisProcessList.c b/solaris/SolarisProcessList.c
index d62ea1d4..8faa49f3 100644
--- a/solaris/SolarisProcessList.c
+++ b/solaris/SolarisProcessList.c
@@ -25,6 +25,8 @@ in the source distribution for its full text.
#define MAXCMDLINE 255
+#define GZONE "global "
+#define UZONE "unknown "
/*{
#include "zfs/ZfsArcStats.h"
@@ -65,12 +67,12 @@ typedef struct SolarisProcessList_ {
char* SolarisProcessList_readZoneName(kstat_ctl_t* kd, SolarisProcess* sproc) {
char* zname;
if ( sproc->zoneid == 0 ) {
- zname = xStrdup("global ");
+ zname = xStrdup(GZONE);
} else if ( kd == NULL ) {
- zname = xStrdup("unknown ");
+ zname = xStrdup(UZONE);
} else {
kstat_t* ks = kstat_lookup( kd, "zones", sproc->zoneid, NULL );
- zname = xStrdup(ks->ks_name);
+ zname = xStrdup(ks == NULL ? UZONE : ks->ks_name);
}
return zname;
}
@@ -156,7 +158,7 @@ static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) {
idlebuf += cpuData->idlePercent;
}
}
-
+
if (cpus > 1) {
CPUData* cpuData = &(spl->cpus[0]);
cpuData->userPercent = userbuf / cpus;
@@ -180,7 +182,7 @@ static inline void SolarisProcessList_scanMemoryInfo(ProcessList* pl) {
uint64_t totalswap = 0;
uint64_t totalfree = 0;
int nswap = 0;
- char *spath = NULL;
+ char *spath = NULL;
char *spathbase = NULL;
// Part 1 - physical memory
@@ -194,7 +196,7 @@ static inline void SolarisProcessList_scanMemoryInfo(ProcessList* pl) {
pl->totalMem = totalmem_pgs->value.ui64 * PAGE_SIZE_KB;
pl->usedMem = lockedmem_pgs->value.ui64 * PAGE_SIZE_KB;
// Not sure how to implement this on Solaris - suggestions welcome!
- pl->cachedMem = 0;
+ pl->cachedMem = 0;
// Not really "buffers" but the best Solaris analogue that I can find to
// "memory in use but not by programs or the kernel itself"
pl->buffersMem = (totalmem_pgs->value.ui64 - pages->value.ui64) * PAGE_SIZE_KB;
@@ -205,12 +207,12 @@ static inline void SolarisProcessList_scanMemoryInfo(ProcessList* pl) {
pl->cachedMem = 0;
pl->usedMem = pl->totalMem - (sysconf(_SC_AVPHYS_PAGES) * PAGE_SIZE);
}
-
+
// Part 2 - swap
nswap = swapctl(SC_GETNSWP, NULL);
if (nswap > 0) { sl = xMalloc((nswap * sizeof(swapent_t)) + sizeof(int)); }
if (sl != NULL) { spathbase = xMalloc( nswap * MAXPATHLEN ); }
- if (spathbase != NULL) {
+ if (spathbase != NULL) {
spath = spathbase;
swapdev = sl->swt_ent;
for (int i = 0; i < nswap; i++, swapdev++) {
@@ -220,7 +222,7 @@ static inline void SolarisProcessList_scanMemoryInfo(ProcessList* pl) {
sl->swt_n = nswap;
}
nswap = swapctl(SC_LIST, sl);
- if (nswap > 0) {
+ if (nswap > 0) {
swapdev = sl->swt_ent;
for (int i = 0; i < nswap; i++, swapdev++) {
totalswap += swapdev->ste_pages;
@@ -230,7 +232,7 @@ static inline void SolarisProcessList_scanMemoryInfo(ProcessList* pl) {
free(spathbase);
free(sl);
pl->totalSwap = totalswap * PAGE_SIZE_KB;
- pl->usedSwap = pl->totalSwap - (totalfree * PAGE_SIZE_KB);
+ pl->usedSwap = pl->totalSwap - (totalfree * PAGE_SIZE_KB);
}
static inline void SolarisProcessList_scanZfsArcstats(ProcessList* pl) {
@@ -288,7 +290,7 @@ void ProcessList_delete(ProcessList* pl) {
* and MUST conform to the appropriate definition in order
* to work. See libproc(3LIB) on a Solaris or Illumos
* system for more info.
- */
+ */
int SolarisProcessList_walkproc(psinfo_t *_psinfo, lwpsinfo_t *_lwpsinfo, void *listptr) {
struct timeval tv;
@@ -308,7 +310,7 @@ int SolarisProcessList_walkproc(psinfo_t *_psinfo, lwpsinfo_t *_lwpsinfo, void *
getpid = _psinfo->pr_pid * 1024;
} else {
getpid = lwpid;
- }
+ }
Process *proc = ProcessList_getProcess(pl, getpid, &preExisting, (Process_New) SolarisProcess_new);
SolarisProcess *sproc = (SolarisProcess*) proc;
@@ -339,7 +341,7 @@ int SolarisProcessList_walkproc(psinfo_t *_psinfo, lwpsinfo_t *_lwpsinfo, void *
sproc->realpid = _psinfo->pr_pid;
sproc->lwpid = lwpid_real;
sproc->zoneid = _psinfo->pr_zoneid;
- sproc->zname = SolarisProcessList_readZoneName(spl->kd,sproc);
+ sproc->zname = SolarisProcessList_readZoneName(spl->kd,sproc);
proc->user = UsersTable_getRef(pl->usersTable, proc->st_uid);
proc->comm = xStrdup(_psinfo->pr_fname);
proc->commLen = strnlen(_psinfo->pr_fname,PRFNSZ);
@@ -378,7 +380,7 @@ int SolarisProcessList_walkproc(psinfo_t *_psinfo, lwpsinfo_t *_lwpsinfo, void *
proc->percent_cpu = ((uint16_t)_lwpsinfo->pr_pctcpu/(double)32768)*(double)100.0;
proc->time = _lwpsinfo->pr_time.tv_sec;
if (!preExisting) { // Tasks done only for NEW LWPs
- sproc->is_lwp = true;
+ sproc->is_lwp = true;
proc->basenameOffset = -1;
proc->ppid = _psinfo->pr_pid * 1024;
proc->tgid = _psinfo->pr_pid * 1024;
diff --git a/solaris/SolarisProcessList.h b/solaris/SolarisProcessList.h
index 26bf4491..06c1330e 100644
--- a/solaris/SolarisProcessList.h
+++ b/solaris/SolarisProcessList.h
@@ -12,6 +12,8 @@ in the source distribution for its full text.
#define MAXCMDLINE 255
+#define GZONE "global "
+#define UZONE "unknown "
#include "zfs/ZfsArcStats.h"
@@ -57,7 +59,7 @@ void ProcessList_delete(ProcessList* pl);
* and MUST conform to the appropriate definition in order
* to work. See libproc(3LIB) on a Solaris or Illumos
* system for more info.
- */
+ */
int SolarisProcessList_walkproc(psinfo_t *_psinfo, lwpsinfo_t *_lwpsinfo, void *listptr);
diff --git a/unsupported/Platform.c b/unsupported/Platform.c
index ba844191..0e46a348 100644
--- a/unsupported/Platform.c
+++ b/unsupported/Platform.c
@@ -50,7 +50,7 @@ ProcessFieldData Process_fields[] = {
[PROCESSOR] = { .name = "PROCESSOR", .title = "CPU ", .description = "Id of the CPU the process last executed on", .flags = 0, },
[M_SIZE] = { .name = "M_SIZE", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, },
[M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, },
- [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
+ [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
[PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, },
[PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, },
[USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
@@ -108,8 +108,11 @@ int Platform_getMaxPid() {
}
double Platform_setCPUValues(Meter* this, int cpu) {
- (void) this;
(void) cpu;
+
+ double* v = this->values;
+ v[CPU_METER_FREQUENCY] = -1;
+
return 0.0;
}
diff --git a/unsupported/UnsupportedProcessList.c b/unsupported/UnsupportedProcessList.c
index 9be4eee4..65749b18 100644
--- a/unsupported/UnsupportedProcessList.c
+++ b/unsupported/UnsupportedProcessList.c
@@ -18,7 +18,7 @@ in the source distribution for its full text.
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
ProcessList* this = xCalloc(1, sizeof(ProcessList));
ProcessList_init(this, Class(Process), usersTable, pidWhiteList, userId);
-
+
return this;
}

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