59 Commits

Author SHA1 Message Date
691b7dd5af Merge branch 'cgzones-readme' 2021-09-20 16:31:31 +10:00
ad0f9c58bf Merge branch 'readme' of https://github.com/cgzones/htop into cgzones-readme 2021-09-20 16:31:24 +10:00
a8d0f2a7fe Merge branch 'cgzones-multicolumn' 2021-09-20 16:30:18 +10:00
e6596cbd69 Merge branch 'multicolumn' of https://github.com/cgzones/htop into cgzones-multicolumn 2021-09-20 16:29:44 +10:00
40c9f89971 Merge branch 'cgzones-mouse' 2021-09-20 16:29:17 +10:00
09ad8067f4 Merge branch 'mouse' of https://github.com/cgzones/htop into cgzones-mouse 2021-09-20 16:29:05 +10:00
bda3ee2b81 Update ReadMe
Add license and repology badge, improve several wording, improve
several sections.

[skip ci]
2021-09-19 14:47:32 +02:00
bdb015ffa3 Header: do not let multi-column meters expand to empty neighbors
Extending to right neighbors is intended for text meters with an
overlong content, so the whole text is shown if possible.
Multi column meters, like the combined memory and swap meter, position
its text depending on the given total width; keep the position to the
original assigned header slot.

Short term resolution for #796
2021-09-18 17:21:32 +02:00
80a515abcc Fix typo 2021-09-18 15:55:21 +02:00
5000cefc13 Fix typo in gettime implementation on darwin 2021-09-18 14:14:23 +02:00
bf7d98e7ac MainPanel: do not reset on disabled mouse events
Do not reset the hidden process selection (and hidden function bar) on mouse events, when mouse support is disabled.
2021-09-18 11:48:32 +02:00
c096712b8d Merge pull request #779 from BenBE/percent-highlight
Highlight percentages similar to large numbers
2021-09-14 12:53:33 +10:00
be82448bd5 Process_printPercentage using one color transition
Update Process_printPercentage such that color change happens only once at 100% and beyond.
2021-09-14 11:16:34 +10:00
68c00b9cdb Header: cache number of columns in HeaderLayout_getColumns
The header layout, and therefore the number of columns, should never
be changed within such loop.
2021-09-12 18:35:24 +02:00
3c8d586a1c Linux: recalculate LRS value
The LRS value is only zero in the first cycle; drop the check to
recalculate while running.
2021-09-12 18:20:40 +02:00
3869c43393 valgrind: rewrite ncurses suppressions
Simplify and update valgrind suppressions for possible leak and
reachable memory inside ncurses.
2021-09-11 00:07:23 +02:00
fcca4c2f2d valgrind: track origin of uninitialised values 2021-09-11 00:07:23 +02:00
dd88510dcd HeaderOptionsPanel: select the current not saved option
Select the current active header layout, not the current saved layout
from the settings, as the value gets only saved back from the active
header to settings on closing the setup menu.

Closes: #785
2021-09-11 00:06:41 +02:00
43ffdb0eda Linux: zero CPU data after allocation
Zero all the CPU data, like totalPeriod, after its memory allocation via
realloc(3).

    Conditional jump or move depends on uninitialised value(s)
       at 0x132A9B: LinuxProcessList_scanCPUTime (LinuxProcessList.c:1928)
       by 0x1358C3: ProcessList_goThroughEntries (LinuxProcessList.c:2079)
        by 0x12A79A: ProcessList_scan (ProcessList.c:627)
        by 0x11CA67: CommandLine_run (CommandLine.c:357)
        by 0x4A81E49: (below main) (libc-start.c:314)
      Uninitialised value was created by a heap allocation
        at 0x48396C5: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
        by 0x12F633: xRealloc (XUtils.c:64)
        by 0x12F633: xReallocArray (XUtils.c:78)
        by 0x1325A8: LinuxProcessList_updateCPUcount (LinuxProcessList.c:207)
        by 0x134E0A: ProcessList_new (LinuxProcessList.c:284)
        by 0x11C8D0: CommandLine_run (CommandLine.c:301)
        by 0x4A81E49: (below main) (libc-start.c:314)
2021-09-11 00:04:00 +02:00
bf395e10c5 Add xReallocArrayZero() helper
Add helper function to reallocate an dynamic allocated array including
zeroing the newly allocated memory.
2021-09-11 00:04:00 +02:00
8f259bc5e1 MemorySwapMeter: align with CPU meter
Use the same width for each sub meter to align with CPU meter.
Currently if the total width is even, so it does not split exactly into
2 equal parts plus 1 (for the middle space character column), the extra
column is added to the second meter width.

Closes: #783
2021-09-10 17:09:48 +02:00
38e6136b82 CRT: close backup stderr file after reset
Close the backup file descriptor of original stderr once it has been
restored at stderr.
2021-09-10 17:01:26 +02:00
589b0733d9 Settings: set ok when reading configuration from sysconfdir
Without this htoprc from sysconfdir is ignored and default meters
are loaded.
2021-09-10 08:58:58 +02:00
c9b58c7fbe Add missing end-of-line to htoprc file version mismatch warning 2021-09-08 12:13:56 +10:00
ca06e68037 Fix a typo in a configure.ac comment 2021-09-08 12:11:58 +10:00
a516e0852e Update configure to reflect rc2 in the version 2021-09-05 19:07:29 +02:00
3f805cf347 Highlight large percentages similar to large memory columns 2021-09-05 18:49:05 +02:00
556d7c03e8 Add a Process_printPercentage helper routine
Replace several open-coded variants of percentage formatting.
This function has been ported from Hishams old 'next' branch.
2021-09-05 18:47:07 +02:00
0925c54caa Drop redundant semicolons 2021-09-04 14:17:37 +02:00
d0f5b61aa5 hwloc: use int in hwloc_bitmap_foreach_begin loop
Affinity.c:67:10: runtime error: implicit conversion from type 'int' of value -1 (32-bit, signed) to type 'unsigned int' changed the value to 4294967295 (32-bit, unsigned)
2021-09-04 09:48:53 +02:00
284f8c5e0b configure: output vserver as implied if ancient-vserver is enabled
The build time configuration ancient-vserver implies the configuration
vserver; say so in the configure status report if only ancient-vserver
has been specified.

Also indent with 3 spaces.
2021-09-04 09:48:53 +02:00
11b65a2861 Header: use upper case floating point suffix 2021-09-04 09:48:53 +02:00
b85b718e69 Settings: enclose casted macro argument in parenthesis 2021-09-04 09:48:53 +02:00
7891cdc552 Reduce variable scope
Also avoid declaring variables of different type, pointer and array, in
the same line.
2021-09-04 09:48:53 +02:00
b9fdf1c2a1 ColumnsPanel: drop unused struct declaration 2021-09-04 09:48:53 +02:00
2844429f15 NetBSD: scale CPU frequencies
Use a value type of 'long int' to avoid ENOMEM failures of sysctl(3).

Also check for "machdep.tsc_freq", scaled in MHz.
2021-09-03 12:17:45 +02:00
3834f2a68f NetBSD: misc const additions 2021-09-03 12:17:45 +02:00
343c2e58be NetBSD: update process fields
Populate fields to ttyname, minflt, majflt and processor.
2021-09-03 12:17:45 +02:00
fd2c4f5ddd NetBSD: fix reading environment variables of processes
kvm_getenvv(3) seems not to work with kvm_openfiles(..., KVM_NO_FILES,
...)
2021-09-03 12:17:45 +02:00
7f95ed8528 NetBSD: simplify Platform_setMemoryValues 2021-09-03 12:17:45 +02:00
9579d9b7aa NetBSD: silence dropping const qualifier on define_key(3)
On NetBSD define_key(3) has the prototype

    int define_key(char *sequence, int key_symbol);
2021-09-03 12:17:45 +02:00
0580dbb202 NetBSD: color process state P as running
On NetBSD state 'R' means runnable not running.

Improve the color identifier name accordingly.
2021-09-03 12:17:45 +02:00
c0c2bb98a2 Add completion handling for dynamic meters and columns
Be sure to free dynamic memory allocated for meters and
columns strings, no-op on platforms other than pcp.

Closes #774
2021-09-03 09:47:01 +02:00
9b30870eec Merge pull request #775 from cgzones/pcp
PCP: do not set exe to empty string
2021-09-03 12:08:00 +10:00
25c945e2ef PCP: do not set exe to empty string
In case the executable is an empty string, e.g. if pcp is run by an
unprivileged user, do not set procExe to an empty value, which breaks
the formatting of the PROCEXE column and the merged-cmdline logic.
2021-09-02 23:37:53 +02:00
f94934472f Linux: rework disk-io parsing
Generalize sub-diskname handling, like sdb1/sdb2, to not count the
usage twice with the aggregate top-diskname, like sdb.
Rely on /proc/diskstats being ordered, e.g. no sub-diskname precedes its
top-diskname.

Closes: #675
2021-09-02 22:12:58 +02:00
becd33795c Settings: create default meters on no existing config file
If htop is started for the first time and no configuration file exists
the header is empty cause no meters are added as a default.

Add the default meters if parsing all available configuration paths
failed.
2021-09-02 08:03:21 +02:00
74f99e3693 linux: simplify recheck condition
`recheck` is calculated modulo 2048, so its maximum value is 2047.
Drop the quite similar (up to 27 milliseconds) explicit check against
2000.
2021-09-02 08:03:21 +02:00
e1f4645bd1 Process: drop unused merged-command bit fields 2021-09-02 08:03:21 +02:00
0afd0fe572 linux: color void delay accounting values gray
Use the color gray, similar to other process fields, if the delay
accounting value is either 0 (or very small) or cannot be accessed, e.g.
by an unprivileged user.
2021-09-02 08:03:21 +02:00
ff336b652c linux: drop unused macro IOPriority_error 2021-09-02 08:03:21 +02:00
58a59c11f4 linux: drop dead process field column DIRTY
The field for dirty pages in /proc/[pid]/statm is always 0 since Linux
2.6 (see man:proc(5)).
2021-09-02 08:03:21 +02:00
3f806368e0 CPUMeter: use correct buffer size 2021-09-02 08:03:21 +02:00
4855d92469 travis-ci: update
Drop explicit CFLAGS specification as `-Wno-c11-extensions` is enabled
on FreeBSD by the configure script.

Run and check `make install` and `make installcheck`.
2021-09-02 08:03:21 +02:00
b81bb9038c Fix resource leaks dealing with unrecognised config file version
Plug leaks of an open file descriptor and dynamically allocated
'option' when we bail out early reading unknown config version.
2021-08-31 08:08:01 +02:00
1f2f567ca1 Fix meterPanels size calculation for dynamic array allocation 2021-08-31 08:08:01 +02:00
393330239e Small editorial fixes to ChangeLog 2021-08-27 09:31:06 +02:00
d2c34259b4 Remove trailing whitespace in changelog for CI checks 2021-08-27 12:19:50 +10:00
858ad8029d Update configure to reflect rc1 in the version 2021-08-27 12:14:23 +10:00
55 changed files with 420 additions and 297 deletions

View File

@ -9,7 +9,8 @@ os:
script:
- ./autogen.sh
# clang might warn about C11 generic selections in isnan()
- CFLAGS=-Wno-c11-extensions ./configure --enable-werror
- ./configure --enable-werror
- make -k
- CFLAGS=-Wno-c11-extensions make distcheck DISTCHECK_CONFIGURE_FLAGS=--enable-werror
- make distcheck DISTCHECK_CONFIGURE_FLAGS=--enable-werror
- sudo make install
- make installcheck

View File

@ -63,9 +63,9 @@ Affinity* Affinity_get(const Process* proc, ProcessList* pl) {
Affinity_add(affinity, i);
}
} else {
unsigned int id;
hwloc_bitmap_foreach_begin(id, cpuset);
Affinity_add(affinity, id);
int id;
hwloc_bitmap_foreach_begin(id, cpuset)
Affinity_add(affinity, (unsigned)id);
hwloc_bitmap_foreach_end();
}
}

View File

@ -425,9 +425,9 @@ Affinity* AffinityPanel_getAffinity(Panel* super, ProcessList* pl) {
Affinity* affinity = Affinity_new(pl);
#ifdef HAVE_LIBHWLOC
unsigned int i;
int i;
hwloc_bitmap_foreach_begin(i, this->workCpuset)
Affinity_add(affinity, i);
Affinity_add(affinity, (unsigned)i);
hwloc_bitmap_foreach_end();
#else
for (int i = 0; i < Vector_size(this->cpuids); i++) {

View File

@ -52,9 +52,9 @@ static void CPUMeter_init(Meter* this) {
// Custom uiName runtime logic to include the param (processor)
static void CPUMeter_getUiName(const Meter* this, char* buffer, size_t length) {
if (this->param > 0)
xSnprintf(buffer, sizeof(length), "%s %u", Meter_uiName(this), this->param);
xSnprintf(buffer, length, "%s %u", Meter_uiName(this), this->param);
else
xSnprintf(buffer, sizeof(length), "%s", Meter_uiName(this));
xSnprintf(buffer, length, "%s", Meter_uiName(this));
}
static void CPUMeter_updateValues(Meter* this) {
@ -381,6 +381,7 @@ const MeterClass AllCPUs2Meter_class = {
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "AllCPUs2",
@ -401,6 +402,7 @@ const MeterClass LeftCPUsMeter_class = {
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "LeftCPUs",
@ -421,6 +423,7 @@ const MeterClass RightCPUsMeter_class = {
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "RightCPUs",
@ -441,6 +444,7 @@ const MeterClass LeftCPUs2Meter_class = {
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "LeftCPUs2",
@ -461,6 +465,7 @@ const MeterClass RightCPUs2Meter_class = {
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "RightCPUs2",
@ -481,6 +486,7 @@ const MeterClass AllCPUs4Meter_class = {
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "AllCPUs4",
@ -501,6 +507,7 @@ const MeterClass LeftCPUs4Meter_class = {
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "LeftCPUs4",
@ -521,6 +528,7 @@ const MeterClass RightCPUs4Meter_class = {
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "RightCPUs4",
@ -541,6 +549,7 @@ const MeterClass AllCPUs8Meter_class = {
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "AllCPUs8",
@ -561,6 +570,7 @@ const MeterClass LeftCPUs8Meter_class = {
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "LeftCPUs8",
@ -581,6 +591,7 @@ const MeterClass RightCPUs8Meter_class = {
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "RightCPUs8",

22
CRT.c
View File

@ -138,7 +138,7 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[PROCESS_GIGABYTES] = ColorPair(Green, Black),
[PROCESS_BASENAME] = A_BOLD | ColorPair(Cyan, Black),
[PROCESS_TREE] = ColorPair(Cyan, Black),
[PROCESS_R_STATE] = ColorPair(Green, Black),
[PROCESS_RUN_STATE] = ColorPair(Green, Black),
[PROCESS_D_STATE] = A_BOLD | ColorPair(Red, Black),
[PROCESS_HIGH_PRIORITY] = ColorPair(Red, Black),
[PROCESS_LOW_PRIORITY] = ColorPair(Green, Black),
@ -240,7 +240,7 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[PROCESS_GIGABYTES] = A_BOLD,
[PROCESS_BASENAME] = A_BOLD,
[PROCESS_TREE] = A_BOLD,
[PROCESS_R_STATE] = A_BOLD,
[PROCESS_RUN_STATE] = A_BOLD,
[PROCESS_D_STATE] = A_BOLD,
[PROCESS_HIGH_PRIORITY] = A_BOLD,
[PROCESS_LOW_PRIORITY] = A_DIM,
@ -342,7 +342,7 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[PROCESS_GIGABYTES] = ColorPair(Green, White),
[PROCESS_BASENAME] = ColorPair(Blue, White),
[PROCESS_TREE] = ColorPair(Green, White),
[PROCESS_R_STATE] = ColorPair(Green, White),
[PROCESS_RUN_STATE] = ColorPair(Green, White),
[PROCESS_D_STATE] = A_BOLD | ColorPair(Red, White),
[PROCESS_HIGH_PRIORITY] = ColorPair(Red, White),
[PROCESS_LOW_PRIORITY] = ColorPair(Green, White),
@ -444,7 +444,7 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[PROCESS_GIGABYTES] = ColorPair(Green, Black),
[PROCESS_BASENAME] = ColorPair(Green, Black),
[PROCESS_TREE] = ColorPair(Blue, Black),
[PROCESS_R_STATE] = ColorPair(Green, Black),
[PROCESS_RUN_STATE] = ColorPair(Green, Black),
[PROCESS_D_STATE] = A_BOLD | ColorPair(Red, Black),
[PROCESS_HIGH_PRIORITY] = ColorPair(Red, Black),
[PROCESS_LOW_PRIORITY] = ColorPair(Green, Black),
@ -546,7 +546,7 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[PROCESS_GIGABYTES] = ColorPair(Green, Blue),
[PROCESS_BASENAME] = A_BOLD | ColorPair(Cyan, Blue),
[PROCESS_TREE] = ColorPair(Cyan, Blue),
[PROCESS_R_STATE] = ColorPair(Green, Blue),
[PROCESS_RUN_STATE] = ColorPair(Green, Blue),
[PROCESS_D_STATE] = A_BOLD | ColorPair(Red, Blue),
[PROCESS_HIGH_PRIORITY] = ColorPair(Red, Blue),
[PROCESS_LOW_PRIORITY] = ColorPair(Green, Blue),
@ -652,7 +652,7 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[PROCESS_THREAD_BASENAME] = A_BOLD | ColorPair(Blue, Black),
[PROCESS_COMM] = ColorPair(Magenta, Black),
[PROCESS_THREAD_COMM] = ColorPair(Yellow, Black),
[PROCESS_R_STATE] = ColorPair(Green, Black),
[PROCESS_RUN_STATE] = ColorPair(Green, Black),
[PROCESS_D_STATE] = A_BOLD | ColorPair(Red, Black),
[PROCESS_HIGH_PRIORITY] = ColorPair(Red, Black),
[PROCESS_LOW_PRIORITY] = ColorPair(Green, Black),
@ -772,6 +772,8 @@ static void dumpStderr(void) {
fsync(STDERR_FILENO);
dup2(stderrRedirectBackupFd, STDERR_FILENO);
close(stderrRedirectBackupFd);
stderrRedirectBackupFd = -1;
lseek(stderrRedirectNewFd, 0, SEEK_SET);
bool header = false;
@ -886,6 +888,10 @@ void CRT_init(const Settings* settings, bool allowUnicode) {
}
if (termType && (String_startsWith(termType, "xterm") || String_eq(termType, "vt220"))) {
#ifdef HTOP_NETBSD
#define define_key(s_, k_) define_key((char*)s_, k_)
IGNORE_WCASTQUAL_BEGIN
#endif
define_key("\033[H", KEY_HOME);
define_key("\033[F", KEY_END);
define_key("\033[7~", KEY_HOME);
@ -906,6 +912,10 @@ void CRT_init(const Settings* settings, bool allowUnicode) {
sequence[1] = c;
define_key(sequence, KEY_ALT('A' + (c - 'a')));
}
#ifdef HTOP_NETBSD
IGNORE_WCASTQUAL_END
#undef define_key
#endif
}
CRT_installSignalHandlers();

2
CRT.h
View File

@ -74,7 +74,7 @@ typedef enum ColorElements_ {
PROCESS_MEGABYTES,
PROCESS_GIGABYTES,
PROCESS_TREE,
PROCESS_R_STATE,
PROCESS_RUN_STATE,
PROCESS_D_STATE,
PROCESS_BASENAME,
PROCESS_HIGH_PRIORITY,

View File

@ -40,7 +40,7 @@ static void CategoriesPanel_delete(Object* object) {
static void CategoriesPanel_makeMetersPage(CategoriesPanel* this) {
size_t columns = HeaderLayout_getColumns(this->scr->header->headerLayout);
MetersPanel** meterPanels = xMallocArray(columns, sizeof(MetersPanel));
MetersPanel** meterPanels = xMallocArray(columns, sizeof(MetersPanel*));
for (size_t i = 0; i < columns; i++) {
char titleBuffer[32];

View File

@ -1,6 +1,5 @@
What's new in version 3.1.0
* Updated COPYING file to remove the PLPA exemption (appendix 2)
With this change the license is now GPLv2 without any additional wording.
* Improved default sort ordering
@ -26,10 +25,11 @@ What's new in version 3.1.0
Moving this column to be handled as a platform-independently available
information simplifies the markup of the command line.
* Introduce configuration file versioning and config_reader_min_version
Starting with this version the configuration file contains an version
Starting with this version the configuration file contains a version
identifying the minimum version of the configuration parser needed to
fully understand the configuration file format.
Old configuration file formats are automatically upgraded on startup.
Old configuration file formats are automatically upgraded when
saving the config file (htoprc).
* Make the configuration parser friendlier to users (thanks to Bart Bakker)
With this change only settings that cannot be parsed properly are
reset to their defaults.
@ -48,12 +48,12 @@ What's new in version 3.1.0
* Option and key ("*") to collapse / expand all branches under PID 1
(and PID 2 if kernel threads are shown) (thanks to Krishna Chaitanya)
* Keep following a process when inverting the sort order, displaying
the help screen or hiding/unhiding userland threads
the help screen or hiding/unhiding userland threads.
If a thread is currently selected the selection is updated to point
to the thread's parent process. (thanks to Gonzalo, et.al.)
* Reorder process scanning to be performed before updating the display
of the meters in the header
* Always check the user for a process for any changes
* Always check the user for a process for any changes.
This affects multiple platforms that previously didn't correctly handle
the user field for a process to change at runtime (e.g. due to seteuid
or similar syscalls).
@ -105,14 +105,14 @@ What's new in version 3.1.0
* Correctly color the ZFS ARC ratio (thanks to Ross Williams)
* Bugfixes related to CPU time display/calculations for darwin on M1 systems
(thanks to Alexander Momchilov)
* Harmonize the handling of multiple batteries across different platforms
* Harmonize the handling of multiple batteries across different platforms.
The system is now considered to run on AC if at least one power supply
marked as AC is found in the system.
Battery capacity is summed up over all batteries found.
This also changes the old behavior that batteries reported by the
system after the first AC adapter where sometimes ignored.
* Correctly handle multiple batteries on Darwin
Resolves a possible memory leak on systems with multiple batteries
* Correctly handle multiple batteries on Darwin.
Resolves a possible memory leak on systems with multiple batteries.
* Handle Linux Shmem being part of Cached in the MemoryMeter
* Add SwapCached to the Linux swap meter (thanks to David Zarzycki)
* Convert process time to days if applicable (thanks to David Zarzycki)
@ -138,7 +138,7 @@ What's new in version 3.1.0
* Add command line option to drop Linux capabilities
* Support scheduler affinity on platforms beyond Linux
* Report on any failure to write the configuration file
* Cache stderr to be able to print assert messages
* Cache stderr to be able to print assert messages.
These messages are shown in case htop terminates unexpectedly.
* Print current settings on crash
* Reset signal handlers on program exit

View File

@ -118,12 +118,6 @@ const PanelClass ColumnsPanel_class = {
.eventHandler = ColumnsPanel_eventHandler
};
typedef struct {
Panel* super;
unsigned int id;
unsigned int offset;
} DynamicIterator;
static void ColumnsPanel_add(Panel* super, unsigned int key, Hashtable* columns) {
const char* name;
if (key < LAST_PROCESSFIELD) {

View File

@ -393,10 +393,8 @@ int CommandLine_run(const char* name, int argc, char** argv) {
/* Delete these last, since they can get accessed in the crash handler */
Settings_delete(settings);
if (dc)
Hashtable_delete(dc);
if (dm)
Hashtable_delete(dm);
DynamicColumns_delete(dc);
DynamicMeters_delete(dm);
return 0;
}

View File

@ -22,6 +22,13 @@ Hashtable* DynamicColumns_new(void) {
return Platform_dynamicColumns();
}
void DynamicColumns_delete(Hashtable* dynamics) {
if (dynamics) {
Platform_dynamicColumnsDone(dynamics);
Hashtable_delete(dynamics);
}
}
const char* DynamicColumn_init(unsigned int key) {
return Platform_dynamicColumnInit(key);
}

View File

@ -21,6 +21,8 @@ typedef struct DynamicColumn_ {
Hashtable* DynamicColumns_new(void);
void DynamicColumns_delete(Hashtable* dynamics);
const char* DynamicColumn_init(unsigned int key);
const DynamicColumn* DynamicColumn_lookup(Hashtable* dynamics, unsigned int key);

View File

@ -38,6 +38,13 @@ Hashtable* DynamicMeters_new(void) {
return Platform_dynamicMeters();
}
void DynamicMeters_delete(Hashtable* dynamics) {
if (dynamics) {
Platform_dynamicMetersDone(dynamics);
Hashtable_delete(dynamics);
}
}
typedef struct {
unsigned int key;
const char* name;

View File

@ -17,6 +17,8 @@ typedef struct DynamicMeter_ {
Hashtable* DynamicMeters_new(void);
void DynamicMeters_delete(Hashtable* dynamics);
const char* DynamicMeter_lookup(Hashtable* dynamics, unsigned int key);
bool DynamicMeter_search(Hashtable* dynamics, const char* name, unsigned int* key);

View File

@ -86,8 +86,9 @@ static void Header_addMeterByName(Header* this, const char* name, MeterModeId mo
if (paren) {
int ok = sscanf(paren, "(%10u)", &param); // CPUMeter
if (!ok) {
char* end, dynamic[32] = {0};
char dynamic[32] = {0};
if (sscanf(paren, "(%30s)", dynamic)) { // DynamicMeter
char* end;
if ((end = strrchr(dynamic, ')')) == NULL)
return; // htoprc parse failure
*end = '\0';
@ -195,25 +196,28 @@ void Header_draw(const Header* this) {
}
const int width = COLS - pad;
int x = pad;
float roundingLoss = 0.0f;
float roundingLoss = 0.0F;
Header_forEachColumn(this, col) {
Vector* meters = this->columns[col];
float colWidth = (float)width * HeaderLayout_layouts[this->headerLayout].widths[col] / 100.0f;
float colWidth = (float)width * HeaderLayout_layouts[this->headerLayout].widths[col] / 100.0F;
roundingLoss += colWidth - floorf(colWidth);
if (roundingLoss >= 1.0f) {
colWidth += 1.0f;
roundingLoss -= 1.0f;
if (roundingLoss >= 1.0F) {
colWidth += 1.0F;
roundingLoss -= 1.0F;
}
for (int y = (pad / 2), i = 0; i < Vector_size(meters); i++) {
Meter* meter = (Meter*) Vector_get(meters, i);
float actualWidth = colWidth;
if (meter->mode == TEXT_METERMODE) {
/* Let meters in text mode expand to the right on empty neighbors;
except for multi column meters. */
if (meter->mode == TEXT_METERMODE && !Meter_isMultiColumn(meter)) {
for (int j = 1; j < meter->columnWidthCount; j++) {
actualWidth += (float)width * HeaderLayout_layouts[this->headerLayout].widths[col + j] / 100.0f;
actualWidth += (float)width * HeaderLayout_layouts[this->headerLayout].widths[col + j] / 100.0F;
}
}

View File

@ -23,7 +23,7 @@ typedef struct Header_ {
int height;
} Header;
#define Header_forEachColumn(this_, i_) for (size_t (i_)=0; (i_) < HeaderLayout_getColumns((this_)->headerLayout); ++(i_))
#define Header_forEachColumn(this_, i_) for (size_t (i_)=0, H_fEC_numColumns_ = HeaderLayout_getColumns((this_)->headerLayout); (i_) < H_fEC_numColumns_; ++(i_))
Header* Header_new(ProcessList* pl, Settings* settings, HeaderLayout hLayout);

View File

@ -82,6 +82,6 @@ HeaderOptionsPanel* HeaderOptionsPanel_new(Settings* settings, ScreenManager* sc
for (int i = 0; i < LAST_HEADER_LAYOUT; i++) {
Panel_add(super, (Object*) CheckItem_newByVal(HeaderLayout_layouts[i].description, false));
}
CheckItem_set((CheckItem*)Panel_get(super, settings->hLayout), true);
CheckItem_set((CheckItem*)Panel_get(super, scr->header->headerLayout), true);
return this;
}

View File

@ -61,8 +61,8 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
if (ch == KEY_RESIZE)
return IGNORED;
/* reset on every normal key */
if (ch != ERR)
/* reset on every normal key, except mouse events while mouse support is disabled */
if (ch != ERR && (ch != KEY_MOUSE || this->state->settings->enableMouse))
this->state->hideProcessSelection = false;
if (EVENT_IS_HEADER_CLICK(ch)) {

View File

@ -33,10 +33,14 @@ static void MemorySwapMeter_updateValues(Meter* this) {
static void MemorySwapMeter_draw(Meter* this, int x, int y, int w) {
MemorySwapMeterData* data = this->meterData;
/* Use the same width for each sub meter to align with CPU meter */
const int colwidth = w / 2;
const int diff = w - colwidth * 2;
assert(data->memoryMeter->draw);
data->memoryMeter->draw(data->memoryMeter, x, y, w / 2);
data->memoryMeter->draw(data->memoryMeter, x, y, colwidth);
assert(data->swapMeter->draw);
data->swapMeter->draw(data->swapMeter, x + w / 2, y, w - w / 2);
data->swapMeter->draw(data->swapMeter, x + colwidth + diff, y, colwidth);
}
static void MemorySwapMeter_init(Meter* this) {
@ -91,6 +95,7 @@ const MeterClass MemorySwapMeter_class = {
},
.updateValues = MemorySwapMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.name = "MemorySwap",
.uiName = "Memory & Swap",
.description = "Combined memory and swap usage",

View File

@ -73,6 +73,7 @@ typedef struct MeterClass_ {
const char* const caption; /* prefix in the actual header */
const char* const description; /* optional meter description in header setup menu */
const uint8_t maxItems;
const bool isMultiColumn; /* whether the meter draws multiple sub-columns (defaults to false) */
} MeterClass;
#define As_Meter(this_) ((const MeterClass*)((this_)->super.klass))
@ -92,6 +93,7 @@ typedef struct MeterClass_ {
#define Meter_attributes(this_) As_Meter(this_)->attributes
#define Meter_name(this_) As_Meter(this_)->name
#define Meter_uiName(this_) As_Meter(this_)->uiName
#define Meter_isMultiColumn(this_) As_Meter(this_)->isMultiColumn
typedef struct GraphData_ {
struct timeval time;

View File

@ -707,6 +707,26 @@ void Process_printLeftAlignedField(RichString* str, int attr, const char* conten
RichString_appendChr(str, attr, ' ', width + 1 - columns);
}
void Process_printPercentage(float val, char* buffer, int n, int* attr) {
if (val >= 0) {
if (val < 99.9F) {
if (val < 0.05F) {
*attr = CRT_colors[PROCESS_SHADOW];
}
xSnprintf(buffer, n, "%4.1f ", val);
} else if (val < 999) {
*attr = CRT_colors[PROCESS_MEGABYTES];
xSnprintf(buffer, n, "%3d. ", (int)val);
} else {
*attr = CRT_colors[PROCESS_MEGABYTES];
xSnprintf(buffer, n, "%4d ", (int)val);
}
} else {
*attr = CRT_colors[PROCESS_SHADOW];
xSnprintf(buffer, n, " N/A ");
}
}
void Process_writeField(const Process* this, RichString* str, ProcessField field) {
char buffer[256];
size_t n = sizeof(buffer);
@ -821,34 +841,13 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
xSnprintf(buffer, n, "%4ld ", this->nlwp);
break;
case PERCENT_CPU:
case PERCENT_CPU: Process_printPercentage(this->percent_cpu, buffer, n, &attr); break;
case PERCENT_NORM_CPU: {
float cpuPercentage = this->percent_cpu;
if (field == PERCENT_NORM_CPU) {
cpuPercentage /= this->processList->activeCPUs;
}
if (cpuPercentage > 999.9F) {
xSnprintf(buffer, n, "%4u ", (unsigned int)cpuPercentage);
} else if (cpuPercentage > 99.9F) {
xSnprintf(buffer, n, "%3u. ", (unsigned int)cpuPercentage);
} else {
if (cpuPercentage < 0.05F)
attr = CRT_colors[PROCESS_SHADOW];
xSnprintf(buffer, n, "%4.1f ", cpuPercentage);
}
float cpuPercentage = this->percent_cpu / this->processList->activeCPUs;
Process_printPercentage(cpuPercentage, buffer, n, &attr);
break;
}
case PERCENT_MEM:
if (this->percent_mem > 99.9F) {
xSnprintf(buffer, n, "100. ");
} else {
if (this->percent_mem < 0.05F)
attr = CRT_colors[PROCESS_SHADOW];
xSnprintf(buffer, n, "%4.1f ", this->percent_mem);
}
break;
case PERCENT_MEM: Process_printPercentage(this->percent_mem, buffer, n, &attr); break;
case PGRP: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->pgrp); break;
case PID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->pid); break;
case PPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->ppid); break;
@ -864,8 +863,12 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
case STATE:
xSnprintf(buffer, n, "%c ", this->state);
switch (this->state) {
#ifdef HTOP_NETBSD
case 'P':
#else
case 'R':
attr = CRT_colors[PROCESS_R_STATE];
#endif
attr = CRT_colors[PROCESS_RUN_STATE];
break;
case 'D':
attr = CRT_colors[PROCESS_D_STATE];

View File

@ -79,8 +79,6 @@ typedef struct ProcessMergedCommand_ {
char* str; /* merged Command string */
size_t highlightCount; /* how many portions of cmdline to highlight */
ProcessCmdlineHighlight highlights[8]; /* which portions of cmdline to highlight */
bool separateComm : 1; /* whether comm is a separate field */
bool unmatchedExe : 1; /* whether exe matched with cmdline */
bool cmdlineChanged : 1; /* whether cmdline changed */
bool exeChanged : 1; /* whether exe changed */
bool commChanged : 1; /* whether comm changed */
@ -358,6 +356,8 @@ void Process_fillStarttimeBuffer(Process* this);
void Process_printLeftAlignedField(RichString* str, int attr, const char* content, unsigned int width);
void Process_printPercentage(float val, char* buffer, int n, int* attr);
void Process_display(const Object* cast, RichString* out);
void Process_done(Process* this);

100
README
View File

@ -1,10 +1,12 @@
# [![htop](htop.png)](https://htop.dev)
# [![htop logo](htop.png)](https://htop.dev)
[![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/21665/badge.svg)](https://scan.coverity.com/projects/21665)
[![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://web.libera.chat/#htop)
[![Github Release](https://img.shields.io/github/release/htop-dev/htop.svg)](https://github.com/htop-dev/htop/releases/latest)
[![GitHub Release](https://img.shields.io/github/release/htop-dev/htop.svg)](https://github.com/htop-dev/htop/releases/latest)
[![Packaging status](https://repology.org/badge/tiny-repos/htop.svg)](https://repology.org/project/htop/versions)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](COPYING?raw=true)
![Screenshot of htop](docs/images/screenshot.png?raw=true)
@ -13,23 +15,27 @@
`htop` is a cross-platform interactive process viewer.
`htop` allows scrolling the list of processes vertically and horizontally to see their full command lines and related information like memory and CPU consumption.
Also system wide information, like load average or swap usage, is shown.
The information displayed is configurable through a graphical setup and can be sorted and filtered interactively.
Tasks related to processes (e.g. killing and renicing) can be done without entering their PIDs.
Running `htop` requires `ncurses` libraries (typically named libncursesw*).
Running `htop` requires `ncurses` libraries, typically named libncurses(w).
For more information and details on how to contribute to `htop` visit [htop.dev](https://htop.dev).
`htop` is written in C.
For more information and details visit [htop.dev](https://htop.dev).
## Build instructions
### Prerequisite
List of build-time dependencies:
* `build-essential` standard GNU autotools-based
* `autoconf`
* `autotools`
* `ncurses`
* standard GNU autotools-based C toolchain
- C99 compliant compiler
- `autoconf`
- `autotools`
* `ncurses`
**Note about `ncurses`:**
> htop requires ncurses 6.0. Be aware the appropriate package is sometimes still called libncurses5 (on Debian/Ubuntu). Also ncurses usually comes in two flavours:
@ -42,27 +48,26 @@ List of additional build-time dependencies (based on feature flags):
* `sensors`
* `hwloc`
* `libcap`
* `libnl-3`
Compiling `htop` requires the header files for `ncurses` . Install these and other required packages for C development from your package manager.
Install these and other required packages for C development from your package manager.
**Debian/Ubuntu**
~~~ shell
sudo apt install libncursesw5-dev autotools-dev autoconf
sudo apt install libncursesw5-dev autotools-dev autoconf build-essential
~~~
**Fedora/RHEL**
~~~ shell
sudo dnf install ncurses-devel automake autoconf
sudo dnf install ncurses-devel automake autoconf gcc
~~~
### Compiling from source:
To compile from sources downloaded from the Git repository (`git clone` or downloads from [Github releases](https://github.com/htop-dev/htop/releases/)), then run:
### Compile from source:
To compile from source, download from the Git repository (`git clone` or downloads from [GitHub releases](https://github.com/htop-dev/htop/releases/)), then run:
~~~ shell
./autogen.sh && ./configure && make
~~~
By default `make install` will install into `/usr/local`, for changing the path use `./configure --prefix=/some/path`.
### Install
To install on the local system run `make install`. By default `make install` installs into `/usr/local`. To change this path use `./configure --prefix=/some/path`.
@ -74,52 +79,55 @@ To install on the local system run `make install`. By default `make install` ins
* `--enable-unicode`:
enable Unicode support
dependency: *libncursesw*
default: *yes*
* `--enable-pcp`:
enable Performance Co-Pilot support via a new pcp-htop utility
dependency: *libpcp*
default: *no*
- dependency: *libncursesw*
- default: *yes*
* `--enable-affinity`:
enable `sched_setaffinity(2)` and `sched_getaffinity(2)` for affinity support; conflicts with hwloc
default: *check*
- default: *check*
* `--enable-hwloc`:
enable hwloc support for CPU affinity; disables affinity support
dependency: *libhwloc*
default: *no*
- dependency: *libhwloc*
- default: *no*
* `--enable-static`:
build a static htop binary; hwloc and delay accounting are not supported
default: *no*
- default: *no*
* `--enable-debug`:
Enable asserts and internal sanity checks; implies a performance penalty
default: *no*
- default: *no*
#### Performance Co-Pilot
* `--enable-pcp`:
enable Performance Co-Pilot support via a new pcp-htop utility
- dependency: *libpcp*
- default: *no*
#### Linux
* `--enable-sensors`:
enable libsensors(3) support for reading temperature data
dependencies: *libsensors-dev*(build-time), at runtime *libsensors* is loaded via `dlopen(3)` if available
default: *check*
- dependencies: *libsensors-dev*(build-time), at runtime *libsensors* is loaded via `dlopen(3)` if available
- default: *check*
* `--enable-capabilities`:
enable Linux capabilities support
dependency: *libcap*
default: *check*
- dependency: *libcap*
- default: *check*
* `--with-proc`:
location of a Linux-compatible proc filesystem
default: */proc*
- default: */proc*
* `--enable-openvz`:
enable OpenVZ support
default: *no*
- default: *no*
* `--enable-vserver`:
enable VServer support
default: *no*
- default: *no*
* `--enable-ancient-vserver`:
enable ancient VServer support (implies `--enable-vserver`)
default: *no*
- default: *no*
* `--enable-delayacct`:
enable Linux delay accounting support
dependencies: *pkg-config*(build-time), *libnl-3* and *libnl-genl-3*
default: *check*
- dependencies: *pkg-config*(build-time), *libnl-3* and *libnl-genl-3*
- default: *check*
## Runtime dependencies:
@ -128,20 +136,22 @@ To install on the local system run `make install`. By default `make install` ins
### Runtime optional dependencies:
`htop` has a set of fixed optional dependencies, depending on build/configure option used:
* `libdl`, if not building static and support for some of the optional libraries is enabled, is always required when support for to optionally load dependencies (i.e. `libsensors`, `systemd`) is present.
#### Linux
* `libdl`, if not building a static binary, is always required when support for to optionally dependencies (i.e. `libsensors`, `libsystemd`) is present.
* `libcap`, user-space interfaces to the POSIX 1003.1e, is always required when `--enable-capabilities` was used to configure `htop`.
* `libsensors`, readout of temperatures and CPU speeds, is optional even when `--enable-sensors` was used to configure `htop`.
* `systemd` is optional when `--enable-static` was not used to configure `htop` (Linux only). If building statically and `libsystemd` is not found by `configure` support for the SystemD meter is disabled entirely.
* `libsystemd` is optional when `--enable-static` was not used to configure `htop`. If building statically and `libsystemd` is not found by `configure`, support for the systemd meter is disabled entirely.
`htop` checks for the availability of the actual runtime lib as `htop` runs.
**BSD**
On most *BSD systems you also have `kvm` as a static requirement to read all the kernel information.
#### BSD
On most BSD systems `kvm` is a requirement to read kernel information.
More information on required and optional dependencies can be found in [configure.ac](configure.ac).
## Usage
See the manual page (`man htop`) or the on-line help ('F1' or 'h' inside `htop`) for a list of supported key commands.
See the manual page (`man htop`) or the help menu (**F1** or **h** inside `htop`) for a list of supported key commands.
## Support
@ -151,14 +161,14 @@ If you have trouble running `htop` please consult your Operating System / Linux
We have a [development mailing list](https://htop.dev/mailinglist.html). Feel free to subscribe for release announcements or asking questions on the development of htop.
You can also join our IRC channel #htop on Libera.Chat and talk to the developers there.
You can also join our IRC channel [#htop on Libera.Chat](https://web.libera.chat/#htop) and talk to the developers there.
If you have found an issue with the source of htop, please check whether this has already been reported in our [Github issue tracker](https://github.com/htop-dev/htop/issues).
If not, please file a new issue describing the problem you have found, the location in the source code you are referring to and a possible fix.
If you have found an issue within the source of htop, please check whether this has already been reported in our [GitHub issue tracker](https://github.com/htop-dev/htop/issues).
If not, please file a new issue describing the problem you have found, the potential location in the source code you are referring to and a possible fix if available.
## History
`htop` was invented, developed and maintained by Hisham Muhammad from 2004 to 2019. His [legacy repository](https://github.com/hishamhm/htop/) has been archived to preserve the history.
`htop` was invented, developed and maintained by [Hisham Muhammad](https://hisham.hm/) from 2004 to 2019. His [legacy repository](https://github.com/hishamhm/htop/) has been archived to preserve the history.
In 2020 a [team](https://github.com/orgs/htop-dev/people) took over the development amicably and continues to maintain `htop` collaboratively.

View File

@ -134,8 +134,9 @@ static void Settings_readFields(Settings* settings, const char* line) {
}
// Dynamically-defined columns are always stored by-name.
char* end, dynamic[32] = {0};
char dynamic[32] = {0};
if (sscanf(ids[i], "Dynamic(%30s)", dynamic)) {
char* end;
if ((end = strrchr(dynamic, ')')) == NULL)
continue;
*end = '\0';
@ -180,8 +181,10 @@ static bool Settings_read(Settings* this, const char* fileName, unsigned int ini
this->config_version = atoi(option[1]);
if (this->config_version > CONFIG_READER_MIN_VERSION) {
// the version of the config file on disk is newer than what we can read
fprintf(stderr, "WARNING: %s specifies configuration format version v%d, but this %s binary supports up to v%d.", fileName, this->config_version, PACKAGE, CONFIG_READER_MIN_VERSION);
fprintf(stderr, "WARNING: %s specifies configuration format version v%d, but this %s binary supports up to v%d\n.", fileName, this->config_version, PACKAGE, CONFIG_READER_MIN_VERSION);
fprintf(stderr, " The configuration version will be downgraded to v%d when %s exits.\n", CONFIG_READER_MIN_VERSION, PACKAGE);
String_freeArray(option);
fclose(fd);
return false;
}
} else if (String_eq(option[0], "fields")) {
@ -355,9 +358,9 @@ int Settings_write(const Settings* this, bool onCrash) {
}
#define printSettingInteger(setting_, value_) \
fprintf(fd, setting_ "=%d%c", (int) value_, separator);
fprintf(fd, setting_ "=%d%c", (int) (value_), separator)
#define printSettingString(setting_, value_) \
fprintf(fd, setting_ "=%s%c", value_, separator);
fprintf(fd, setting_ "=%s%c", value_, separator)
if (!onCrash) {
fprintf(fd, "# Beware! This file is rewritten by htop when settings are changed in the interface.\n");
@ -539,7 +542,10 @@ Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns)
}
if (!ok) {
this->changed = true;
Settings_read(this, SYSCONFDIR "/htoprc", initialCpuCount);
ok = Settings_read(this, SYSCONFDIR "/htoprc", initialCpuCount);
}
if (!ok) {
Settings_defaultMeters(this, initialCpuCount);
}
return this;
}

View File

@ -78,6 +78,22 @@ void* xReallocArray(void* ptr, size_t nmemb, size_t size) {
return xRealloc(ptr, nmemb * size);
}
void* xReallocArrayZero(void* ptr, size_t prevmemb, size_t newmemb, size_t size) {
assert((ptr == NULL) == (prevmemb == 0));
if (prevmemb == newmemb) {
return ptr;
}
void* ret = xReallocArray(ptr, newmemb, size);
if (newmemb > prevmemb) {
memset((unsigned char*)ret + prevmemb * size, '\0', (newmemb - prevmemb) * size);
}
return ret;
}
inline bool String_contains_i(const char* s1, const char* s2) {
return strcasestr(s1, s2) != NULL;
}

View File

@ -30,6 +30,8 @@ void* xRealloc(void* ptr, size_t size) ATTR_ALLOC_SIZE1(2);
void* xReallocArray(void* ptr, size_t nmemb, size_t size) ATTR_ALLOC_SIZE2(2, 3);
void* xReallocArrayZero(void* ptr, size_t prevmemb, size_t newmemb, size_t size) ATTR_ALLOC_SIZE2(3, 4);
/*
* String_startsWith gives better performance if strlen(match) can be computed
* at compile time (e.g. when they are immutable string literals). :)

View File

@ -6,7 +6,7 @@
# ----------------------------------------------------------------------
AC_PREREQ([2.69])
AC_INIT([htop], [3.1.0-dev], [htop@groups.io], [], [https://htop.dev/])
AC_INIT([htop], [3.1.0-rc2], [htop@groups.io], [], [https://htop.dev/])
AC_CONFIG_SRCDIR([htop.c])
AC_CONFIG_AUX_DIR([build-aux])
@ -367,7 +367,7 @@ if test "$enable_static" = yes; then
fi
if test "$my_htop_platform" = "solaris"; then
# On OmniOS /usr/include/sys/regset.h redefines ERR to 13 - \r, breaking the Enter key.
# Since ncruses macros use the ERR macro, we can not use another name.
# Since ncurses macros use the ERR macro, we can not use another name.
AC_DEFINE([ERR], [(-1)], [Predefine ncurses macro.])
fi
AC_CHECK_FUNCS( [set_escdelay] )
@ -472,7 +472,7 @@ AC_ARG_ENABLE([vserver],
[],
[enable_vserver=no])
if test "x$enable_vserver" = xyes; then
AC_DEFINE([HAVE_VSERVER], [1], [Define if VServer support enabled.])
AC_DEFINE([HAVE_VSERVER], [1], [Define if VServer support enabled.])
fi
@ -482,8 +482,11 @@ AC_ARG_ENABLE([ancient_vserver],
[],
[enable_ancient_vserver=no])
if test "x$enable_ancient_vserver" = xyes; then
AC_DEFINE([HAVE_VSERVER], [1], [Define if VServer support enabled.])
AC_DEFINE([HAVE_ANCIENT_VSERVER], [1], [Define if ancient vserver support enabled.])
if test "x$enable_vserver" != xyes; then
enable_vserver=implied
fi
AC_DEFINE([HAVE_VSERVER], [1], [Define if VServer support enabled.])
AC_DEFINE([HAVE_ANCIENT_VSERVER], [1], [Define if ancient vserver support enabled.])
fi

View File

@ -269,7 +269,7 @@ ERROR_A:
Process_updateCmdline(proc, k->kp_proc.p_comm, 0, strlen(k->kp_proc.p_comm));
}
// Converts nanoseconds to hundreths of a second (centiseconds) as needed by the "time" field of the Process struct.
// Converts nanoseconds to hundredths of a second (centiseconds) as needed by the "time" field of the Process struct.
static long long int nanosecondsToCentiseconds(uint64_t nanoseconds) {
const uint64_t centiseconds_per_second = 100;
const uint64_t nanoseconds_per_second = 1e9;

View File

@ -432,7 +432,8 @@ void Platform_gettime_monotonic(uint64_t* msec) {
#else
Generic_gettime_monotomic(msec);
Generic_gettime_monotonic(msec);
#endif
}

View File

@ -99,6 +99,8 @@ void Platform_gettime_monotonic(uint64_t* msec);
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { }
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }
@ -107,6 +109,8 @@ static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter,
static inline Hashtable* Platform_dynamicColumns(void) { return NULL; }
static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { }
static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; }
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; }

View File

@ -92,6 +92,8 @@ static inline void Platform_gettime_monotonic(uint64_t* msec) {
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { }
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }
@ -100,6 +102,8 @@ static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter,
static inline Hashtable* Platform_dynamicColumns(void) { return NULL; }
static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { }
static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; }
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; }

View File

@ -92,6 +92,8 @@ static inline void Platform_gettime_monotonic(uint64_t* msec) {
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { }
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }
@ -102,6 +104,8 @@ static inline Hashtable* Platform_dynamicColumns(void) { return NULL; }
static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; }
static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { }
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; }
#endif

View File

@ -392,9 +392,6 @@ except the process's executable instructions).
.B M_LRS (LIB)
The library size of the process.
.TP
.B M_DT (DIRTY)
The size of the dirty pages of the process.
.TP
.B M_SWAP (SWAP)
The size of the process's swapped pages.
.TP

View File

@ -30,8 +30,6 @@ typedef int IOPriority;
#define IOPriority_tuple(class_, data_) (((class_) << IOPRIO_CLASS_SHIFT) | (data_))
#define IOPriority_error 0xffffffff
#define IOPriority_None IOPriority_tuple(IOPRIO_CLASS_NONE, 0)
#define IOPriority_Idle IOPriority_tuple(IOPRIO_CLASS_IDLE, 7)

View File

@ -56,7 +56,6 @@ const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
[M_TRS] = { .name = "M_TRS", .title = " CODE ", .description = "Size of the text segment of the process", .flags = 0, .defaultSortDesc = true, },
[M_DRS] = { .name = "M_DRS", .title = " DATA ", .description = "Size of the data segment plus stack usage of the process", .flags = 0, .defaultSortDesc = true, },
[M_LRS] = { .name = "M_LRS", .title = " LIB ", .description = "The library size of the process (calculated from memory maps)", .flags = PROCESS_FLAG_LINUX_LRS_FIX, .defaultSortDesc = true, },
[M_DT] = { .name = "M_DT", .title = " DIRTY ", .description = "Size of the dirty pages of the process (unused since Linux 2.6; always 0)", .flags = 0, .defaultSortDesc = true, },
[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, .defaultSortDesc = true, },
[PERCENT_NORM_CPU] = { .name = "PERCENT_NORM_CPU", .title = "NCPU%", .description = "Normalized percentage of the CPU time the process used in the last sampling (normalized by cpu count)", .flags = 0, .defaultSortDesc = true, },
@ -86,9 +85,9 @@ const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
[OOM] = { .name = "OOM", .title = " OOM ", .description = "OOM (Out-of-Memory) killer score", .flags = PROCESS_FLAG_LINUX_OOM, .defaultSortDesc = true, },
[IO_PRIORITY] = { .name = "IO_PRIORITY", .title = "IO ", .description = "I/O priority", .flags = PROCESS_FLAG_LINUX_IOPRIO, },
#ifdef HAVE_DELAYACCT
[PERCENT_CPU_DELAY] = { .name = "PERCENT_CPU_DELAY", .title = "CPUD% ", .description = "CPU delay %", .flags = PROCESS_FLAG_LINUX_DELAYACCT, .defaultSortDesc = true, },
[PERCENT_CPU_DELAY] = { .name = "PERCENT_CPU_DELAY", .title = "CPUD%", .description = "CPU delay %", .flags = PROCESS_FLAG_LINUX_DELAYACCT, .defaultSortDesc = true, },
[PERCENT_IO_DELAY] = { .name = "PERCENT_IO_DELAY", .title = "IOD% ", .description = "Block I/O delay %", .flags = PROCESS_FLAG_LINUX_DELAYACCT, .defaultSortDesc = true, },
[PERCENT_SWAP_DELAY] = { .name = "PERCENT_SWAP_DELAY", .title = "SWAPD% ", .description = "Swapin delay %", .flags = PROCESS_FLAG_LINUX_DELAYACCT, .defaultSortDesc = true, },
[PERCENT_SWAP_DELAY] = { .name = "PERCENT_SWAP_DELAY", .title = "SWPD%", .description = "Swapin delay %", .flags = PROCESS_FLAG_LINUX_DELAYACCT, .defaultSortDesc = true, },
#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, .defaultSortDesc = true, },
[M_SWAP] = { .name = "M_SWAP", .title = " SWAP ", .description = "Size of the process's swapped pages", .flags = PROCESS_FLAG_LINUX_SMAPS, .defaultSortDesc = true, },
@ -190,16 +189,6 @@ bool LinuxProcess_changeAutogroupPriorityBy(Process* this, Arg delta) {
return success;
}
#ifdef HAVE_DELAYACCT
static void LinuxProcess_printDelay(float delay_percent, char* buffer, int n) {
if (isnan(delay_percent)) {
xSnprintf(buffer, n, " N/A ");
} else {
xSnprintf(buffer, n, "%4.1f ", delay_percent);
}
}
#endif
static void LinuxProcess_writeField(const Process* this, RichString* str, ProcessField field) {
const LinuxProcess* lp = (const LinuxProcess*) this;
bool coloring = this->settings->highlightMegabytes;
@ -210,7 +199,6 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces
case CMINFLT: Process_printCount(str, lp->cminflt, coloring); return;
case CMAJFLT: Process_printCount(str, lp->cmajflt, coloring); return;
case M_DRS: Process_printBytes(str, lp->m_drs * pageSize, coloring); return;
case M_DT: Process_printBytes(str, lp->m_dt * pageSize, coloring); return;
case M_LRS:
if (lp->m_lrs) {
Process_printBytes(str, lp->m_lrs * pageSize, coloring);
@ -279,9 +267,9 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces
break;
}
#ifdef HAVE_DELAYACCT
case PERCENT_CPU_DELAY: LinuxProcess_printDelay(lp->cpu_delay_percent, buffer, n); break;
case PERCENT_IO_DELAY: LinuxProcess_printDelay(lp->blkio_delay_percent, buffer, n); break;
case PERCENT_SWAP_DELAY: LinuxProcess_printDelay(lp->swapin_delay_percent, buffer, n); break;
case PERCENT_CPU_DELAY: Process_printPercentage(lp->cpu_delay_percent, buffer, n, &attr); break;
case PERCENT_IO_DELAY: Process_printPercentage(lp->blkio_delay_percent, buffer, n, &attr); break;
case PERCENT_SWAP_DELAY: Process_printPercentage(lp->swapin_delay_percent, buffer, n, &attr); break;
#endif
case CTXT:
if (lp->ctxt_diff > 1000) {
@ -330,8 +318,6 @@ static int LinuxProcess_compareByKey(const Process* v1, const Process* v2, Proce
switch (key) {
case M_DRS:
return SPACESHIP_NUMBER(p1->m_drs, p2->m_drs);
case M_DT:
return SPACESHIP_NUMBER(p1->m_dt, p2->m_dt);
case M_LRS:
return SPACESHIP_NUMBER(p1->m_lrs, p2->m_lrs);
case M_TRS:

View File

@ -47,7 +47,6 @@ typedef struct LinuxProcess_ {
long m_trs;
long m_drs;
long m_lrs;
long m_dt;
/* Data read (in bytes) */
unsigned long long io_rchar;

View File

@ -167,11 +167,11 @@ static void LinuxProcessList_updateCPUcount(ProcessList* super) {
DIR* dir = opendir("/sys/devices/system/cpu");
if (!dir) {
super->activeCPUs = 1;
super->existingCPUs = 1;
this->cpuData = xReallocArray(this->cpuData, 2, sizeof(CPUData));
this->cpuData = xReallocArrayZero(this->cpuData, super->existingCPUs ? (super->existingCPUs + 1) : 0, 2, sizeof(CPUData));
this->cpuData[0].online = true; /* average is always "online" */
this->cpuData[1].online = true;
super->activeCPUs = 1;
super->existingCPUs = 1;
return;
}
@ -204,10 +204,7 @@ static void LinuxProcessList_updateCPUcount(ProcessList* super) {
/* readdir() iterates with no specific order */
unsigned int max = MAXIMUM(existing, id + 1);
if (max > currExisting) {
this->cpuData = xReallocArray(this->cpuData, max + /* aggregate */ 1, sizeof(CPUData));
for (unsigned int j = currExisting; j < max; j++) {
this->cpuData[j].online = false;
}
this->cpuData = xReallocArrayZero(this->cpuData, currExisting ? (currExisting + 1) : 0, max + /* aggregate */ 1, sizeof(CPUData));
this->cpuData[0].online = true; /* average is always "online" */
currExisting = max;
}
@ -678,7 +675,7 @@ static bool LinuxProcessList_readStatmFile(LinuxProcess* process, openat_arg_t p
if (!statmfile)
return false;
long int dummy;
long int dummy, dummy2;
int r = fscanf(statmfile, "%ld %ld %ld %ld %ld %ld %ld",
&process->super.m_virt,
@ -687,7 +684,7 @@ static bool LinuxProcessList_readStatmFile(LinuxProcess* process, openat_arg_t p
&process->m_trs,
&dummy, /* unused since Linux 2.6; always 0 */
&process->m_drs,
&process->m_dt);
&dummy2); /* unused since Linux 2.6; always 0 */
fclose(statmfile);
if (r == 7) {
@ -1426,14 +1423,14 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
{
bool prev = proc->usesDeletedLib;
if ((lp->m_lrs == 0 && (settings->flags & PROCESS_FLAG_LINUX_LRS_FIX)) ||
if ((settings->flags & PROCESS_FLAG_LINUX_LRS_FIX) ||
(settings->highlightDeletedExe && !proc->procExeDeleted && !proc->isKernelThread && !proc->isUserlandThread)) {
// Check if we really should recalculate the M_LRS value for this process
uint64_t passedTimeInMs = pl->realtimeMs - lp->last_mlrs_calctime;
uint64_t recheck = ((uint64_t)rand()) % 2048;
if (passedTimeInMs > 2000 || passedTimeInMs > recheck) {
if (passedTimeInMs > recheck) {
lp->last_mlrs_calctime = pl->realtimeMs;
LinuxProcessList_readMaps(lp, procFd, settings->flags & PROCESS_FLAG_LINUX_LRS_FIX, settings->highlightDeletedExe);
}

View File

@ -543,6 +543,8 @@ bool Platform_getDiskIO(DiskIOData* data) {
if (!fd)
return false;
char lastTopDisk[32] = { '\0' };
unsigned long long int read_sum = 0, write_sum = 0, timeSpend_sum = 0;
char lineBuffer[256];
while (fgets(lineBuffer, sizeof(lineBuffer), fd)) {
@ -556,22 +558,11 @@ bool Platform_getDiskIO(DiskIOData* data) {
continue;
/* only count root disks, e.g. do not count IO from sda and sda1 twice */
if ((diskname[0] == 's' || diskname[0] == 'h')
&& diskname[1] == 'd'
&& isalpha((unsigned char)diskname[2])
&& isdigit((unsigned char)diskname[3]))
if (lastTopDisk[0] && String_startsWith(diskname, lastTopDisk))
continue;
/* only count root disks, e.g. do not count IO from mmcblk0 and mmcblk0p1 twice */
if (diskname[0] == 'm'
&& diskname[1] == 'm'
&& diskname[2] == 'c'
&& diskname[3] == 'b'
&& diskname[4] == 'l'
&& diskname[5] == 'k'
&& isdigit((unsigned char)diskname[6])
&& diskname[7] == 'p')
continue;
/* This assumes disks are listed directly before any of their partitions */
String_safeStrncpy(lastTopDisk, diskname, sizeof(lastTopDisk));
read_sum += read_tmp;
write_sum += write_tmp;

View File

@ -112,6 +112,8 @@ static inline void Platform_gettime_monotonic(uint64_t* msec) {
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { }
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }
@ -120,6 +122,8 @@ static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter,
static inline Hashtable* Platform_dynamicColumns(void) { return NULL; }
static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { }
static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; }
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; }

View File

@ -19,7 +19,6 @@ in the source distribution for its full text.
M_TRS = 42, \
M_DRS = 43, \
M_LRS = 44, \
M_DT = 45, \
CTID = 100, \
VPID = 101, \
VXID = 102, \

View File

@ -39,14 +39,17 @@ static long fscale;
static int pageSize;
static int pageSizeKB;
static char const *freqSysctls[] = {
"machdep.est.frequency.current",
"machdep.powernow.frequency.current",
"machdep.intrepid.frequency.current",
"machdep.loongson.frequency.current",
"machdep.cpu.frequency.current",
"machdep.frequency.current",
NULL
static const struct {
const char* name;
long int scale;
} freqSysctls[] = {
{ "machdep.est.frequency.current", 1 },
{ "machdep.powernow.frequency.current", 1 },
{ "machdep.intrepid.frequency.current", 1 },
{ "machdep.loongson.frequency.current", 1 },
{ "machdep.cpu.frequency.current", 1 },
{ "machdep.frequency.current", 1 },
{ "machdep.tsc_freq", 1000000 },
};
static void NetBSDProcessList_updateCPUcount(ProcessList* super) {
@ -261,7 +264,6 @@ static void NetBSDProcessList_scanProcs(NetBSDProcessList* this) {
bool hideKernelThreads = settings->hideKernelThreads;
bool hideUserlandThreads = settings->hideUserlandThreads;
int count = 0;
int nlwps = 0;
const struct kinfo_proc2* kprocs = kvm_getproc2(this->kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), &count);
@ -279,7 +281,6 @@ static void NetBSDProcessList_scanProcs(NetBSDProcessList* this) {
proc->tpgid = kproc->p_tpgid;
proc->tgid = kproc->p_pid;
proc->session = kproc->p_sid;
proc->tty_nr = kproc->p_tdev;
proc->pgrp = kproc->p__pgid;
proc->isKernelThread = !!(kproc->p_flag & P_SYSTEM);
proc->isUserlandThread = proc->pid != proc->tgid;
@ -287,6 +288,15 @@ static void NetBSDProcessList_scanProcs(NetBSDProcessList* this) {
Process_fillStarttimeBuffer(proc);
ProcessList_add(&this->super, proc);
proc->tty_nr = kproc->p_tdev;
const char* name = ((dev_t)kproc->p_tdev != KERN_PROC_TTY_NODEV) ? devname(kproc->p_tdev, S_IFCHR) : NULL;
if (!name) {
free(proc->tty_name);
proc->tty_name = NULL;
} else {
free_and_xStrdup(&proc->tty_name, name);
}
NetBSDProcessList_updateExe(kproc, proc);
NetBSDProcessList_updateProcessName(this->kd, kproc, proc);
} else {
@ -312,8 +322,12 @@ static void NetBSDProcessList_scanProcs(NetBSDProcessList* this) {
proc->nice = kproc->p_nice - 20;
proc->time = 100 * (kproc->p_rtime_sec + ((kproc->p_rtime_usec + 500000) / 1000000));
proc->priority = kproc->p_priority - PZERO;
proc->processor = kproc->p_cpuid;
proc->minflt = kproc->p_uru_minflt;
proc->majflt = kproc->p_uru_majflt;
struct kinfo_lwp* klwps = kvm_getlwps(this->kd, kproc->p_pid, kproc->p_paddr, sizeof(struct kinfo_lwp), &nlwps);
int nlwps = 0;
const struct kinfo_lwp* klwps = kvm_getlwps(this->kd, kproc->p_pid, kproc->p_paddr, sizeof(struct kinfo_lwp), &nlwps);
switch (kproc->p_realstat) {
case SIDL: proc->state = 'I'; break;
@ -417,7 +431,7 @@ static void NetBSDProcessList_scanCPUFrequency(NetBSDProcessList* this) {
unsigned int cpus = this->super.existingCPUs;
bool match = false;
char name[64];
int freq = 0;
long int freq = 0;
size_t freqSize;
for (unsigned int i = 0; i < cpus; i++) {
@ -429,7 +443,7 @@ static void NetBSDProcessList_scanCPUFrequency(NetBSDProcessList* this) {
xSnprintf(name, sizeof(name), "machdep.cpufreq.cpu%u.current", i);
freqSize = sizeof(freq);
if (sysctlbyname(name, &freq, &freqSize, NULL, 0) != -1) {
this->cpuData[i + 1].frequency = freq;
this->cpuData[i + 1].frequency = freq; /* already in MHz */
match = true;
}
}
@ -442,9 +456,10 @@ static void NetBSDProcessList_scanCPUFrequency(NetBSDProcessList* this) {
* Iterate through legacy sysctl nodes for single-core frequency until
* we find a match...
*/
for (const char** s = freqSysctls; *s != NULL; ++s) {
for (size_t i = 0; i < ARRAYSIZE(freqSysctls); i++) {
freqSize = sizeof(freq);
if (sysctlbyname(*s, &freq, &freqSize, NULL, 0) != -1) {
if (sysctlbyname(freqSysctls[i].name, &freq, &freqSize, NULL, 0) != -1) {
freq /= freqSysctls[i].scale; /* scale to MHz */
match = true;
break;
}

View File

@ -260,14 +260,11 @@ double Platform_setCPUValues(Meter* this, int cpu) {
void Platform_setMemoryValues(Meter* this) {
const ProcessList* pl = this->pl;
long int usedMem = pl->usedMem;
long int buffersMem = pl->buffersMem;
long int cachedMem = pl->cachedMem;
this->total = pl->totalMem;
this->values[0] = usedMem;
this->values[1] = buffersMem;
this->values[0] = pl->usedMem;
this->values[1] = pl->buffersMem;
// this->values[2] = "shared memory, like tmpfs and shm"
this->values[3] = cachedMem;
this->values[3] = pl->cachedMem;
// this->values[4] = "available memory"
}
@ -284,19 +281,19 @@ char* Platform_getProcessEnv(pid_t pid) {
char** ptr;
int count;
kvm_t* kt;
struct kinfo_proc* kproc;
const struct kinfo_proc2* kproc;
size_t capacity = 4096, size = 0;
if ((kt = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL) {
return NULL;
}
if ((kproc = kvm_getprocs(kt, KERN_PROC_PID, pid, &count)) == NULL) {
if ((kproc = kvm_getproc2(kt, KERN_PROC_PID, pid, sizeof(struct kinfo_proc2), &count)) == NULL) {
(void) kvm_close(kt);
return NULL;
}
if ((ptr = kvm_getenvv(kt, kproc, 0)) == NULL) {
if ((ptr = kvm_getenvv2(kt, kproc, 0)) == NULL) {
(void) kvm_close(kt);
return NULL;
}
@ -393,7 +390,7 @@ bool Platform_getNetworkIO(NetworkIOData* data) {
if (getifaddrs(&ifaddrs) != 0)
return false;
for (struct ifaddrs* ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
for (const struct ifaddrs* ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr)
continue;
if (ifa->ifa_addr->sa_family != AF_LINK)
@ -401,7 +398,7 @@ bool Platform_getNetworkIO(NetworkIOData* data) {
if (ifa->ifa_flags & IFF_LOOPBACK)
continue;
struct if_data* ifd = (struct if_data *)ifa->ifa_data;
const struct if_data* ifd = (const struct if_data *)ifa->ifa_data;
data->bytesReceived += ifd->ifi_ibytes;
data->packetsReceived += ifd->ifi_ipackets;

View File

@ -96,6 +96,8 @@ static inline void Platform_gettime_monotonic(uint64_t* msec) {
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { }
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }
@ -104,6 +106,8 @@ static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter,
static inline Hashtable* Platform_dynamicColumns(void) { return NULL; }
static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { }
static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; }
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; }

View File

@ -90,6 +90,8 @@ static inline void Platform_gettime_monotonic(uint64_t* msec) {
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { }
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }
@ -98,6 +100,8 @@ static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter,
static inline Hashtable* Platform_dynamicColumns(void) { return NULL; }
static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { }
static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; }
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; }

View File

@ -226,6 +226,18 @@ void PCPDynamicColumns_init(PCPDynamicColumns* columns) {
free(path);
}
static void PCPDynamicColumns_free(ATTR_UNUSED ht_key_t key, void* value, ATTR_UNUSED void* data) {
PCPDynamicColumn* column = (PCPDynamicColumn*) value;
free(column->metricName);
free(column->super.heading);
free(column->super.caption);
free(column->super.description);
}
void PCPDynamicColumns_done(Hashtable* table) {
Hashtable_foreach(table, PCPDynamicColumns_free, NULL);
}
void PCPDynamicColumn_writeField(PCPDynamicColumn* this, const Process* proc, RichString* str) {
const PCPProcess* pp = (const PCPProcess*) proc;
unsigned int type = PCPMetric_type(this->id);

View File

@ -26,6 +26,8 @@ typedef struct PCPDynamicColumns_ {
void PCPDynamicColumns_init(PCPDynamicColumns* columns);
void PCPDynamicColumns_done(Hashtable* table);
void PCPDynamicColumn_writeField(PCPDynamicColumn* this, const Process* proc, RichString* str);
int PCPDynamicColumn_compareByKey(const PCPProcess* p1, const PCPProcess* p2, ProcessField key);

View File

@ -283,6 +283,22 @@ void PCPDynamicMeters_init(PCPDynamicMeters* meters) {
free(path);
}
static void PCPDynamicMeter_free(ATTR_UNUSED ht_key_t key, void* value, ATTR_UNUSED void* data) {
PCPDynamicMeter* meter = (PCPDynamicMeter*) value;
for (size_t i = 0; i < meter->totalMetrics; i++) {
free(meter->metrics[i].name);
free(meter->metrics[i].label);
free(meter->metrics[i].suffix);
}
free(meter->metrics);
free(meter->super.caption);
free(meter->super.description);
}
void PCPDynamicMeters_done(Hashtable* table) {
Hashtable_foreach(table, PCPDynamicMeter_free, NULL);
}
void PCPDynamicMeter_enable(PCPDynamicMeter* this) {
for (size_t i = 0; i < this->totalMetrics; i++)
PCPMetric_enable(this->metrics[i].id, true);

View File

@ -33,6 +33,8 @@ typedef struct PCPDynamicMeters_ {
void PCPDynamicMeters_init(PCPDynamicMeters* meters);
void PCPDynamicMeters_done(Hashtable* table);
void PCPDynamicMeter_enable(PCPDynamicMeter* this);
void PCPDynamicMeter_updateValues(PCPDynamicMeter* this, Meter* meter);

View File

@ -317,7 +317,7 @@ static void PCPProcessList_updateCmdline(Process* process, int pid, int offset,
Process_updateComm(process, comm);
if (PCPMetric_instance(PCP_PROC_EXE, pid, offset, &value, PM_TYPE_STRING)) {
Process_updateExe(process, value.cp);
Process_updateExe(process, value.cp[0] ? value.cp : NULL);
free(value.cp);
}
}

View File

@ -363,6 +363,14 @@ void Platform_init(void) {
Platform_getMaxPid();
}
void Platform_dynamicColumnsDone(Hashtable* columns) {
PCPDynamicColumns_done(columns);
}
void Platform_dynamicMetersDone(Hashtable* meters) {
PCPDynamicMeters_done(meters);
}
void Platform_done(void) {
pmDestroyContext(pcp->context);
if (pcp->result)

View File

@ -138,6 +138,8 @@ void Platform_gettime_monotonic(uint64_t* msec);
Hashtable* Platform_dynamicMeters(void);
void Platform_dynamicMetersDone(Hashtable* meters);
void Platform_dynamicMeterInit(Meter* meter);
void Platform_dynamicMeterUpdateValues(Meter* meter);
@ -146,6 +148,8 @@ void Platform_dynamicMeterDisplay(const Meter* meter, RichString* out);
Hashtable* Platform_dynamicColumns(void);
void Platform_dynamicColumnsDone(Hashtable* columns);
const char* Platform_dynamicColumnInit(unsigned int key);
bool Platform_dynamicColumnWriteField(const Process* proc, RichString* str, unsigned int key);

View File

@ -1,63 +1,47 @@
{
<ncurses internal memory allocated at startup>
Memcheck:Leak
match-leak-kinds: reachable
...
fun:CRT_init
fun:main
}
{
<ncurses internal memory allocated at startup>
Memcheck:Leak
match-leak-kinds: reachable
...
fun:CRT_init
}
{
<ncurses internal memory>
Memcheck:Leak
match-leak-kinds: reachable
...
fun:wgetch
fun:ScreenManager_run
fun:Action_runSetup
fun:actionSetup
fun:MainPanel_eventHandler
fun:ScreenManager_run
fun:main
}
{
<ncurses internal memory>
Memcheck:Leak
match-leak-kinds: reachable
...
fun:wgetch
fun:ScreenManager_run
fun:main
}
{
<ncurses internal memory>
Memcheck:Leak
match-leak-kinds: reachable
...
fun:wrefresh
fun:main
}
{
<ncurses internal memory>
Memcheck:Leak
match-leak-kinds: reachable
fun:realloc
fun:_nc_doalloc
fun:_nc_tparm_analyze
fun:tparm
match-leak-kinds: possible,reachable
...
fun:doupdate_sp
fun:wrefresh
obj:*
}
{
<ncurses internal memory>
Memcheck:Leak
match-leak-kinds: possible,reachable
...
fun:newterm_sp
fun:newterm
fun:initscr
fun:CRT_init
}
{
<ncurses internal memory>
Memcheck:Leak
match-leak-kinds: reachable
...
obj:*/libtinfo*
fun:CRT_init
}
{
<ncurses internal memory>
Memcheck:Leak
match-leak-kinds: reachable
...
obj:*/libncurses*
fun:CRT_init
}
{
<ncurses internal memory>
Memcheck:Leak
match-leak-kinds: possible,reachable
...
obj:*/libncurses*
fun:CRT_setColors
fun:CRT_init
}

View File

@ -3,4 +3,4 @@
SCRIPT=$(readlink -f "$0")
SCRIPTDIR=$(dirname "$SCRIPT")
valgrind --leak-check=full --show-reachable=yes --show-leak-kinds=all --track-fds=yes --errors-for-leak-kinds=all --suppressions="${SCRIPTDIR}/htop_suppressions.valgrind" "${SCRIPTDIR}/../htop"
valgrind --leak-check=full --show-reachable=yes --show-leak-kinds=all --track-fds=yes --errors-for-leak-kinds=all --track-origins=yes --suppressions="${SCRIPTDIR}/htop_suppressions.valgrind" "${SCRIPTDIR}/../htop"

View File

@ -131,6 +131,8 @@ IGNORE_WCASTQUAL_END
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { }
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }
@ -139,6 +141,8 @@ static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter,
static inline Hashtable* Platform_dynamicColumns(void) { return NULL; }
static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { }
static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; }
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; }

View File

@ -79,6 +79,8 @@ static inline void Platform_gettime_monotonic(uint64_t* msec) {
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { }
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }
@ -87,6 +89,8 @@ static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter,
static inline Hashtable* Platform_dynamicColumns(void) { return NULL; }
static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { }
static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; }
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; }