Merge branch 'highlight-new-old-processes'

Thanks to @adsr for the great work
Closes #241, closes #74
Massive rebase, so #keepfingerscrossed
This commit is contained in:
Daniel Lange 2020-11-16 13:19:31 +01:00
commit 8bc083c6c6
14 changed files with 161 additions and 37 deletions

12
CRT.c
View File

@ -112,6 +112,8 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[PROCESS_D_STATE] = A_BOLD | ColorPair(Red, Black),
[PROCESS_HIGH_PRIORITY] = ColorPair(Red, Black),
[PROCESS_LOW_PRIORITY] = ColorPair(Green, Black),
[PROCESS_NEW] = ColorPair(Black, Green),
[PROCESS_TOMB] = ColorPair(Black, Red),
[PROCESS_THREAD] = ColorPair(Green, Black),
[PROCESS_THREAD_BASENAME] = A_BOLD | ColorPair(Green, Black),
[BAR_BORDER] = A_BOLD,
@ -191,6 +193,8 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[PROCESS_D_STATE] = A_BOLD,
[PROCESS_HIGH_PRIORITY] = A_BOLD,
[PROCESS_LOW_PRIORITY] = A_DIM,
[PROCESS_NEW] = A_BOLD,
[PROCESS_TOMB] = A_DIM,
[PROCESS_THREAD] = A_BOLD,
[PROCESS_THREAD_BASENAME] = A_REVERSE,
[BAR_BORDER] = A_BOLD,
@ -270,6 +274,8 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[PROCESS_D_STATE] = A_BOLD | ColorPair(Red, White),
[PROCESS_HIGH_PRIORITY] = ColorPair(Red, White),
[PROCESS_LOW_PRIORITY] = ColorPair(Green, White),
[PROCESS_NEW] = ColorPair(White, Green),
[PROCESS_TOMB] = ColorPair(White, Red),
[PROCESS_THREAD] = ColorPair(Blue, White),
[PROCESS_THREAD_BASENAME] = A_BOLD | ColorPair(Blue, White),
[BAR_BORDER] = ColorPair(Blue, White),
@ -349,6 +355,8 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[PROCESS_D_STATE] = A_BOLD | ColorPair(Red, Black),
[PROCESS_HIGH_PRIORITY] = ColorPair(Red, Black),
[PROCESS_LOW_PRIORITY] = ColorPair(Green, Black),
[PROCESS_NEW] = ColorPair(Black, Green),
[PROCESS_TOMB] = ColorPair(Black, Red),
[PROCESS_THREAD] = ColorPair(Blue, Black),
[PROCESS_THREAD_BASENAME] = A_BOLD | ColorPair(Blue, Black),
[BAR_BORDER] = ColorPair(Blue, Black),
@ -428,6 +436,8 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[PROCESS_D_STATE] = A_BOLD | ColorPair(Red, Blue),
[PROCESS_HIGH_PRIORITY] = ColorPair(Red, Blue),
[PROCESS_LOW_PRIORITY] = ColorPair(Green, Blue),
[PROCESS_NEW] = ColorPair(Blue, Green),
[PROCESS_TOMB] = ColorPair(Blue, Red),
[PROCESS_THREAD] = ColorPair(Green, Blue),
[PROCESS_THREAD_BASENAME] = A_BOLD | ColorPair(Green, Blue),
[BAR_BORDER] = A_BOLD | ColorPair(Yellow, Blue),
@ -509,6 +519,8 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[PROCESS_D_STATE] = A_BOLD | ColorPair(Red, Black),
[PROCESS_HIGH_PRIORITY] = ColorPair(Red, Black),
[PROCESS_LOW_PRIORITY] = ColorPair(Green, Black),
[PROCESS_NEW] = ColorPair(Black, Green),
[PROCESS_TOMB] = ColorPair(Black, Red),
[BAR_BORDER] = A_BOLD | ColorPair(Green, Black),
[BAR_SHADOW] = ColorPair(Cyan, Black),
[SWAP] = ColorPair(Red, Black),

2
CRT.h
View File

@ -73,6 +73,8 @@ typedef enum ColorElements_ {
PROCESS_BASENAME,
PROCESS_HIGH_PRIORITY,
PROCESS_LOW_PRIORITY,
PROCESS_NEW,
PROCESS_TOMB,
PROCESS_THREAD,
PROCESS_THREAD_BASENAME,
BAR_BORDER,

View File

@ -93,6 +93,7 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Also show CPU percentage numerically"), &(settings->showCPUUsage)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Also show CPU frequency"), &(settings->showCPUFrequency)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Enable the mouse"), &(settings->enableMouse)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Highlight new and old processes"), &(settings->highlightChanges)));
#ifdef HAVE_LIBHWLOC
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Show topology when selecting affinity by default"), &(settings->topologyAffinity)));
#endif

12
Panel.c
View File

@ -273,16 +273,18 @@ void Panel_draw(Panel* this, bool focus) {
Object_display(itemObj, &item);
int itemLen = RichString_sizeVal(item);
int amt = MINIMUM(itemLen - scrollH, this->w);
bool selected = (i == this->selected);
if (selected) {
attrset(selectionColor);
RichString_setAttr(&item, selectionColor);
if (i == this->selected) {
item.highlightAttr = selectionColor;
}
if (item.highlightAttr) {
attrset(item.highlightAttr);
RichString_setAttr(&item, item.highlightAttr);
this->selectedLen = itemLen;
}
mvhline(y + line, x, ' ', this->w);
if (amt > 0)
RichString_printoffnVal(item, y + line, x, scrollH, amt);
if (selected)
if (item.highlightAttr)
attrset(CRT_colors[RESET_COLOR]);
RichString_end(item);
line++;

View File

@ -394,6 +394,14 @@ void Process_display(const Object* cast, RichString* out) {
RichString_setAttr(out, CRT_colors[PROCESS_TAG]);
}
if (this->settings->highlightChanges) {
if (Process_isTomb(this)) {
out->highlightAttr = CRT_colors[PROCESS_TOMB];
} else if (Process_isNew(this)) {
out->highlightAttr = CRT_colors[PROCESS_NEW];
}
}
assert(out->chlen > 0);
}
@ -429,6 +437,18 @@ void Process_toggleTag(Process* this) {
this->tag = this->tag == true ? false : true;
}
bool Process_isNew(const Process* this) {
assert(this->processList);
if (this->processList->scanTs >= this->seenTs) {
return this->processList->scanTs - this->seenTs <= this->processList->settings->highlightDelaySecs;
}
return false;
}
bool Process_isTomb(const Process* this) {
return this->tombTs > 0;
}
bool Process_setPriority(Process* this, int priority) {
CRT_dropPrivileges();
int old_prio = getpriority(PRIO_PROCESS, this->pid);

View File

@ -9,18 +9,19 @@ in the source distribution for its full text.
*/
#include <stdbool.h>
#include <time.h>
#include <sys/types.h>
#include "Object.h"
#include "RichString.h"
#ifdef __ANDROID__
#define SYS_ioprio_get __NR_ioprio_get
#define SYS_ioprio_set __NR_ioprio_set
#endif
#define PROCESS_FLAG_IO 0x0001
#define DEFAULT_HIGHLIGHT_SECS 5
typedef enum ProcessFields {
NULL_PROCESSFIELD = 0,
@ -59,6 +60,7 @@ struct Settings_;
typedef struct Process_ {
Object super;
const struct ProcessList_* processList;
const struct Settings_* settings;
unsigned long long int time;
@ -76,6 +78,7 @@ typedef struct Process_ {
bool tag;
bool showChildren;
bool show;
bool wasShown;
unsigned int pgrp;
unsigned int session;
unsigned int tty_nr;
@ -99,6 +102,9 @@ typedef struct Process_ {
int exit_signal;
time_t seenTs;
time_t tombTs;
unsigned long int minflt;
unsigned long int majflt;
} Process;
@ -172,6 +178,10 @@ void Process_init(Process* this, const struct Settings_* settings);
void Process_toggleTag(Process* this);
bool Process_isNew(const Process* this);
bool Process_isTomb(const Process* this);
bool Process_setPriority(Process* this, int priority);
bool Process_changePriorityBy(Process* this, Arg delta);

View File

@ -9,6 +9,7 @@ in the source distribution for its full text.
#include <assert.h>
#include <string.h>
#include <time.h>
#include "CRT.h"
#include "XUtils.h"
@ -27,6 +28,8 @@ ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, Users
// set later by platform-specific code
this->cpuCount = 0;
this->scanTs = 0;
#ifdef HAVE_LIBHWLOC
this->topologyOk = false;
if (hwloc_topology_init(&this->topology) == 0) {
@ -85,6 +88,10 @@ void ProcessList_printHeader(ProcessList* this, RichString* header) {
void ProcessList_add(ProcessList* this, Process* p) {
assert(Vector_indexOf(this->processes, p, Process_pidCompare) == -1);
assert(Hashtable_get(this->processTable, p->pid) == NULL);
p->processList = this;
// highlighting processes found in first scan by first scan marked "far in the past"
p->seenTs = this->scanTs;
Vector_add(this->processes, p);
Hashtable_put(this->processTable, p->pid, p);
@ -304,6 +311,7 @@ Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting,
}
void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate) {
struct timespec now;
// in pause mode only gather global data for meters (CPU/memory/...)
if (pauseProcessUpdate) {
@ -315,6 +323,7 @@ void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate) {
for (int i = 0; i < Vector_size(this->processes); i++) {
Process* p = (Process*) Vector_get(this->processes, i);
p->updated = false;
p->wasShown = p->show;
p->show = true;
}
@ -323,12 +332,34 @@ void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate) {
this->kernelThreads = 0;
this->runningTasks = 0;
// set scanTs
static bool firstScanDone = false;
if (!firstScanDone) {
this->scanTs = 0;
firstScanDone = true;
} else if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) {
this->scanTs = now.tv_sec;
}
ProcessList_goThroughEntries(this, false);
for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
Process* p = (Process*) Vector_get(this->processes, i);
if (p->updated == false) {
if (p->tombTs > 0) {
// remove tombed process
if (this->scanTs >= p->tombTs) {
ProcessList_remove(this, p);
}
} else if (p->updated == false) {
// process no longer exists
if (this->settings->highlightChanges && p->wasShown) {
// mark tombed
p->tombTs = this->scanTs + this->settings->highlightDelaySecs;
} else {
// immediately remove
ProcessList_remove(this, p);
}
} else {
p->updated = false;
}

View File

@ -70,6 +70,7 @@ typedef struct ProcessList_ {
int cpuCount;
time_t scanTs;
} ProcessList;
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId);

View File

@ -39,6 +39,7 @@ typedef struct RichString_ {
int chlen;
CharType* chptr;
CharType chstr[RICHSTRING_MAXLEN + 1];
int highlightAttr;
} RichString;
void RichString_setAttrn(RichString* this, int attrs, int start, int finish);

View File

@ -102,6 +102,7 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi
struct timeval tv;
gettimeofday(&tv, NULL);
double newTime = ((double)tv.tv_sec * 10) + ((double)tv.tv_usec / 100000);
*timedOut = (newTime - *oldTime > this->settings->delay);
*rescan |= *timedOut;

View File

@ -157,6 +157,10 @@ static bool Settings_read(Settings* this, const char* fileName, int initialCpuCo
this->highlightMegabytes = atoi(option[1]);
} else if (String_eq(option[0], "highlight_threads")) {
this->highlightThreads = atoi(option[1]);
} else if (String_eq(option[0], "highlight_changes")) {
this->highlightChanges = atoi(option[1]);
} else if (String_eq(option[0], "highlight_changes_delay_secs")) {
this->highlightDelaySecs = atoi(option[1]);
} else if (String_eq(option[0], "header_margin")) {
this->headerMargin = atoi(option[1]);
} else if (String_eq(option[0], "expand_system_time")) {
@ -265,6 +269,8 @@ bool Settings_write(Settings* this) {
fprintf(fd, "highlight_base_name=%d\n", (int) this->highlightBaseName);
fprintf(fd, "highlight_megabytes=%d\n", (int) this->highlightMegabytes);
fprintf(fd, "highlight_threads=%d\n", (int) this->highlightThreads);
fprintf(fd, "highlight_changes=%d\n", (int) this->highlightChanges);
fprintf(fd, "highlight_changes_delay_secs=%d\n", (int) this->highlightDelaySecs);
fprintf(fd, "tree_view=%d\n", (int) this->treeView);
fprintf(fd, "header_margin=%d\n", (int) this->headerMargin);
fprintf(fd, "detailed_cpu_time=%d\n", (int) this->detailedCPUTime);
@ -306,6 +312,8 @@ Settings* Settings_new(int initialCpuCount) {
this->updateProcessNames = false;
this->showProgramPath = true;
this->highlightThreads = true;
this->highlightChanges = false;
this->highlightDelaySecs = DEFAULT_HIGHLIGHT_SECS;
#ifdef HAVE_LIBHWLOC
this->topologyAffinity = false;
#endif

View File

@ -47,6 +47,8 @@ typedef struct Settings_ {
bool highlightBaseName;
bool highlightMegabytes;
bool highlightThreads;
bool highlightChanges;
int highlightDelaySecs;
bool updateProcessNames;
bool accountGuestInCPUMeter;
bool headerMargin;

View File

@ -4,7 +4,7 @@ htop \- interactive process viewer
.SH "SYNOPSIS"
.LP
.B htop
.RB [ \-dCFhpustv ]
.RB [ \-dCFhpustvH ]
.SH "DESCRIPTION"
.LP
.B htop
@ -62,6 +62,9 @@ Output version information and exit
.TP
\fB\-t \-\-tree
Show processes in tree view
.TP
\fB\-H \-\-highlight-changes=DELAY\fR
Highlight new and old processes
.SH "INTERACTIVE COMMANDS"
.LP
The following commands are supported while in

34
htop.c
View File

@ -50,8 +50,9 @@ static void printHelpFlag(void) {
"-d --delay=DELAY Set the delay between updates, in tenths of seconds\n"
"-F --filter=FILTER Show only the commands matching the given filter\n"
"-h --help Print this help screen\n"
"-H --highlight-changes[=DELAY] Highlight new and old processes\n"
"-M --no-mouse Disable the mouse\n"
"-p --pid=PID,[,PID,PID...] Show only the given PIDs\n"
"-p --pid=PID[,PID,PID...] Show only the given PIDs\n"
"-s --sort-key=COLUMN Sort by COLUMN (try --sort-key=help for a list)\n"
"-t --tree Show the tree view by default\n"
"-u --user[=USERNAME] Show only processes for a given user (or $USER)\n"
@ -76,6 +77,8 @@ typedef struct CommandLineSettings_ {
bool enableMouse;
bool treeView;
bool allowUnicode;
bool highlightChanges;
int highlightDelaySecs;
} CommandLineSettings;
static CommandLineSettings parseArguments(int argc, char** argv) {
@ -90,6 +93,8 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
.enableMouse = true,
.treeView = false,
.allowUnicode = true,
.highlightChanges = false,
.highlightDelaySecs = -1,
};
static struct option long_opts[] =
@ -106,12 +111,13 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
{"tree", no_argument, 0, 't'},
{"pid", required_argument, 0, 'p'},
{"filter", required_argument, 0, 'F'},
{"highlight-changes", optional_argument, 0, 'H'},
{0,0,0,0}
};
int opt, opti=0;
/* Parse arguments */
while ((opt = getopt_long(argc, argv, "hVMCs:td:u::Up:F:", long_opts, &opti))) {
while ((opt = getopt_long(argc, argv, "hVMCs:td:u::Up:F:H::", long_opts, &opti))) {
if (opt == EOF) break;
switch (opt) {
case 'h':
@ -206,6 +212,24 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
break;
}
case 'H': {
const char *delay = optarg;
if (!delay && optind < argc && argv[optind] != NULL &&
(argv[optind][0] != '\0' && argv[optind][0] != '-')) {
delay = argv[optind++];
}
if (delay) {
if (sscanf(delay, "%16d", &(flags.highlightDelaySecs)) == 1) {
if (flags.highlightDelaySecs < 1)
flags.highlightDelaySecs = 1;
} else {
fprintf(stderr, "Error: invalid highlight delay value \"%s\".\n", delay);
exit(1);
}
}
flags.highlightChanges = true;
break;
}
default:
exit(1);
}
@ -284,6 +308,12 @@ int main(int argc, char** argv) {
if (flags.treeView) {
settings->treeView = true;
}
if (flags.highlightChanges) {
settings->highlightChanges = true;
}
if (flags.highlightDelaySecs != -1) {
settings->highlightDelaySecs = flags.highlightDelaySecs;
}
CRT_init(settings->delay, settings->colorScheme, flags.allowUnicode);