52 Commits

Author SHA1 Message Date
6ee99566cd Bump version to 3.0.0beta3 2018-02-26 20:13:09 -03:00
dc6bb069f0 Update generated header 2018-02-26 20:13:09 -03:00
0169577019 Fix inttypes.h header 2018-02-26 20:13:09 -03:00
0e38be9ee7 Darwin: expose LAST_PROCESSFIELD like the other platforms 2018-02-26 20:13:09 -03:00
8e6c1e1bac Add more default screens 2018-02-26 20:13:09 -03:00
709619800f Only compute counters is process is shown 2018-02-26 20:13:09 -03:00
a72439c9b7 Implemented various performance counters 2018-02-26 20:13:09 -03:00
61e94c1b5b Add IPC performance counter for Linux 2018-02-26 20:13:09 -03:00
b9f5892593 Add perf counter object 2018-02-26 20:13:09 -03:00
267d03b6d8 configure.ac: add --enable-perfcounters 2018-02-26 20:13:09 -03:00
3b819daf82 Set default sort keys in default screens 2018-02-26 20:13:09 -03:00
d9f8cdf0a6 Add make symbols target 2018-02-26 20:13:09 -03:00
59982a188c Store .sort_key as a string 2018-02-26 20:13:09 -03:00
0800424fe6 Match iotop's screen configuration 2018-02-26 20:13:09 -03:00
b4a8f048d1 Use screen's flags when reading process data 2018-02-26 20:13:09 -03:00
2df1f61d77 Screens: Fix "New Screen" option 2018-02-26 20:13:09 -03:00
e6c98b6e8e htoprc: store screen 0's setup for improved compatibility 2018-02-26 20:13:09 -03:00
b815e4c7a3 Add support for multiple screens, switchable using Tab 2018-02-26 20:13:09 -03:00
4791050cea Begin add supporting for multiple screens 2018-02-26 20:13:09 -03:00
1edcfad874 Move responsibility for cursor placement to Panels 2018-02-26 20:13:09 -03:00
d4ea7cd65c Fix bashisms (#749)
The configure script relied on bash-specific extensions to shell syntax
and behavior, causing build failures on systems with other /bin/sh
implementations. This commit replaces those with equivalent constructs
that should work in all POSIX shells.
2018-02-26 20:07:52 -03:00
9ca1c993ac Add Contributing Guide! 2018-02-26 11:45:53 -03:00
ccd156f8ba Updates to generated header files 2018-02-26 11:44:46 -03:00
858af2505f Protect against overflows in RichString_setAttrn 2018-02-26 11:05:12 -03:00
655c7293d2 Update ChangeLog 2018-02-26 10:54:01 -03:00
bc5d46982f use CFLAGS from ncurses*-config, if present (#745)
Fixes #695.
2018-02-26 10:19:01 -03:00
c01f40eb3e Fix build failure ('major' undefined) in glibc 2.28. (#746)
glibc 2.28 no longer defines 'major' and 'minor' in <sys/types.h> and
requires us to include <sys/sysmacros.h>. (glibc 2.25 starts
deprecating the macros in <sys/types.h>.) Now do include the latter if
found on the system.

At the moment, let's also utilize AC_HEADER_MAJOR in configure script.
However as Autoconf 2.69 has not yet updated the AC_HEADER_MAJOR macro
to reflect the glibc change [1], so add a workaround code.

Fixes #663. Supersedes pull request #729.

Reference:
[1] https://git.savannah.gnu.org/gitweb/?p=autoconf.git;a=commit;h=e17a30e987d7ee695fb4294a82d987ec3dc9b974

Signed-off-by: Kang-Che Sung <explorer09@gmail.com>
2018-02-26 10:15:05 -03:00
eed18dd107 Remove unused function from unsupported/ 2018-02-18 21:18:53 -03:00
f914617508 Make settings file finding sequence more straightforward
Avoid unnecessary access() call and make code read more linearly.
2018-02-18 20:42:17 -03:00
03b2581745 Only consider a read successful when the file seems valid
Require at least the `fields` entry to be present,
so we can have a decent guess that it was indeed a settings file.
2018-02-18 20:35:23 -03:00
8c653212c0 Replace size_t with int/void* union
I was occasionally passing negative values to size_t.
Plus, this better reflects the intent of the variant argument.

Reported by Coverity:
https://scan8.coverity.com/reports.htm#v13253/p10402/fileInstanceId=22093891&defectInstanceId=7543346&mergedDefectId=174179&fileStart=251&fileEnd=500
2018-02-18 10:38:49 -03:00
b064d501ae linux/Battery.c: make sure fd is always closed
Detected by Coverity:
https://scan8.coverity.com/reports.htm#v13252/p10402/fileInstanceId=22093957&defectInstanceId=7543348&mergedDefectId=174180
2018-02-18 10:21:22 -03:00
ff78a1bfce Fix out-of-bounds read
Detected by Coverity:
https://scan8.coverity.com/reports.htm#v13252/p10402/fileInstanceId=22093847&defectInstanceId=7543344&mergedDefectId=174181
2018-02-18 10:17:56 -03:00
f4f35da7e0 Fix indentation 2018-02-18 10:17:29 -03:00
76366be3f1 Update ChangeLog 2018-02-17 21:11:54 -02:00
6dda8d2586 linux/LinuxProcessList.c: Fix indentation. 2018-02-17 20:52:46 -02:00
5fca258f33 call clear() function when SIGWINCH is received. (#660) 2018-02-17 16:25:57 -02:00
70ed51a303 linux/LinuxProcessList: fix reading of number of read syscalls of process
The "if" tests if the character at index "5" is 'r', as a first quick
check. However at index "5" will always be a colon ":". This patch fixes
the off-by-one error. htop now shows proper values in the RD_SYSC
column.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2018-02-17 16:14:34 -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
35 changed files with 503 additions and 112 deletions

View File

@ -115,7 +115,7 @@ static void Action_runSetup(Settings* settings, const Header* header, ProcessLis
static bool changePriority(MainPanel* panel, int delta) { static bool changePriority(MainPanel* panel, int delta) {
bool anyTagged; bool anyTagged;
bool ok = MainPanel_foreachProcess(panel, (MainPanel_ForeachProcessFn) Process_changePriorityBy, delta, &anyTagged); bool ok = MainPanel_foreachProcess(panel, (MainPanel_ForeachProcessFn) Process_changePriorityBy, (Arg){ .i = delta }, &anyTagged);
if (!ok) if (!ok)
beep(); beep();
return anyTagged; return anyTagged;
@ -187,6 +187,7 @@ static Htop_Reaction sortBy(State* st) {
// ---------------------------------------- // ----------------------------------------
static Htop_Reaction actionResize(State* st) { static Htop_Reaction actionResize(State* st) {
clear();
Panel_resize(st->panel, COLS, LINES-(st->panel->y)-1); Panel_resize(st->panel, COLS, LINES-(st->panel->y)-1);
return HTOP_REDRAW_BAR; return HTOP_REDRAW_BAR;
} }
@ -297,7 +298,7 @@ static Htop_Reaction actionSetAffinity(State* st) {
void* set = Action_pickFromVector(st, affinityPanel, 15); void* set = Action_pickFromVector(st, affinityPanel, 15);
if (set) { if (set) {
Affinity* affinity = AffinityPanel_getAffinity(affinityPanel, st->pl); Affinity* affinity = AffinityPanel_getAffinity(affinityPanel, st->pl);
bool ok = MainPanel_foreachProcess((MainPanel*)panel, (MainPanel_ForeachProcessFn) Affinity_set, (size_t) affinity, NULL); bool ok = MainPanel_foreachProcess((MainPanel*)panel, (MainPanel_ForeachProcessFn) Affinity_set, (Arg){ .v = affinity }, NULL);
if (!ok) beep(); if (!ok) beep();
Affinity_delete(affinity); Affinity_delete(affinity);
} }
@ -314,7 +315,7 @@ static Htop_Reaction actionKill(State* st) {
Panel_setHeader(st->panel, "Sending..."); Panel_setHeader(st->panel, "Sending...");
Panel_draw(st->panel, true); Panel_draw(st->panel, true);
refresh(); refresh();
MainPanel_foreachProcess((MainPanel*)st->panel, (MainPanel_ForeachProcessFn) Process_sendSignal, (size_t) sgn->key, NULL); MainPanel_foreachProcess((MainPanel*)st->panel, (MainPanel_ForeachProcessFn) Process_sendSignal, (Arg){ .i = sgn->key }, NULL);
napms(500); napms(500);
} }
} }

56
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,56 @@
Contributing Guide
==================
Hello, and thank you so much for taking your time to contribute in any way to
htop! There are many ways to contribute, and I'll try to list them below. The
support from the free software community has been amazing over the years and
it is the number one thing that keeps me going, maintaining and improving
something that started as a tiny pet project back in 2004 and that nowadays is
a piece of software used all over the world, in both reality [and
fiction!](http://hisham.hm/htop/index.php?page=sightings). Cheers!
-- Hisham Muhammad
Bug Reports
-----------
Bug reports should be posted in the [Github issue
tracker](http://github.com/hishamhm/htop/issues). (I reply to them all, but I
usually do it in batches! :) ) Bug reports are extremely important since it's
impossible for me to test htop in every possible system, distribution and
scenario. Your feedback is what keeps the tool stable and always improving!
Thank you!
Pull Requests
-------------
Code contributions are most welcome! Just [fork the
repo](http://github.com/hishamhm/htop) and send a [pull
request](https://github.com/hishamhm/htop/pulls). Help is especially
appreciated for support of platforms other than Linux. If proposing new
features, please be mindful that htop is a system tool that needs to keep a
small footprint and perform well on systems under stress -- so unfortunately I
can't accept every new feature proposed, as I need to keep the tool slim and
maintainable. Great ideas backed by a PR are always carefully considered for
inclusion, though! Also, PRs containing bug fixes and portability tweaks are a
no-brainer, please send those in!
Feature Requests
----------------
Back when htop was hosted in SourceForge, there used to be separate Bug
Tracker and Feature Request pages. These go all lumped together under "Issues"
in Github, which is a bit confusing. For this reason, I close Feature Requests
and file them with the [`feature
request`](https://github.com/hishamhm/htop/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22feature+request%22+)
label, where they remain accessible, but not mixed with actual bug reports.
This doesn't mean I'm dismissing or ignoring feature requests right away! It's
just an organizational issue (with Github, really!).
Donations
---------
If you like htop, feel free to [buy the author a
beer](http://hisham.hm/htop/index.php?page=donate). :-)

32
CRT.c
View File

@ -37,6 +37,7 @@ in the source distribution for its full text.
#define White COLOR_WHITE #define White COLOR_WHITE
#define ColorPairGrayBlack ColorPair(Magenta,Magenta) #define ColorPairGrayBlack ColorPair(Magenta,Magenta)
#define ColorIndexGrayBlack ColorIndex(Magenta,Magenta)
#define KEY_WHEELUP KEY_F(20) #define KEY_WHEELUP KEY_F(20)
#define KEY_WHEELDOWN KEY_F(21) #define KEY_WHEELDOWN KEY_F(21)
@ -718,22 +719,23 @@ void CRT_enableDelay() {
void CRT_setColors(int colorScheme) { void CRT_setColors(int colorScheme) {
CRT_colorScheme = colorScheme; CRT_colorScheme = colorScheme;
if (colorScheme == COLORSCHEME_BLACKNIGHT) {
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) { for (int j = 0; j < 8; j++) {
if (ColorIndex(i,j) != ColorIndex(Magenta,Magenta)) { if (ColorIndex(i,j) != ColorPairGrayBlack) {
init_pair(ColorIndex(i,j), i, j); 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]; 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 White COLOR_WHITE
#define ColorPairGrayBlack ColorPair(Magenta,Magenta) #define ColorPairGrayBlack ColorPair(Magenta,Magenta)
#define ColorIndexGrayBlack ColorIndex(Magenta,Magenta)
#define KEY_WHEELUP KEY_F(20) #define KEY_WHEELUP KEY_F(20)
#define KEY_WHEELDOWN KEY_F(21) #define KEY_WHEELDOWN KEY_F(21)

View File

@ -1,3 +1,51 @@
What's new in version 2.1.1
* Check for pkg-config when building with --enable-delayacct
(thanks to @florian2833z for the report)
* Use CFLAGS from ncurses*-config if present
(thanks to Michael Klein)
* Fix build failure in Glibc 2.28
(thanks to Kang-Che Sung)
* BUGFIX: fix behavior of SYSCR column
(thanks to Marc Kleine-Budde)
* 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 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; this->settings->changed = true;
const Header* header = this->scr->header; const Header* header = this->scr->header;
CRT_setColors(mark); CRT_setColors(mark);
clear();
Panel* menu = (Panel*) Vector_get(this->scr->panels, 0); Panel* menu = (Panel*) Vector_get(this->scr->panels, 0);
Header_draw(header); Header_draw(header);
RichString_setAttr(&(super->header), CRT_colors[PANEL_HEADER_FOCUS]); RichString_setAttr(&(super->header), CRT_colors[PANEL_HEADER_FOCUS]);

View File

@ -25,7 +25,12 @@ typedef struct MainPanel_ {
pid_t pidSearch; pid_t pidSearch;
} MainPanel; } MainPanel;
typedef bool(*MainPanel_ForeachProcessFn)(Process*, size_t); typedef union {
int i;
void* v;
} Arg;
typedef bool(*MainPanel_ForeachProcessFn)(Process*, Arg);
#define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar) #define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar)
@ -150,7 +155,7 @@ const char* MainPanel_getValue(MainPanel* this, int i) {
return ""; return "";
} }
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, size_t arg, bool* wasAnyTagged) { bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged) {
Panel* super = (Panel*) this; Panel* super = (Panel*) this;
bool ok = true; bool ok = true;
bool anyTagged = false; bool anyTagged = false;

View File

@ -21,7 +21,12 @@ typedef struct MainPanel_ {
pid_t pidSearch; pid_t pidSearch;
} MainPanel; } MainPanel;
typedef bool(*MainPanel_ForeachProcessFn)(Process*, size_t); typedef union {
int i;
void* v;
} Arg;
typedef bool(*MainPanel_ForeachProcessFn)(Process*, Arg);
#define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar) #define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar)
@ -34,7 +39,7 @@ int MainPanel_selectedPid(MainPanel* this);
const char* MainPanel_getValue(MainPanel* this, int i); const char* MainPanel_getValue(MainPanel* this, int i);
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, size_t arg, bool* wasAnyTagged); bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged);
extern PanelClass MainPanel_class; extern PanelClass MainPanel_class;

View File

@ -152,7 +152,7 @@ int Meter_humanUnit(char* buffer, unsigned long int value, int size) {
if (value / 1024 < powi) if (value / 1024 < powi)
break; break;
if (prefix[1] == 0) if (prefix[1] == '\0')
break; break;
powi *= 1024; powi *= 1024;
@ -287,7 +287,7 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
int blockSizes[10]; int blockSizes[10];
xSnprintf(bar, w + 1, "%*s", w, buffer); xSnprintf(bar, w + 1, "%*.*s", w, w, buffer);
// First draw in the bar[] buffer... // First draw in the bar[] buffer...
int offset = 0; int offset = 0;
@ -359,7 +359,7 @@ static int GraphMeterMode_pixPerRow;
static void GraphMeterMode_draw(Meter* this, int x, int y, int w) { static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
if (!this->drawData) this->drawData = xCalloc(1, sizeof(GraphData)); if (!this->drawData) this->drawData = xCalloc(1, sizeof(GraphData));
GraphData* data = (GraphData*) this->drawData; GraphData* data = (GraphData*) this->drawData;
const int nValues = METER_BUFFER_LEN; const int nValues = METER_BUFFER_LEN;
#ifdef HAVE_LIBNCURSESW #ifdef HAVE_LIBNCURSESW
@ -404,7 +404,7 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
k = -i/2; k = -i/2;
i = 0; i = 0;
} }
for (; i < nValues; i+=2, k++) { for (; i < nValues - 1; i+=2, k++) {
int pix = GraphMeterMode_pixPerRow * GRAPH_HEIGHT; int pix = GraphMeterMode_pixPerRow * GRAPH_HEIGHT;
int v1 = CLAMP((int) lround(data->values[i] * pix), 1, pix); int v1 = CLAMP((int) lround(data->values[i] * pix), 1, pix);
int v2 = CLAMP((int) lround(data->values[i+1] * pix), 1, pix); int v2 = CLAMP((int) lround(data->values[i+1] * pix), 1, pix);

View File

@ -130,7 +130,7 @@ void OpenFilesScreen_scan(InfoScreen* this) {
char** data = fdata->data.data; char** data = fdata->data.data;
int lenN = data['n'] ? strlen(data['n']) : 0; int lenN = data['n'] ? strlen(data['n']) : 0;
int sizeEntry = 5 + 7 + 10 + 10 + 10 + lenN + 5 /*spaces*/ + 1 /*null*/; int sizeEntry = 5 + 7 + 10 + 10 + 10 + lenN + 5 /*spaces*/ + 1 /*null*/;
char* entry = xMalloc(sizeEntry); char entry[sizeEntry];
xSnprintf(entry, sizeEntry, "%5.5s %7.7s %10.10s %10.10s %10.10s %s", xSnprintf(entry, sizeEntry, "%5.5s %7.7s %10.10s %10.10s %10.10s %s",
data['f'] ? data['f'] : "", data['f'] ? data['f'] : "",
data['t'] ? data['t'] : "", data['t'] ? data['t'] : "",

View File

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

View File

@ -28,7 +28,12 @@ in the source distribution for its full text.
#include <time.h> #include <time.h>
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <inttypes.h> #ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#elif defined(MAJOR_IN_SYSMACROS) || \
(defined(HAVE_SYS_SYSMACROS_H) && HAVE_SYS_SYSMACROS_H)
#include <sys/sysmacros.h>
#endif
#ifdef __ANDROID__ #ifdef __ANDROID__
#define SYS_ioprio_get __NR_ioprio_get #define SYS_ioprio_get __NR_ioprio_get
@ -46,6 +51,7 @@ in the source distribution for its full text.
#include "Object.h" #include "Object.h"
#include <sys/types.h> #include <sys/types.h>
#include <inttypes.h>
#define PROCESS_FLAG_IO 0x0001 #define PROCESS_FLAG_IO 0x0001
@ -175,6 +181,8 @@ typedef struct ProcessClass_ {
#define Process_isChildOf(process_, pid_) (process_->tgid == pid_ || (process_->tgid == process_->pid && process_->ppid == pid_)) #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; static int Process_getuid = -1;
@ -535,11 +543,11 @@ bool Process_setPriority(Process* this, int priority) {
return (err == 0); return (err == 0);
} }
bool Process_changePriorityBy(Process* this, size_t delta) { bool Process_changePriorityBy(Process* this, int delta) {
return Process_setPriority(this, this->nice + delta); return Process_setPriority(this, this->nice + delta);
} }
void Process_sendSignal(Process* this, size_t sgn) { void Process_sendSignal(Process* this, int sgn) {
CRT_dropPrivileges(); CRT_dropPrivileges();
kill(this->pid, (int) sgn); kill(this->pid, (int) sgn);
CRT_restorePrivileges(); CRT_restorePrivileges();
@ -600,7 +608,7 @@ long Process_compare(const void* v1, const void* v2) {
return (p1->starttime_ctime - p2->starttime_ctime); return (p1->starttime_ctime - p2->starttime_ctime);
} }
case STATE: case STATE:
return (p1->state - p2->state); return (Process_sortState(p1->state) - Process_sortState(p2->state));
case ST_UID: case ST_UID:
return (p1->st_uid - p2->st_uid); return (p1->st_uid - p2->st_uid);
case TIME: case TIME:

View File

@ -9,6 +9,11 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#ifdef MAJOR_IN_MKDEV
#elif defined(MAJOR_IN_SYSMACROS) || \
(defined(HAVE_SYS_SYSMACROS_H) && HAVE_SYS_SYSMACROS_H)
#endif
#ifdef __ANDROID__ #ifdef __ANDROID__
#define SYS_ioprio_get __NR_ioprio_get #define SYS_ioprio_get __NR_ioprio_get
#define SYS_ioprio_set __NR_ioprio_set #define SYS_ioprio_set __NR_ioprio_set
@ -24,6 +29,7 @@ in the source distribution for its full text.
#include "Object.h" #include "Object.h"
#include <sys/types.h> #include <sys/types.h>
#include <inttypes.h>
#define PROCESS_FLAG_IO 0x0001 #define PROCESS_FLAG_IO 0x0001
@ -153,6 +159,8 @@ typedef struct ProcessClass_ {
#define Process_isChildOf(process_, pid_) (process_->tgid == pid_ || (process_->tgid == process_->pid && process_->ppid == pid_)) #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_K 1024L
#define ONE_M (ONE_K * ONE_K) #define ONE_M (ONE_K * ONE_K)
@ -190,9 +198,9 @@ void Process_toggleTag(Process* this);
bool Process_setPriority(Process* this, int priority); bool Process_setPriority(Process* this, int priority);
bool Process_changePriorityBy(Process* this, size_t delta); bool Process_changePriorityBy(Process* this, int delta);
void Process_sendSignal(Process* this, size_t sgn); void Process_sendSignal(Process* this, int sgn);
long Process_pidCompare(const void* v1, const void* v2); long Process_pidCompare(const void* v1, const void* v2);

View File

@ -232,6 +232,11 @@ void ProcessList_sort(ProcessList* this) {
pid_t ppid = process->tgid == process->pid ? process->ppid : process->tgid; pid_t ppid = process->tgid == process->pid ? process->ppid : process->tgid;
// Bisect the process vector to find parent // Bisect the process vector to find parent
int l = 0, r = size; 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) { while (l < r) {
int c = (l + r) / 2; int c = (l + r) / 2;
pid_t pid = ((Process*)(Vector_get(this->processes, c)))->pid; pid_t pid = ((Process*)(Vector_get(this->processes, c)))->pid;

View File

@ -63,6 +63,10 @@ typedef struct RichString_ {
}*/ }*/
#ifndef CLAMP
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
#define charBytes(n) (sizeof(CharType) * (n)) #define charBytes(n) (sizeof(CharType) * (n))
static void RichString_extendLen(RichString* this, int len) { static void RichString_extendLen(RichString* this, int len) {
@ -103,6 +107,7 @@ static inline void RichString_writeFrom(RichString* this, int attrs, const char*
inline void RichString_setAttrn(RichString* this, int attrs, int start, int finish) { inline void RichString_setAttrn(RichString* this, int attrs, int start, int finish) {
cchar_t* ch = this->chptr + start; cchar_t* ch = this->chptr + start;
finish = CLAMP(finish, 0, this->chlen - 1);
for (int i = start; i <= finish; i++) { for (int i = start; i <= finish; i++) {
ch->attr = attrs; ch->attr = attrs;
ch++; ch++;
@ -132,6 +137,7 @@ static inline void RichString_writeFrom(RichString* this, int attrs, const char*
void RichString_setAttrn(RichString* this, int attrs, int start, int finish) { void RichString_setAttrn(RichString* this, int attrs, int start, int finish) {
chtype* ch = this->chptr + start; chtype* ch = this->chptr + start;
finish = CLAMP(finish, 0, this->chlen - 1);
for (int i = start; i <= finish; i++) { for (int i = start; i <= finish; i++) {
*ch = (*ch & 0xff) | attrs; *ch = (*ch & 0xff) | attrs;
ch++; ch++;

View File

@ -59,6 +59,10 @@ typedef struct RichString_ {
} RichString; } RichString;
#ifndef CLAMP
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
#define charBytes(n) (sizeof(CharType) * (n)) #define charBytes(n) (sizeof(CharType) * (n))
#define RichString_setLen(this, len) do{ if(len < RICHSTRING_MAXLEN && this->chlen < RICHSTRING_MAXLEN) { RichString_setChar(this,len,0); this->chlen=len; } else RichString_extendLen(this,len); }while(0) #define RichString_setLen(this, len) do{ if(len < RICHSTRING_MAXLEN && this->chlen < RICHSTRING_MAXLEN) { RichString_setChar(this,len,0); this->chlen=len; } else RichString_extendLen(this,len); }while(0)

View File

@ -285,7 +285,8 @@ static bool Settings_read(Settings* this, const char* fileName) {
if (!fd) if (!fd)
return false; return false;
bool readMeters = false; bool didReadMeters = false;
bool didReadFields = false;
ProcessField* legacyFields = xCalloc(Platform_numberOfFields+1, sizeof(ProcessField)); ProcessField* legacyFields = xCalloc(Platform_numberOfFields+1, sizeof(ProcessField));
int legacyFlags; int legacyFlags;
bool legacyFieldsRead = false; bool legacyFieldsRead = false;
@ -342,16 +343,16 @@ static bool Settings_read(Settings* this, const char* fileName) {
if (this->colorScheme < 0 || this->colorScheme >= LAST_COLORSCHEME) this->colorScheme = 0; if (this->colorScheme < 0 || this->colorScheme >= LAST_COLORSCHEME) this->colorScheme = 0;
} else if (String_eq(option[0], "left_meters")) { } else if (String_eq(option[0], "left_meters")) {
Settings_readMeters(this, option[1], 0); Settings_readMeters(this, option[1], 0);
readMeters = true; didReadMeters = true;
} else if (String_eq(option[0], "right_meters")) { } else if (String_eq(option[0], "right_meters")) {
Settings_readMeters(this, option[1], 1); Settings_readMeters(this, option[1], 1);
readMeters = true; didReadMeters = true;
} else if (String_eq(option[0], "left_meter_modes")) { } else if (String_eq(option[0], "left_meter_modes")) {
Settings_readMeterModes(this, option[1], 0); Settings_readMeterModes(this, option[1], 0);
readMeters = true; didReadMeters = true;
} else if (String_eq(option[0], "right_meter_modes")) { } else if (String_eq(option[0], "right_meter_modes")) {
Settings_readMeterModes(this, option[1], 1); Settings_readMeterModes(this, option[1], 1);
readMeters = true; didReadMeters = true;
} else if (strncmp(option[0], "screen:", 7) == 0) { } else if (strncmp(option[0], "screen:", 7) == 0) {
Settings_newScreen(this, option[0] + 7, option[1]); Settings_newScreen(this, option[0] + 7, option[1]);
} else if (String_eq(option[0], ".tree_view")) { } else if (String_eq(option[0], ".tree_view")) {
@ -378,10 +379,10 @@ static bool Settings_read(Settings* this, const char* fileName) {
this->screens[0]->flags = legacyFlags; this->screens[0]->flags = legacyFlags;
} }
} }
if (!readMeters) { if (!didReadMeters) {
Settings_defaultMeters(this); Settings_defaultMeters(this);
} }
return true; return didReadFields;
} }
static void writeFields(FILE* fd, ProcessField* fields, bool byName) { static void writeFields(FILE* fd, ProcessField* fields, bool byName) {
@ -513,10 +514,8 @@ Settings* Settings_new(int cpuCount) {
free(htopDir); free(htopDir);
free(configDir); free(configDir);
struct stat st; struct stat st;
if (lstat(legacyDotfile, &st) != 0) { int err = lstat(legacyDotfile, &st);
st.st_mode = 0; if (err || S_ISLNK(st.st_mode)) {
}
if (access(legacyDotfile, R_OK) != 0 || S_ISLNK(st.st_mode)) {
free(legacyDotfile); free(legacyDotfile);
legacyDotfile = NULL; legacyDotfile = NULL;
} }
@ -525,33 +524,38 @@ Settings* Settings_new(int cpuCount) {
this->colorScheme = 0; this->colorScheme = 0;
this->changed = false; this->changed = false;
this->delay = DEFAULT_DELAY; this->delay = DEFAULT_DELAY;
bool ok = Settings_read(this, legacyDotfile ? legacyDotfile : this->filename); bool ok = false;
if (ok) { if (legacyDotfile) {
if (legacyDotfile) { ok = Settings_read(this, legacyDotfile);
if (ok) {
// Transition to new location and delete old configuration file // Transition to new location and delete old configuration file
if (Settings_write(this)) if (Settings_write(this))
unlink(legacyDotfile); unlink(legacyDotfile);
} }
} else { free(legacyDotfile);
}
if (!ok) {
ok = Settings_read(this, this->filename);
}
if (!ok) {
this->changed = true; this->changed = true;
// TODO: how to get SYSCONFDIR correctly through Autoconf? // TODO: how to get SYSCONFDIR correctly through Autoconf?
char* systemSettings = String_cat(SYSCONFDIR, "/htoprc"); char* systemSettings = String_cat(SYSCONFDIR, "/htoprc");
ok = Settings_read(this, systemSettings); ok = Settings_read(this, systemSettings);
free(systemSettings); free(systemSettings);
if (!ok) { }
Settings_defaultMeters(this); if (!ok) {
Settings_defaultScreens(this); Settings_defaultMeters(this);
this->hideKernelThreads = true; Settings_defaultScreens(this);
this->highlightMegabytes = true; this->hideKernelThreads = true;
this->highlightThreads = true; this->highlightMegabytes = true;
this->headerMargin = true; this->highlightThreads = true;
} this->headerMargin = true;
} }
this->ssIndex = 0; this->ssIndex = 0;
this->ss = this->screens[this->ssIndex]; this->ss = this->screens[this->ssIndex];
free(legacyDotfile);
return this; return this;
} }

View File

@ -9,6 +9,7 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#define DEFAULT_DELAY 15
#include "Process.h" #include "Process.h"
#include <stdbool.h> #include <stdbool.h>

View File

@ -108,7 +108,8 @@ bool TraceScreen_forkTracer(TraceScreen* this) {
(void) written; (void) written;
exit(1); exit(1);
} }
fcntl(this->fdpair[0], F_SETFL, O_NONBLOCK); int ok = fcntl(this->fdpair[0], F_SETFL, O_NONBLOCK);
if (ok == -1) return false;
this->strace = fdopen(this->fdpair[0], "r"); this->strace = fdopen(this->fdpair[0], "r");
this->fd_strace = fileno(this->strace); this->fd_strace = fileno(this->strace);
return true; return true;

View File

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

View File

@ -70,8 +70,16 @@ extern Object* Vector_get(Vector* this, int idx);
#endif #endif
#ifdef DEBUG
extern int Vector_size(Vector* this); 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. # Process this file with autoconf to produce a configure script.
AC_PREREQ(2.65) AC_PREREQ(2.65)
AC_INIT([htop],[2.0.2],[hisham@gobolinux.org]) AC_INIT([htop],[3.0.0beta3],[hisham@gobolinux.org])
SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(date +%s)}" 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") year=$(date -u -d "@$SOURCE_DATE_EPOCH" "+%Y" 2>/dev/null || date -u -r "$SOURCE_DATE_EPOCH" "+%Y" 2>/dev/null || date -u "+%Y")
@ -61,6 +61,16 @@ AC_CHECK_HEADERS([stdlib.h string.h strings.h sys/param.h sys/time.h unistd.h],[
]) ])
AC_CHECK_HEADERS([execinfo.h],[:],[:]) AC_CHECK_HEADERS([execinfo.h],[:],[:])
AC_HEADER_MAJOR
dnl glibc 2.25 deprecates 'major' and 'minor' in <sys/types.h> and requires to
dnl include <sys/sysmacros.h>. However the logic in AC_HEADER_MAJOR has not yet
dnl been updated in Autoconf 2.69, so use a workaround:
m4_version_prereq([2.70], [],
[if test "x$ac_cv_header_sys_mkdev_h" = xno; then
AC_CHECK_HEADER(sys/sysmacros.h, [AC_DEFINE(MAJOR_IN_SYSMACROS, 1,
[Define to 1 if `major', `minor', and `makedev' are declared in <sys/sysmacros.h>.])])
fi])
# Checks for typedefs, structures, and compiler characteristics. # Checks for typedefs, structures, and compiler characteristics.
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
AC_HEADER_STDBOOL AC_HEADER_STDBOOL
@ -154,20 +164,26 @@ m4_define([HTOP_CHECK_SCRIPT],
[ [
if test ! -z "m4_toupper($HTOP_[$1]_CONFIG_SCRIPT)"; then if test ! -z "m4_toupper($HTOP_[$1]_CONFIG_SCRIPT)"; then
# to be used to set the path to ncurses*-config when cross-compiling # to be used to set the path to ncurses*-config when cross-compiling
htop_config_script=$(m4_toupper($HTOP_[$1]_CONFIG_SCRIPT) --libs 2> /dev/null) htop_config_script_libs=$(m4_toupper($HTOP_[$1]_CONFIG_SCRIPT) --libs 2> /dev/null)
htop_config_script_cflags=$(m4_toupper($HTOP_[$1]_CONFIG_SCRIPT) --cflags 2> /dev/null)
else else
htop_config_script=$([$4] --libs 2> /dev/null) htop_config_script_libs=$([$4] --libs 2> /dev/null)
htop_config_script_cflags=$([$4] --cflags 2> /dev/null)
fi fi
htop_script_success=no htop_script_success=no
htop_save_LDFLAGS="$LDFLAGS" htop_save_LDFLAGS="$LDFLAGS"
if test ! "x$htop_config_script" = x; then htop_save_CFLAGS="$CFLAGS"
LDFLAGS="$htop_config_script $LDFLAGS" if test ! "x$htop_config_script_libs" = x; then
LDFLAGS="$htop_config_script_libs $LDFLAGS"
CFLAGS="$htop_config_script_cflags $CFLAGS"
AC_CHECK_LIB([$1], [$2], [ AC_CHECK_LIB([$1], [$2], [
AC_DEFINE([$3], 1, [The library is present.]) AC_DEFINE([$3], 1, [The library is present.])
LIBS="$htop_config_script $LIBS " LIBS="$htop_config_script_libs $LIBS "
htop_script_success=yes htop_script_success=yes
], []) ], [
LDFLAGS="$save_LDFLAGS" CFLAGS="$htop_save_CFLAGS"
])
LDFLAGS="$htop_save_LDFLAGS"
fi fi
if test "x$htop_script_success" = xno; then if test "x$htop_script_success" = xno; then
[$5] [$5]
@ -305,10 +321,11 @@ fi
AC_ARG_ENABLE(delayacct, [AS_HELP_STRING([--enable-delayacct], [enable linux delay accounting])],, enable_delayacct="no") AC_ARG_ENABLE(delayacct, [AS_HELP_STRING([--enable-delayacct], [enable linux delay accounting])],, enable_delayacct="no")
if test "x$enable_delayacct" = xyes if test "x$enable_delayacct" = xyes
then then
PKG_PROG_PKG_CONFIG()
PKG_CHECK_MODULES(LIBNL3, libnl-3.0, [], [missing_libraries="$missing_libraries libnl-3"]) PKG_CHECK_MODULES(LIBNL3, libnl-3.0, [], [missing_libraries="$missing_libraries libnl-3"])
PKG_CHECK_MODULES(LIBNL3GENL, libnl-genl-3.0, [], [missing_libraries="$missing_libraries libnl-genl-3"]) PKG_CHECK_MODULES(LIBNL3GENL, libnl-genl-3.0, [], [missing_libraries="$missing_libraries libnl-genl-3"])
CFLAGS+=" $LIBNL3_CFLAGS $LIBNL3GENL_CFLAGS" CFLAGS="$CFLAGS $LIBNL3_CFLAGS $LIBNL3GENL_CFLAGS"
LIBS+=" $LIBNL3_LIBS $LIBNL3GENL_LIBS" LIBS="$LIBS $LIBNL3_LIBS $LIBNL3GENL_LIBS"
AC_DEFINE(HAVE_DELAYACCT, 1, [Define if delay accounting support should be enabled.]) AC_DEFINE(HAVE_DELAYACCT, 1, [Define if delay accounting support should be enabled.])
fi fi

View File

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

View File

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

View File

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

View File

@ -49,11 +49,11 @@ The following commands are supported while in htop:
.LP .LP
.TP 5 .TP 5
.B Up, Alt-k .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. if necessary.
.TP .TP
.B Down, Alt-j .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. necessary.
.TP .TP
.B Left, Alt-h .B Left, Alt-h

View File

@ -72,6 +72,8 @@ static unsigned long int parseBatInfo(const char *fileName, const unsigned short
fclose(file); fclose(file);
if (!line) break;
char *foundNumStr = String_getToken(line, wordNum); char *foundNumStr = String_getToken(line, wordNum);
const unsigned long int foundNum = atoi(foundNumStr); const unsigned long int foundNum = atoi(foundNumStr);
free(foundNumStr); free(foundNumStr);
@ -108,16 +110,13 @@ static ACPresence procAcpiCheck() {
char statePath[50]; char statePath[50];
xSnprintf((char *) statePath, sizeof statePath, "%s/%s/state", power_supplyPath, entryName); xSnprintf((char *) statePath, sizeof statePath, "%s/%s/state", power_supplyPath, entryName);
FILE* file = fopen(statePath, "r"); FILE* file = fopen(statePath, "r");
if (!file) { if (!file) {
isOn = AC_ERROR; isOn = AC_ERROR;
continue; continue;
} }
char* line = String_readLine(file); char* line = String_readLine(file);
if (!line) continue;
fclose(file); fclose(file);
if (!line) continue;
const char *isOnline = String_getToken(line, 2); const char *isOnline = String_getToken(line, 2);
free(line); free(line);

View File

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

View File

@ -26,6 +26,12 @@ in the source distribution for its full text.
#include <assert.h> #include <assert.h>
#include <sys/types.h> #include <sys/types.h>
#include <fcntl.h> #include <fcntl.h>
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#elif defined(MAJOR_IN_SYSMACROS) || \
(defined(HAVE_SYS_SYSMACROS_H) && HAVE_SYS_SYSMACROS_H)
#include <sys/sysmacros.h>
#endif
#ifdef HAVE_DELAYACCT #ifdef HAVE_DELAYACCT
#include <netlink/attr.h> #include <netlink/attr.h>
@ -436,7 +442,7 @@ static void LinuxProcessList_readIoFile(LinuxProcess* process, const char* dirna
} }
break; break;
case 's': case 's':
if (line[5] == 'r' && strncmp(line+1, "yscr: ", 6) == 0) { if (line[4] == 'r' && strncmp(line+1, "yscr: ", 6) == 0) {
process->io_syscr = strtoull(line+7, NULL, 10); process->io_syscr = strtoull(line+7, NULL, 10);
} else if (strncmp(line+1, "yscw: ", 6) == 0) { } else if (strncmp(line+1, "yscw: ", 6) == 0) {
process->io_syscw = strtoull(line+7, NULL, 10); process->io_syscw = strtoull(line+7, NULL, 10);
@ -595,36 +601,36 @@ static void LinuxProcessList_readOomData(LinuxProcess* process, const char* dirn
static int handleNetlinkMsg(struct nl_msg *nlmsg, void *linuxProcess) { static int handleNetlinkMsg(struct nl_msg *nlmsg, void *linuxProcess) {
struct nlmsghdr *nlhdr; struct nlmsghdr *nlhdr;
struct nlattr *nlattrs[TASKSTATS_TYPE_MAX + 1]; struct nlattr *nlattrs[TASKSTATS_TYPE_MAX + 1];
struct nlattr *nlattr; struct nlattr *nlattr;
struct taskstats *stats; struct taskstats *stats;
int rem; int rem;
unsigned long long int timeDelta; unsigned long long int timeDelta;
LinuxProcess* lp = (LinuxProcess*) linuxProcess; LinuxProcess* lp = (LinuxProcess*) linuxProcess;
nlhdr = nlmsg_hdr(nlmsg); nlhdr = nlmsg_hdr(nlmsg);
if (genlmsg_parse(nlhdr, 0, nlattrs, TASKSTATS_TYPE_MAX, NULL) < 0) { if (genlmsg_parse(nlhdr, 0, nlattrs, TASKSTATS_TYPE_MAX, NULL) < 0) {
return NL_SKIP; return NL_SKIP;
} }
if ((nlattr = nlattrs[TASKSTATS_TYPE_AGGR_PID]) || (nlattr = nlattrs[TASKSTATS_TYPE_NULL])) { if ((nlattr = nlattrs[TASKSTATS_TYPE_AGGR_PID]) || (nlattr = nlattrs[TASKSTATS_TYPE_NULL])) {
stats = nla_data(nla_next(nla_data(nlattr), &rem)); stats = nla_data(nla_next(nla_data(nlattr), &rem));
assert(lp->super.pid == stats->ac_pid); assert(lp->super.pid == stats->ac_pid);
timeDelta = (stats->ac_etime*1000 - lp->delay_read_time); timeDelta = (stats->ac_etime*1000 - lp->delay_read_time);
#define BOUNDS(x) isnan(x) ? 0.0 : (x > 100) ? 100.0 : x; #define BOUNDS(x) isnan(x) ? 0.0 : (x > 100) ? 100.0 : x;
#define DELTAPERC(x,y) BOUNDS((float) (x - y) / timeDelta * 100); #define DELTAPERC(x,y) BOUNDS((float) (x - y) / timeDelta * 100);
lp->cpu_delay_percent = DELTAPERC(stats->cpu_delay_total, lp->cpu_delay_total); lp->cpu_delay_percent = DELTAPERC(stats->cpu_delay_total, lp->cpu_delay_total);
lp->blkio_delay_percent = DELTAPERC(stats->blkio_delay_total, lp->blkio_delay_total); lp->blkio_delay_percent = DELTAPERC(stats->blkio_delay_total, lp->blkio_delay_total);
lp->swapin_delay_percent = DELTAPERC(stats->swapin_delay_total, lp->swapin_delay_total); lp->swapin_delay_percent = DELTAPERC(stats->swapin_delay_total, lp->swapin_delay_total);
#undef DELTAPERC #undef DELTAPERC
#undef BOUNDS #undef BOUNDS
lp->swapin_delay_total = stats->swapin_delay_total; lp->swapin_delay_total = stats->swapin_delay_total;
lp->blkio_delay_total = stats->blkio_delay_total; lp->blkio_delay_total = stats->blkio_delay_total;
lp->cpu_delay_total = stats->cpu_delay_total; lp->cpu_delay_total = stats->cpu_delay_total;
lp->delay_read_time = stats->ac_etime*1000; lp->delay_read_time = stats->ac_etime*1000;
} }
return NL_OK; return NL_OK;
} }
static void LinuxProcessList_readDelayAcctData(LinuxProcessList* this, LinuxProcess* process) { static void LinuxProcessList_readDelayAcctData(LinuxProcessList* this, LinuxProcess* process) {

View File

@ -9,6 +9,11 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#ifdef MAJOR_IN_MKDEV
#elif defined(MAJOR_IN_SYSMACROS) || \
(defined(HAVE_SYS_SYSMACROS_H) && HAVE_SYS_SYSMACROS_H)
#endif
#ifdef HAVE_DELAYACCT #ifdef HAVE_DELAYACCT
#endif #endif

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

View File

@ -97,7 +97,7 @@ static Htop_Reaction Platform_actionSetIOPriority(State* st) {
void* set = Action_pickFromVector(st, ioprioPanel, 21); void* set = Action_pickFromVector(st, ioprioPanel, 21);
if (set) { if (set) {
IOPriority ioprio = IOPriorityPanel_getIOPriority(ioprioPanel); IOPriority ioprio = IOPriorityPanel_getIOPriority(ioprioPanel);
bool ok = MainPanel_foreachProcess((MainPanel*)panel, (MainPanel_ForeachProcessFn) LinuxProcess_setIOPriority, (size_t) ioprio, NULL); bool ok = MainPanel_foreachProcess((MainPanel*)panel, (MainPanel_ForeachProcessFn) LinuxProcess_setIOPriority, (Arg){ .i = ioprio }, NULL);
if (!ok) if (!ok)
beep(); beep();
} }

View File

@ -68,8 +68,3 @@ void ProcessList_goThroughEntries(ProcessList* super) {
proc->minflt = 20; proc->minflt = 20;
proc->majflt = 20; proc->majflt = 20;
} }
void UnsupportedProcessList_scan(ProcessList* this) {
(void) this;
// stub!
}

View File

@ -17,6 +17,4 @@ void ProcessList_delete(ProcessList* this);
void ProcessList_goThroughEntries(ProcessList* super); void ProcessList_goThroughEntries(ProcessList* super);
void UnsupportedProcessList_scan(ProcessList* this);
#endif #endif