33 Commits

Author SHA1 Message Date
805546e291 Bump version to 3.0.0beta2 2018-02-17 15:32:24 -02:00
4aba5d878d Fix inttypes.h header 2018-02-17 15:30:15 -02:00
e48b63b585 Darwin: expose LAST_PROCESSFIELD like the other platforms 2018-02-17 15:30:15 -02:00
1748abfb4e Add more default screens 2018-02-17 15:30:15 -02:00
d0fc93d82c Only compute counters is process is shown 2018-02-17 15:30:15 -02:00
0cbdf8ba27 Implemented various performance counters 2018-02-17 15:30:15 -02:00
cf0c074cc8 Add IPC performance counter for Linux 2018-02-17 15:30:15 -02:00
9c40c9a0e7 Add perf counter object 2018-02-17 15:30:15 -02:00
c55c8c2316 configure.ac: add --enable-perfcounters 2018-02-17 15:30:15 -02:00
eb8ca9be84 Set default sort keys in default screens 2018-02-17 15:30:15 -02:00
401d19be37 Add make symbols target 2018-02-17 15:30:15 -02:00
bcf4a30ee6 Store .sort_key as a string 2018-02-17 15:30:15 -02:00
86fea8facd Match iotop's screen configuration 2018-02-17 15:30:15 -02:00
d145a3bfdd Use screen's flags when reading process data 2018-02-17 15:30:15 -02:00
b63d0d04db Screens: Fix "New Screen" option 2018-02-17 15:30:15 -02:00
117cc515fc htoprc: store screen 0's setup for improved compatibility 2018-02-17 15:30:15 -02:00
187a035a76 Add support for multiple screens, switchable using Tab 2018-02-17 15:30:15 -02:00
ece89b8df0 Begin add supporting for multiple screens 2018-02-17 15:30:15 -02:00
52b5beb4e4 Move responsibility for cursor placement to Panels 2018-02-17 15:30:15 -02:00
df9922a67e Fix preservation of LDFLAGS value during configure script
Fixes #738.
2018-02-17 14:50:55 -02:00
fcdff59f4c Update ChangeLog 2018-02-17 14:50:42 -02:00
b544c22c72 Fix issue with small terminals.
Fixes #733.
2018-02-13 06:41:44 -02:00
f37a050d3d Optimize Vector_size on non-debug builds 2018-02-05 11:01:35 +01:00
03f17688ad Handle unexpected values for character passed to isalnum
It seems that certain negative integer values can crash isalnum().
Let's protect against those.

Fixes #711.
2018-02-05 10:59:20 +01:00
a32d7528f6 Check for pkgconfig's presence before using it.
Fixes #710.
2018-02-05 10:22:16 +01:00
ac2dff2881 Fix color behavior on some terminals.
Fixes #635.
2018-02-05 07:20:27 +01:00
c50440f165 Bump version to 2.1.0 2018-02-04 20:13:55 +01:00
b0588d90ff parseBatInfo: check line for NULL before passing it to String_getToken() 2018-02-04 17:04:47 +01:00
b84ebfd4e8 Clarify we are looking for the null termination
Not for a comparison to zero
2018-02-04 17:02:30 +01:00
b86e14d3cf Typo in man page
*hightlight*
2018-02-04 17:01:39 +01:00
b34d76cd41 Fix: infinite loop in tree view on macOS
Fixes #688, the bug regressed on 584a9bc.

On Mac OS X 10.11.6, all processes have their parents since there's a
special process named "kernel_task", whose PID and PPID are 0. As a
result, `this->processes` is never changed causing infinite `while`.
2018-02-04 16:51:06 +01:00
87be623eac Add support for Linux TASK_IDLE
Linux commit 06eb61844d841d0032a9950ce7f8e783ee49c0d0 ("sched/debug:
Add explicit TASK_IDLE printing") exposes kthreads idling using
TASK_IDLE in procfs as "I (idle)".

Until now, when sorting the STATE ("S") column, htop used the raw
value of the state character for comparison, however that led to the
undesirable effect of TASK_IDLE ('I') tasks being sorted above tasks
that were running ('R').

Thus, explicitly recognize the idle process state, and sort it below
others.
2018-02-04 16:44:21 +01:00
b27712181a Darwin: disable thread reading due to bug in macOS High Sierra 2018-02-04 08:59:29 +01:00
20 changed files with 301 additions and 27 deletions

32
CRT.c
View File

@ -37,6 +37,7 @@ in the source distribution for its full text.
#define White COLOR_WHITE
#define ColorPairGrayBlack ColorPair(Magenta,Magenta)
#define ColorIndexGrayBlack ColorIndex(Magenta,Magenta)
#define KEY_WHEELUP KEY_F(20)
#define KEY_WHEELDOWN KEY_F(21)
@ -718,22 +719,23 @@ void CRT_enableDelay() {
void CRT_setColors(int colorScheme) {
CRT_colorScheme = colorScheme;
if (colorScheme == COLORSCHEME_BLACKNIGHT) {
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++) {
if (ColorIndex(i,j) != ColorIndex(Magenta,Magenta)) {
init_pair(ColorIndex(i,j), i, j);
}
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
if (ColorIndex(i,j) != ColorPairGrayBlack) {
int bg = (colorScheme != COLORSCHEME_BLACKNIGHT)
? (j==0 ? -1 : j)
: j;
init_pair(ColorIndex(i,j), i, bg);
}
init_pair(ColorIndex(Magenta,Magenta), 8, 0);
} else {
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++) {
if (ColorIndex(i,j) != ColorIndex(Magenta,Magenta)) {
init_pair(ColorIndex(i,j), i, (j==0?-1:j));
}
}
init_pair(ColorIndex(Magenta,Magenta), 8, -1);
}
}
int grayBlackFg = COLORS > 8 ? 8 : 0;
int grayBlackBg = (colorScheme != COLORSCHEME_BLACKNIGHT)
? -1
: 0;
init_pair(ColorIndexGrayBlack, grayBlackFg, grayBlackBg);
CRT_colors = CRT_colorSchemes[colorScheme];
}

1
CRT.h
View File

@ -26,6 +26,7 @@ in the source distribution for its full text.
#define White COLOR_WHITE
#define ColorPairGrayBlack ColorPair(Magenta,Magenta)
#define ColorIndexGrayBlack ColorIndex(Magenta,Magenta)
#define KEY_WHEELUP KEY_F(20)
#define KEY_WHEELDOWN KEY_F(21)

View File

@ -1,3 +1,45 @@
What's new in version 2.1.1
* Check for pkg-config when building with --enable-delayacct
(thanks to @florian2833z for the report)
* BUGFIX: preserve LDFLAGS when building
(thanks to Lance Frederickson for the report)
* BUGFIX: fix issue with small terminals
(thanks to Daniel Elf for the report)
* BUGFIX: fix crash with particular keycodes
(thanks to Wellington Torrejais da Silva for the report)
* BUGFIX: fix terminal color issues
(thanks to Kang-Che Sung for the report)
What's new in version 2.1.0
* Linux: Delay accounting metrics
(thanks to André Carvalho)
* DragonFlyBSD support
(thanks to Diederik de Groot)
* Support for real-time signals
(thanks to Kang-Che Sung)
* 'c' key now works with threads as well
* Session column renamed from SESN to SID
(thanks to Kamyar Rasta)
* Improved UI for meter style selection
(thanks to Kang-Che Sung)
* Improved code for constructing process tree
(thanks to wangqr)
* Compile-time option to disable setuid
* Error checking of various standard library operations
* Replacement of sprintf with snprintf
(thanks to Tomasz Kramkowski)
* Linux: performance improvements in battery meter
* Linux: update process TTY device
* Linux: add support for sorting TASK_IDLE
(thanks to Vladimir Panteleev)
* Linux: add upper-bound to running process counter
(thanks to Lucas Correia Villa Real)
* BUGFIX: avoid crash when battery is removed
(thanks to Jan Chren)
* BUGFIX: macOS: fix infinite loop in tree view
(thanks to Wataru Ashihara)
What's new in version 2.0.2

View File

@ -78,6 +78,7 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
this->settings->changed = true;
const Header* header = this->scr->header;
CRT_setColors(mark);
clear();
Panel* menu = (Panel*) Vector_get(this->scr->panels, 0);
Header_draw(header);
RichString_setAttr(&(super->header), CRT_colors[PANEL_HEADER_FOCUS]);

View File

@ -152,7 +152,7 @@ int Meter_humanUnit(char* buffer, unsigned long int value, int size) {
if (value / 1024 < powi)
break;
if (prefix[1] == 0)
if (prefix[1] == '\0')
break;
powi *= 1024;
@ -287,7 +287,7 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
int blockSizes[10];
xSnprintf(bar, w + 1, "%*s", w, buffer);
xSnprintf(bar, w + 1, "%*.*s", w, w, buffer);
// First draw in the bar[] buffer...
int offset = 0;

View File

@ -477,7 +477,7 @@ HandlerResult Panel_selectByTyping(Panel* this, int ch) {
this->eventHandlerState = xCalloc(100, sizeof(char));
char* buffer = this->eventHandlerState;
if (ch < 255 && isalnum(ch)) {
if (ch > 0 && ch < 255 && isalnum(ch)) {
int len = strlen(buffer);
if (len < 99) {
buffer[len] = ch;

View File

@ -28,7 +28,6 @@ in the source distribution for its full text.
#include <time.h>
#include <assert.h>
#include <math.h>
#include <inttypes.h>
#ifdef __ANDROID__
#define SYS_ioprio_get __NR_ioprio_get
@ -46,6 +45,7 @@ in the source distribution for its full text.
#include "Object.h"
#include <sys/types.h>
#include <inttypes.h>
#define PROCESS_FLAG_IO 0x0001
@ -175,6 +175,8 @@ typedef struct ProcessClass_ {
#define Process_isChildOf(process_, pid_) (process_->tgid == pid_ || (process_->tgid == process_->pid && process_->ppid == pid_))
#define Process_sortState(state) ((state) == 'I' ? 0x100 : (state))
}*/
static int Process_getuid = -1;
@ -600,7 +602,7 @@ long Process_compare(const void* v1, const void* v2) {
return (p1->starttime_ctime - p2->starttime_ctime);
}
case STATE:
return (p1->state - p2->state);
return (Process_sortState(p1->state) - Process_sortState(p2->state));
case ST_UID:
return (p1->st_uid - p2->st_uid);
case TIME:

View File

@ -24,6 +24,7 @@ in the source distribution for its full text.
#include "Object.h"
#include <sys/types.h>
#include <inttypes.h>
#define PROCESS_FLAG_IO 0x0001
@ -153,6 +154,8 @@ typedef struct ProcessClass_ {
#define Process_isChildOf(process_, pid_) (process_->tgid == pid_ || (process_->tgid == process_->pid && process_->ppid == pid_))
#define Process_sortState(state) ((state) == 'I' ? 0x100 : (state))
#define ONE_K 1024L
#define ONE_M (ONE_K * ONE_K)

View File

@ -232,6 +232,11 @@ void ProcessList_sort(ProcessList* this) {
pid_t ppid = process->tgid == process->pid ? process->ppid : process->tgid;
// Bisect the process vector to find parent
int l = 0, r = size;
// If PID corresponds with PPID (e.g. "kernel_task" (PID:0, PPID:0)
// on Mac OS X 10.11.6) cancel bisecting and regard this process as
// root.
if (process->pid == ppid)
r = 0;
while (l < r) {
int c = (l + r) / 2;
pid_t pid = ((Process*)(Vector_get(this->processes, c)))->pid;

View File

@ -284,11 +284,19 @@ inline Object* Vector_get(Vector* this, int idx) {
#endif
#ifdef DEBUG
inline int Vector_size(Vector* this) {
assert(Vector_isConsistent(this));
return this->items;
}
#else
#define Vector_size(v_) ((v_)->items)
#endif
/*
static void Vector_merge(Vector* this, Vector* v2) {

View File

@ -70,8 +70,16 @@ extern Object* Vector_get(Vector* this, int idx);
#endif
#ifdef DEBUG
extern int Vector_size(Vector* this);
#else
#define Vector_size(v_) ((v_)->items)
#endif
/*
*/

View File

@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.65)
AC_INIT([htop],[2.0.2],[hisham@gobolinux.org])
AC_INIT([htop],[3.0.0beta2],[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")
@ -167,7 +167,7 @@ m4_define([HTOP_CHECK_SCRIPT],
LIBS="$htop_config_script $LIBS "
htop_script_success=yes
], [])
LDFLAGS="$save_LDFLAGS"
LDFLAGS="$htop_save_LDFLAGS"
fi
if test "x$htop_script_success" = xno; then
[$5]
@ -305,6 +305,7 @@ fi
AC_ARG_ENABLE(delayacct, [AS_HELP_STRING([--enable-delayacct], [enable linux delay accounting])],, enable_delayacct="no")
if test "x$enable_delayacct" = xyes
then
PKG_PROG_PKG_CONFIG()
PKG_CHECK_MODULES(LIBNL3, libnl-3.0, [], [missing_libraries="$missing_libraries libnl-3"])
PKG_CHECK_MODULES(LIBNL3GENL, libnl-genl-3.0, [], [missing_libraries="$missing_libraries libnl-genl-3"])
CFLAGS+=" $LIBNL3_CFLAGS $LIBNL3GENL_CFLAGS"

View File

@ -171,7 +171,8 @@ void ProcessList_goThroughEntries(ProcessList* super) {
DarwinProcess_setFromKInfoProc(&proc->super, &ps[i], tv.tv_sec, preExisting);
DarwinProcess_setFromLibprocPidinfo(proc, dpl);
DarwinProcess_scanThreads(proc);
// Disabled due to bug in macOS High Sierra
// DarwinProcess_scanThreads(proc);
super->totalTasks += 1;

View File

@ -25,6 +25,11 @@ in the source distribution for its full text.
#include "CPUMeter.h"
#include "BatteryMeter.h"
#include "DarwinProcess.h"
typedef enum DarwinProcessFields {
LAST_PROCESSFIELD = 100,
} DarwinProcessField;
}*/
#ifndef CLAMP
@ -97,7 +102,7 @@ ProcessFieldData Process_fields[] = {
[TIME] = { .name = "TIME", .title = " TIME+ ", .description = "Total time the process has spent in user and system time", .flags = 0, },
[NLWP] = { .name = "NLWP", .title = "NLWP ", .description = "Number of threads in the process", .flags = 0, },
[TGID] = { .name = "TGID", .title = " TGID ", .description = "Thread group ID (i.e. process ID)", .flags = 0, },
[100] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
[LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
};
MeterClass* Platform_meterTypes[] = {

View File

@ -16,6 +16,10 @@ in the source distribution for its full text.
#include "BatteryMeter.h"
#include "DarwinProcess.h"
typedef enum DarwinProcessFields {
LAST_PROCESSFIELD = 100,
} DarwinProcessField;
#ifndef CLAMP
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif

View File

@ -49,11 +49,11 @@ The following commands are supported while in htop:
.LP
.TP 5
.B Up, Alt-k
Select (hightlight) the previous process in the process list. Scroll the list
Select (highlight) the previous process in the process list. Scroll the list
if necessary.
.TP
.B Down, Alt-j
Select (hightlight) the next process in the process list. Scroll the list if
Select (highlight) the next process in the process list. Scroll the list if
necessary.
.TP
.B Left, Alt-h

View File

@ -72,6 +72,8 @@ static unsigned long int parseBatInfo(const char *fileName, const unsigned short
fclose(file);
if (!line) break;
char *foundNumStr = String_getToken(line, wordNum);
const unsigned long int foundNum = atoi(foundNumStr);
free(foundNumStr);

View File

@ -198,7 +198,7 @@ ProcessFieldData Process_fields[] = {
[0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
[PID] = { .name = "PID", .title = " PID ", .description = "Process/thread ID", .flags = 0, },
[COMM] = { .name = "Command", .title = "Command ", .description = "Command line", .flags = 0, },
[STATE] = { .name = "STATE", .title = "S ", .description = "Process state (S sleeping, R running, D disk, Z zombie, T traced, W paging)", .flags = 0, },
[STATE] = { .name = "STATE", .title = "S ", .description = "Process state (S sleeping, R running, D disk, Z zombie, T traced, W paging, I idle)", .flags = 0, },
[PPID] = { .name = "PPID", .title = " PPID ", .description = "Parent process ID", .flags = 0, },
[PGRP] = { .name = "PGRP", .title = " PGRP ", .description = "Process group ID", .flags = 0, },
[SESSION] = { .name = "SESSION", .title = " SID ", .description = "Process's session ID", .flags = 0, },

135
linux/PerfCounter.c Normal file
View File

@ -0,0 +1,135 @@
/*
* This file is based on tiptop.
* by Erven ROHOU
* Copyright (c) 2011, 2012, 2014 Inria
* License: GNU General Public License version 2.
*/
#include "PerfCounter.h"
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include "XAlloc.h"
/*{
#include <config.h>
#include <sys/types.h>
#include <unistd.h>
#include <asm/unistd.h>
#include <inttypes.h>
#include <stdbool.h>
// The sys_perf_counter_open syscall and header files changed names
// between Linux 2.6.31 and 2.6.32. Do the mangling here.
#ifdef HAVE_LINUX_PERF_COUNTER_H
#include <linux/perf_counter.h>
#define STRUCT_NAME perf_counter_attr
#define SYSCALL_NUM __NR_perf_counter_open
#elif HAVE_LINUX_PERF_EVENT_H
#include <linux/perf_event.h>
#define STRUCT_NAME perf_event_attr
#define SYSCALL_NUM __NR_perf_event_open
#else
#error Sorry, performance counters not supported on this system.
#endif
typedef struct PerfCounter_ {
struct STRUCT_NAME events;
pid_t pid;
int fd;
uint64_t prevValue;
uint64_t value;
} PerfCounter;
#define PerfCounter_delta(pc_) ((pc_)->value - (pc_)->prevValue)
}*/
int PerfCounter_openFds = 0;
static int PerfCounter_fdLimit = -1;
static void PerfCounter_initFdLimit() {
char name[100] = { 0 }; /* needs to fit the name /proc/xxxx/limits */
snprintf(name, sizeof(name) - 1, "/proc/%d/limits", getpid());
FILE* f = fopen(name, "r");
if (f) {
char line[100];
while (fgets(line, 100, f)) {
int n = sscanf(line, "Max open files %d", &PerfCounter_fdLimit);
if (n) {
break;
}
}
fclose(f);
}
PerfCounter_fdLimit -= 20; /* keep some slack */
if (PerfCounter_fdLimit == 0) { /* something went wrong */
PerfCounter_fdLimit = 200; /* reasonable default? */
}
}
static long perf_event_open(struct STRUCT_NAME *hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags) {
int ret = syscall(SYSCALL_NUM, hw_event, pid, cpu, group_fd, flags);
#if defined(__x86_64__) || defined(__i386__)
if (ret < 0 && ret > -4096) {
errno = -ret;
ret = -1;
}
#endif
return ret;
}
PerfCounter* PerfCounter_new(pid_t pid, uint32_t type, uint64_t config) {
if (PerfCounter_fdLimit == -1) {
PerfCounter_initFdLimit();
}
PerfCounter* this = xCalloc(sizeof(PerfCounter), 1);
this->pid = pid;
this->events.disabled = 0;
this->events.pinned = 1;
this->events.exclude_hv = 1;
this->events.exclude_kernel = 1;
this->events.type = type;
this->events.config = config;
if (PerfCounter_openFds < PerfCounter_fdLimit) {
this->fd = perf_event_open(&this->events, pid, -1, -1, 0);
} else {
this->fd = -1;
}
if (this->fd != -1) {
PerfCounter_openFds++;
}
return this;
}
void PerfCounter_delete(PerfCounter* this) {
if (!this) {
return;
}
if (this->fd != -1) {
PerfCounter_openFds--;
}
close(this->fd);
free(this);
}
bool PerfCounter_read(PerfCounter* this) {
if (this->fd == -1) {
return false;
}
uint64_t value;
int r = read(this->fd, &value, sizeof(value));
if (r != sizeof(value)) {
close(this->fd);
this->fd = perf_event_open(&this->events, this->pid, -1, -1, 0);
return false;
}
this->prevValue = this->value;
this->value = value;
return true;
}

54
linux/PerfCounter.h Normal file
View File

@ -0,0 +1,54 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_PerfCounter
#define HEADER_PerfCounter
/*
* This file is based on tiptop.
* by Erven ROHOU
* Copyright (c) 2011, 2012, 2014 Inria
* License: GNU General Public License version 2.
*/
#include <config.h>
#include <sys/types.h>
#include <unistd.h>
#include <asm/unistd.h>
#include <inttypes.h>
#include <stdbool.h>
// The sys_perf_counter_open syscall and header files changed names
// between Linux 2.6.31 and 2.6.32. Do the mangling here.
#ifdef HAVE_LINUX_PERF_COUNTER_H
#include <linux/perf_counter.h>
#define STRUCT_NAME perf_counter_attr
#define SYSCALL_NUM __NR_perf_counter_open
#elif HAVE_LINUX_PERF_EVENT_H
#include <linux/perf_event.h>
#define STRUCT_NAME perf_event_attr
#define SYSCALL_NUM __NR_perf_event_open
#else
#error Sorry, performance counters not supported on this system.
#endif
typedef struct PerfCounter_ {
struct STRUCT_NAME events;
pid_t pid;
int fd;
uint64_t prevValue;
uint64_t value;
} PerfCounter;
#define PerfCounter_delta(pc_) ((pc_)->value - (pc_)->prevValue)
extern int PerfCounter_openFds;
PerfCounter* PerfCounter_new(pid_t pid, uint32_t type, uint64_t config);
void PerfCounter_delete(PerfCounter* this);
bool PerfCounter_read(PerfCounter* this);
#endif