33 Commits
0.6.3 ... 0.6.5

Author SHA1 Message Date
0a5e68652d Tag release 0.6.5 in revision history. 2006-12-01 17:53:52 +00:00
e3198ca63b Fix gcc warning. 2006-11-29 18:35:25 +00:00
92a5a691fd Report change suggested by Bo Liu 2006-11-20 16:46:20 +00:00
6b6b4373b5 Changes suggested by Bo Liu 2006-11-20 16:42:03 +00:00
2a025bf4c6 Add information about the status column
(which I always forget) in the help page
2006-11-16 15:20:44 +00:00
14808f7f70 Getting ready for 0.6.5... 2006-11-14 17:24:09 +00:00
a26ef71ed8 Minor tweak. 2006-11-13 22:04:17 +00:00
a8f45d5743 Sanity cleanup. 2006-11-13 22:00:16 +00:00
9076b9edeb Add latest changes to the log 2006-11-13 21:59:01 +00:00
0f027ded2c Fix for missing libraries message, as reported by Jon 780 2006-11-13 20:06:31 +00:00
3d62edb678 Bugfix: collect orphaned items during tree generation
at the end of the tree.
Add debugging sanity checks.
2006-11-12 21:53:56 +00:00
36848494f5 Add debugging sanity checks. 2006-11-12 21:52:14 +00:00
c90a445103 Don't double-free comm when it's an existingProcess 2006-11-09 01:44:20 +00:00
97ea7a1a8c Ok, second take on fixing the handling of comm.- 2006-11-08 22:16:46 +00:00
adbfe82e63 Oops. 2006-11-08 22:09:13 +00:00
45fab61da3 Avoid double free of prototype's comm. 2006-11-08 22:08:00 +00:00
8adc7ac00f Fix asserts, don't use freed memory. 2006-11-08 21:49:52 +00:00
2713119249 Add missing header. 2006-11-08 21:49:07 +00:00
59c3dd806b Yet another sanity check. 2006-11-08 21:47:11 +00:00
c494308b21 Add an additional debug mode for Hardened GCC. 2006-11-08 21:46:40 +00:00
c4fbd7fc8b Assign creation of the allocation log file to a separate #define. 2006-11-08 20:40:10 +00:00
febe259e91 Add lots of debugging asserts and try to clean up behavior of lists in general.
Make dumping of proc data controlled by a separate debug define.
2006-11-08 20:12:57 +00:00
110ce71b9b Add consistency checks. 2006-11-08 20:09:48 +00:00
46b35b2c7f Initialize variable. 2006-11-08 20:09:12 +00:00
b25ac6b0f7 Handle situation instead of assuming it would never happen,
as it was seen out in the field and tested here.
2006-10-26 23:06:52 +00:00
649419abe5 Prepare for next release 2006-10-04 16:42:15 +00:00
2c4d730403 Allocate per-processor values in a contiguous chunk of memory 2006-10-04 16:25:41 +00:00
538d29b3f6 Add changelog entry for Philipp Richter's contribution 2006-10-04 14:48:03 +00:00
3e4f06d101 Contribution by Philipp Richter: Display IO-Wait, IRQ and Soft-IRQ values in status bar
(minor modifications: default to false, add help)
2006-10-04 14:21:27 +00:00
4a93a7e962 changelog entry for Marc's bugfix 2006-08-30 04:38:53 +00:00
ef5b27f33a A fix for long uptimes, sent my Marc Cahalan 2006-08-30 04:37:20 +00:00
cc5af25e11 Fix bug 1538463. 2006-08-24 21:28:29 +00:00
b10821aae9 --sort-key flag in the command-line, overriding the
saved setting in .htoprc for the session.
(thanks to Rodolfo Borges)
2006-08-04 20:54:37 +00:00
25 changed files with 400 additions and 132 deletions

View File

@ -19,14 +19,14 @@ in the source distribution for its full text.
#include <assert.h> #include <assert.h>
int CPUMeter_attributes[] = { int CPUMeter_attributes[] = {
CPU_NICE, CPU_NORMAL, CPU_KERNEL CPU_NICE, CPU_NORMAL, CPU_KERNEL, CPU_IOWAIT, CPU_IRQ, CPU_SOFTIRQ
}; };
MeterType CPUMeter = { MeterType CPUMeter = {
.setValues = CPUMeter_setValues, .setValues = CPUMeter_setValues,
.display = CPUMeter_display, .display = CPUMeter_display,
.mode = BAR_METERMODE, .mode = BAR_METERMODE,
.items = 3, .items = 6,
.total = 100.0, .total = 100.0,
.attributes = CPUMeter_attributes, .attributes = CPUMeter_attributes,
.name = "CPU", .name = "CPU",
@ -71,10 +71,22 @@ void CPUMeter_setValues(Meter* this, char* buffer, int size) {
ProcessList* pl = this->pl; ProcessList* pl = this->pl;
int processor = this->param; int processor = this->param;
double total = (double) pl->totalPeriod[processor]; double total = (double) pl->totalPeriod[processor];
double cpu;
this->values[0] = pl->nicePeriod[processor] / total * 100.0; this->values[0] = pl->nicePeriod[processor] / total * 100.0;
this->values[1] = pl->userPeriod[processor] / total * 100.0; this->values[1] = pl->userPeriod[processor] / total * 100.0;
this->values[2] = pl->systemPeriod[processor] / total * 100.0; if (pl->expandSystemTime) {
double cpu = MIN(100.0, MAX(0.0, (this->values[0]+this->values[1]+this->values[2]))); this->values[2] = pl->systemPeriod[processor] / total * 100.0;
this->values[3] = pl->ioWaitPeriod[processor] / total * 100.0;
this->values[4] = pl->irqPeriod[processor] / total * 100.0;
this->values[5] = pl->softIrqPeriod[processor] / total * 100.0;
this->type->items = 6;
cpu = MIN(100.0, MAX(0.0, (this->values[0]+this->values[1]+this->values[2]+
this->values[3]+this->values[4]+this->values[5])));
} else {
this->values[2] = pl->systemAllPeriod[processor] / total * 100.0;
this->type->items = 3;
cpu = MIN(100.0, MAX(0.0, (this->values[0]+this->values[1]+this->values[2])));
}
snprintf(buffer, size, "%5.1f%%", cpu ); snprintf(buffer, size, "%5.1f%%", cpu );
} }
@ -85,12 +97,30 @@ void CPUMeter_display(Object* cast, RichString* out) {
sprintf(buffer, "%5.1f%% ", this->values[1]); sprintf(buffer, "%5.1f%% ", this->values[1]);
RichString_append(out, CRT_colors[METER_TEXT], ":"); RichString_append(out, CRT_colors[METER_TEXT], ":");
RichString_append(out, CRT_colors[CPU_NORMAL], buffer); RichString_append(out, CRT_colors[CPU_NORMAL], buffer);
sprintf(buffer, "%5.1f%% ", this->values[2]); if (this->pl->expandSystemTime) {
RichString_append(out, CRT_colors[METER_TEXT], "sys:"); sprintf(buffer, "%5.1f%% ", this->values[2]);
RichString_append(out, CRT_colors[CPU_KERNEL], buffer); RichString_append(out, CRT_colors[METER_TEXT], "sy:");
sprintf(buffer, "%5.1f%% ", this->values[0]); RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
RichString_append(out, CRT_colors[METER_TEXT], "low:"); sprintf(buffer, "%5.1f%% ", this->values[0]);
RichString_append(out, CRT_colors[CPU_NICE], buffer); RichString_append(out, CRT_colors[METER_TEXT], "ni:");
RichString_append(out, CRT_colors[CPU_NICE], buffer);
sprintf(buffer, "%5.1f%% ", this->values[3]);
RichString_append(out, CRT_colors[METER_TEXT], "wa:");
RichString_append(out, CRT_colors[CPU_IOWAIT], buffer);
sprintf(buffer, "%5.1f%% ", this->values[4]);
RichString_append(out, CRT_colors[METER_TEXT], "hi:");
RichString_append(out, CRT_colors[CPU_IRQ], buffer);
sprintf(buffer, "%5.1f%% ", this->values[4]);
RichString_append(out, CRT_colors[METER_TEXT], "si:");
RichString_append(out, CRT_colors[CPU_SOFTIRQ], buffer);
} else {
sprintf(buffer, "%5.1f%% ", this->values[2]);
RichString_append(out, CRT_colors[METER_TEXT], "sys:");
RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
sprintf(buffer, "%5.1f%% ", this->values[0]);
RichString_append(out, CRT_colors[METER_TEXT], "low:");
RichString_append(out, CRT_colors[CPU_NICE], buffer);
}
} }
void AllCPUsMeter_init(Meter* this) { void AllCPUsMeter_init(Meter* this) {

22
CRT.c
View File

@ -93,6 +93,9 @@ typedef enum ColorElements_ {
CPU_NORMAL, CPU_NORMAL,
CPU_KERNEL, CPU_KERNEL,
HELP_BOLD, HELP_BOLD,
CPU_IOWAIT,
CPU_IRQ,
CPU_SOFTIRQ,
LAST_COLORELEMENT LAST_COLORELEMENT
} ColorElements; } ColorElements;
@ -160,6 +163,7 @@ void CRT_done() {
int CRT_readKey() { int CRT_readKey() {
nocbreak(); nocbreak();
cbreak(); cbreak();
nodelay(stdscr, FALSE);
int ret = getch(); int ret = getch();
halfdelay(CRT_delay); halfdelay(CRT_delay);
return ret; return ret;
@ -250,6 +254,9 @@ void CRT_setColors(int colorScheme) {
CRT_colors[CHECK_BOX] = A_BOLD; CRT_colors[CHECK_BOX] = A_BOLD;
CRT_colors[CHECK_MARK] = A_NORMAL; CRT_colors[CHECK_MARK] = A_NORMAL;
CRT_colors[CHECK_TEXT] = A_NORMAL; CRT_colors[CHECK_TEXT] = A_NORMAL;
CRT_colors[CPU_IOWAIT] = A_BOLD;
CRT_colors[CPU_IRQ] = A_BOLD;
CRT_colors[CPU_SOFTIRQ] = A_BOLD;
} else if (CRT_colorScheme == COLORSCHEME_BLACKONWHITE) { } else if (CRT_colorScheme == COLORSCHEME_BLACKONWHITE) {
CRT_colors[RESET_COLOR] = ColorPair(Black,White); CRT_colors[RESET_COLOR] = ColorPair(Black,White);
CRT_colors[DEFAULT_COLOR] = ColorPair(Black,White); CRT_colors[DEFAULT_COLOR] = ColorPair(Black,White);
@ -302,6 +309,9 @@ void CRT_setColors(int colorScheme) {
CRT_colors[CHECK_BOX] = ColorPair(Blue,White); CRT_colors[CHECK_BOX] = ColorPair(Blue,White);
CRT_colors[CHECK_MARK] = ColorPair(Black,White); CRT_colors[CHECK_MARK] = ColorPair(Black,White);
CRT_colors[CHECK_TEXT] = ColorPair(Black,White); CRT_colors[CHECK_TEXT] = ColorPair(Black,White);
CRT_colors[CPU_IOWAIT] = ColorPair(Yellow,White);
CRT_colors[CPU_IRQ] = ColorPair(Blue,White);
CRT_colors[CPU_SOFTIRQ] = ColorPair(Blue,White);
} else if (CRT_colorScheme == COLORSCHEME_BLACKONWHITE2) { } else if (CRT_colorScheme == COLORSCHEME_BLACKONWHITE2) {
CRT_colors[RESET_COLOR] = ColorPair(Black,Black); CRT_colors[RESET_COLOR] = ColorPair(Black,Black);
CRT_colors[DEFAULT_COLOR] = ColorPair(Black,Black); CRT_colors[DEFAULT_COLOR] = ColorPair(Black,Black);
@ -354,6 +364,9 @@ void CRT_setColors(int colorScheme) {
CRT_colors[CHECK_BOX] = ColorPair(Blue,Black); CRT_colors[CHECK_BOX] = ColorPair(Blue,Black);
CRT_colors[CHECK_MARK] = ColorPair(Black,Black); CRT_colors[CHECK_MARK] = ColorPair(Black,Black);
CRT_colors[CHECK_TEXT] = ColorPair(Black,Black); CRT_colors[CHECK_TEXT] = ColorPair(Black,Black);
CRT_colors[CPU_IOWAIT] = ColorPair(Yellow,Black);
CRT_colors[CPU_IRQ] = A_BOLD | ColorPair(Blue,Black);
CRT_colors[CPU_SOFTIRQ] = ColorPair(Blue,Black);
} else if (CRT_colorScheme == COLORSCHEME_MIDNIGHT) { } else if (CRT_colorScheme == COLORSCHEME_MIDNIGHT) {
CRT_colors[RESET_COLOR] = ColorPair(White,Blue); CRT_colors[RESET_COLOR] = ColorPair(White,Blue);
CRT_colors[DEFAULT_COLOR] = ColorPair(White,Blue); CRT_colors[DEFAULT_COLOR] = ColorPair(White,Blue);
@ -406,6 +419,9 @@ void CRT_setColors(int colorScheme) {
CRT_colors[CHECK_BOX] = ColorPair(Cyan,Blue); CRT_colors[CHECK_BOX] = ColorPair(Cyan,Blue);
CRT_colors[CHECK_MARK] = A_BOLD | ColorPair(White,Blue); CRT_colors[CHECK_MARK] = A_BOLD | ColorPair(White,Blue);
CRT_colors[CHECK_TEXT] = A_NORMAL | ColorPair(White,Blue); CRT_colors[CHECK_TEXT] = A_NORMAL | ColorPair(White,Blue);
CRT_colors[CPU_IOWAIT] = A_BOLD | ColorPair(Yellow,Blue);
CRT_colors[CPU_IRQ] = A_BOLD | ColorPair(Black,Blue);
CRT_colors[CPU_SOFTIRQ] = ColorPair(Black,Blue);
} else if (CRT_colorScheme == COLORSCHEME_BLACKNIGHT) { } else if (CRT_colorScheme == COLORSCHEME_BLACKNIGHT) {
CRT_colors[RESET_COLOR] = ColorPair(Cyan,Black); CRT_colors[RESET_COLOR] = ColorPair(Cyan,Black);
CRT_colors[DEFAULT_COLOR] = ColorPair(Cyan,Black); CRT_colors[DEFAULT_COLOR] = ColorPair(Cyan,Black);
@ -458,6 +474,9 @@ void CRT_setColors(int colorScheme) {
CRT_colors[CHECK_BOX] = ColorPair(Green,Black); CRT_colors[CHECK_BOX] = ColorPair(Green,Black);
CRT_colors[CHECK_MARK] = A_BOLD | ColorPair(Green,Black); CRT_colors[CHECK_MARK] = A_BOLD | ColorPair(Green,Black);
CRT_colors[CHECK_TEXT] = ColorPair(Cyan,Black); CRT_colors[CHECK_TEXT] = ColorPair(Cyan,Black);
CRT_colors[CPU_IOWAIT] = ColorPair(Yellow,Black);
CRT_colors[CPU_IRQ] = A_BOLD | ColorPair(Blue,Black);
CRT_colors[CPU_SOFTIRQ] = ColorPair(Blue,Black);
} else { } else {
/* Default */ /* Default */
CRT_colors[RESET_COLOR] = ColorPair(White,Black); CRT_colors[RESET_COLOR] = ColorPair(White,Black);
@ -511,5 +530,8 @@ void CRT_setColors(int colorScheme) {
CRT_colors[CHECK_BOX] = ColorPair(Cyan,Black); CRT_colors[CHECK_BOX] = ColorPair(Cyan,Black);
CRT_colors[CHECK_MARK] = A_BOLD; CRT_colors[CHECK_MARK] = A_BOLD;
CRT_colors[CHECK_TEXT] = A_NORMAL; CRT_colors[CHECK_TEXT] = A_NORMAL;
CRT_colors[CPU_IOWAIT] = ColorPair(Cyan,Black);
CRT_colors[CPU_IRQ] = ColorPair(Yellow,Black);
CRT_colors[CPU_SOFTIRQ] = ColorPair(Magenta,Black);
} }
} }

3
CRT.h
View File

@ -95,6 +95,9 @@ typedef enum ColorElements_ {
CPU_NORMAL, CPU_NORMAL,
CPU_KERNEL, CPU_KERNEL,
HELP_BOLD, HELP_BOLD,
CPU_IOWAIT,
CPU_IRQ,
CPU_SOFTIRQ,
LAST_COLORELEMENT LAST_COLORELEMENT
} ColorElements; } ColorElements;

View File

@ -1,4 +1,31 @@
What's new in version 0.6.5
* Add hardened-debug flags for debugging with Hardened GCC
* BUGFIX: Handle error condition when a directory vanishes
from /proc
* BUGFIX: Fix leak of process command line
* BUGFIX: Collect orphaned items when arranging the tree view.
(thanks to Wolfram Schlich for assistance with debugging)
* Separate proc and memory debugging into separate #defines.
* BUGFIX: Fix message when configure fails due to
missing libraries
(thanks to Jon)
* BUGFIX: Don't truncate value when displaying a very large
process
(thanks to Bo Liu)
What's new in version 0.6.4
* Add an option to split the display of kernel time
in the CPU meter into system, IO-wait, IRQ and soft-IRQ.
(thanks to Philipp Richter)
* --sort-key flag in the command-line, overriding the
saved setting in .htoprc for the session.
(thanks to Rodolfo Borges)
* BUGFIX: Fixed string overflow on uptime display.
(thanks to Marc Cahalan)
What's new in version 0.6.3 What's new in version 0.6.3
* Performance improvements: uses much less CPU than the * Performance improvements: uses much less CPU than the

View File

@ -44,6 +44,15 @@ void ColumnsPanel_delete(Object* object) {
free(this); free(this);
} }
int ColumnsPanel_fieldNameToIndex(const char* name) {
for (int j = 1; j <= LAST_PROCESSFIELD; j++) {
if (String_eq(name, Process_fieldNames[j])) {
return j;
}
}
return 0;
}
void ColumnsPanel_update(Panel* super) { void ColumnsPanel_update(Panel* super) {
ColumnsPanel* this = (ColumnsPanel*) super; ColumnsPanel* this = (ColumnsPanel*) super;
int size = Panel_getSize(super); int size = Panel_getSize(super);
@ -53,12 +62,9 @@ void ColumnsPanel_update(Panel* super) {
this->settings->pl->fields = (ProcessField*) malloc(sizeof(ProcessField) * (size+1)); this->settings->pl->fields = (ProcessField*) malloc(sizeof(ProcessField) * (size+1));
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
char* text = ((ListItem*) Panel_get(super, i))->value; char* text = ((ListItem*) Panel_get(super, i))->value;
for (int j = 1; j <= LAST_PROCESSFIELD; j++) { int j = ColumnsPanel_fieldNameToIndex(text);
if (String_eq(text, Process_fieldNames[j])) { if (j > 0)
this->settings->pl->fields[i] = j; this->settings->pl->fields[i] = j;
break;
}
}
} }
this->settings->pl->fields[size] = 0; this->settings->pl->fields[size] = 0;
} }
@ -83,7 +89,7 @@ HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
case ']': case ']':
case '+': case '+':
{ {
if (selected < size - 2) if (selected < size - 2)
Panel_moveSelectedDown(super); Panel_moveSelectedDown(super);
result = HANDLED; result = HANDLED;
break; break;

View File

@ -24,6 +24,8 @@ ColumnsPanel* ColumnsPanel_new(Settings* settings, ScreenManager* scr);
void ColumnsPanel_delete(Object* object); void ColumnsPanel_delete(Object* object);
int ColumnsPanel_fieldNameToIndex(const char* name);
void ColumnsPanel_update(Panel* super); void ColumnsPanel_update(Panel* super);
HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch); HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch);

View File

@ -49,7 +49,11 @@ void DebugMemory_new() {
singleton->allocations = 0; singleton->allocations = 0;
singleton->deallocations = 0; singleton->deallocations = 0;
singleton->size = 0; singleton->size = 0;
#ifdef DEBUG_ALLOC
singleton->file = fopen("/tmp/htop-debug-alloc.txt", "w"); singleton->file = fopen("/tmp/htop-debug-alloc.txt", "w");
#else
singleton->file = NULL;
#endif
singleton->totals = true; singleton->totals = true;
//singleton->file = NULL; //singleton->file = NULL;
} }

View File

@ -38,6 +38,7 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
Panel_add(super, (Object*) CheckItem_new(String_copy("Highlight program \"basename\""), &(settings->pl->highlightBaseName))); Panel_add(super, (Object*) CheckItem_new(String_copy("Highlight program \"basename\""), &(settings->pl->highlightBaseName)));
Panel_add(super, (Object*) CheckItem_new(String_copy("Highlight megabytes in memory counters"), &(settings->pl->highlightMegabytes))); Panel_add(super, (Object*) CheckItem_new(String_copy("Highlight megabytes in memory counters"), &(settings->pl->highlightMegabytes)));
Panel_add(super, (Object*) CheckItem_new(String_copy("Leave a margin around header"), &(settings->header->margin))); Panel_add(super, (Object*) CheckItem_new(String_copy("Leave a margin around header"), &(settings->header->margin)));
Panel_add(super, (Object*) CheckItem_new(String_copy("Split System Time into System/IO-Wait/Hard-IRQ/Soft-IRQ"), &(settings->pl->expandSystemTime)));
return this; return this;
} }

View File

@ -9,6 +9,7 @@ in the source distribution for its full text.
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <assert.h>
#include "debug.h" #include "debug.h"
@ -31,6 +32,35 @@ struct Hashtable_ {
}; };
}*/ }*/
#ifdef DEBUG
bool Hashtable_isConsistent(Hashtable* this) {
int items = 0;
for (int i = 0; i < this->size; i++) {
HashtableItem* bucket = this->buckets[i];
while (bucket) {
items++;
bucket = bucket->next;
}
}
return items == this->items;
}
int Hashtable_count(Hashtable* this) {
int items = 0;
for (int i = 0; i < this->size; i++) {
HashtableItem* bucket = this->buckets[i];
while (bucket) {
items++;
bucket = bucket->next;
}
}
assert(items == this->items);
return items;
}
#endif
HashtableItem* HashtableItem_new(int key, void* value) { HashtableItem* HashtableItem_new(int key, void* value) {
HashtableItem* this; HashtableItem* this;
@ -45,13 +75,16 @@ Hashtable* Hashtable_new(int size, bool owner) {
Hashtable* this; Hashtable* this;
this = (Hashtable*) malloc(sizeof(Hashtable)); this = (Hashtable*) malloc(sizeof(Hashtable));
this->items = 0;
this->size = size; this->size = size;
this->buckets = (HashtableItem**) calloc(sizeof(HashtableItem*), size); this->buckets = (HashtableItem**) calloc(sizeof(HashtableItem*), size);
this->owner = owner; this->owner = owner;
assert(Hashtable_isConsistent(this));
return this; return this;
} }
void Hashtable_delete(Hashtable* this) { void Hashtable_delete(Hashtable* this) {
assert(Hashtable_isConsistent(this));
for (int i = 0; i < this->size; i++) { for (int i = 0; i < this->size; i++) {
HashtableItem* walk = this->buckets[i]; HashtableItem* walk = this->buckets[i];
while (walk != NULL) { while (walk != NULL) {
@ -67,6 +100,7 @@ void Hashtable_delete(Hashtable* this) {
} }
inline int Hashtable_size(Hashtable* this) { inline int Hashtable_size(Hashtable* this) {
assert(Hashtable_isConsistent(this));
return this->items; return this->items;
} }
@ -85,47 +119,53 @@ void Hashtable_put(Hashtable* this, int key, void* value) {
break; break;
} else } else
bucketPtr = &((*bucketPtr)->next); bucketPtr = &((*bucketPtr)->next);
assert(Hashtable_isConsistent(this));
} }
void* Hashtable_remove(Hashtable* this, int key) { void* Hashtable_remove(Hashtable* this, int key) {
int index = key % this->size; int index = key % this->size;
HashtableItem** bucketPtr = &(this->buckets[index]);
while (true) assert(Hashtable_isConsistent(this));
if (*bucketPtr == NULL) {
return NULL; HashtableItem** bucket;
break; for (bucket = &(this->buckets[index]); *bucket; bucket = &((*bucket)->next) ) {
} else if ((*bucketPtr)->key == key) { if ((*bucket)->key == key) {
void* savedValue = (*bucketPtr)->value; void* value = (*bucket)->value;
HashtableItem* savedNext = (*bucketPtr)->next; HashtableItem* next = (*bucket)->next;
free(*bucketPtr); free(*bucket);
(*bucketPtr) = savedNext; (*bucket) = next;
this->items--; this->items--;
if (this->owner) { if (this->owner) {
free(savedValue); free(value);
assert(Hashtable_isConsistent(this));
return NULL; return NULL;
} else { } else {
return savedValue; assert(Hashtable_isConsistent(this));
return value;
} }
} else }
bucketPtr = &((*bucketPtr)->next); }
assert(Hashtable_isConsistent(this));
return NULL;
} }
//#include <stdio.h>
inline void* Hashtable_get(Hashtable* this, int key) { inline void* Hashtable_get(Hashtable* this, int key) {
int index = key % this->size; int index = key % this->size;
HashtableItem* bucketPtr = this->buckets[index]; HashtableItem* bucketPtr = this->buckets[index];
// fprintf(stderr, "%d -> %d\n", key, index);
while (true) { while (true) {
if (bucketPtr == NULL) { if (bucketPtr == NULL) {
assert(Hashtable_isConsistent(this));
return NULL; return NULL;
} else if (bucketPtr->key == key) { } else if (bucketPtr->key == key) {
assert(Hashtable_isConsistent(this));
return bucketPtr->value; return bucketPtr->value;
} else } else
bucketPtr = bucketPtr->next; bucketPtr = bucketPtr->next;
// fprintf(stderr, "*\n");
} }
} }
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData) { void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData) {
assert(Hashtable_isConsistent(this));
for (int i = 0; i < this->size; i++) { for (int i = 0; i < this->size; i++) {
HashtableItem* walk = this->buckets[i]; HashtableItem* walk = this->buckets[i];
while (walk != NULL) { while (walk != NULL) {
@ -133,4 +173,5 @@ void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData
walk = walk->next; walk = walk->next;
} }
} }
assert(Hashtable_isConsistent(this));
} }

View File

@ -12,6 +12,7 @@ in the source distribution for its full text.
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <assert.h>
#include "debug.h" #include "debug.h"
@ -32,6 +33,14 @@ struct Hashtable_ {
bool owner; bool owner;
}; };
#ifdef DEBUG
bool Hashtable_isConsistent(Hashtable* this);
int Hashtable_count(Hashtable* this);
#endif
HashtableItem* HashtableItem_new(int key, void* value); HashtableItem* HashtableItem_new(int key, void* value);
Hashtable* Hashtable_new(int size, bool owner); Hashtable* Hashtable_new(int size, bool owner);
@ -43,7 +52,7 @@ inline int Hashtable_size(Hashtable* this);
void Hashtable_put(Hashtable* this, int key, void* value); void Hashtable_put(Hashtable* this, int key, void* value);
void* Hashtable_remove(Hashtable* this, int key); void* Hashtable_remove(Hashtable* this, int key);
//#include <stdio.h>
inline void* Hashtable_get(Hashtable* this, int key); inline void* Hashtable_get(Hashtable* this, int key);
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData); void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData);

View File

@ -32,7 +32,11 @@ profile:
$(MAKE) all CFLAGS="-pg -O2" $(MAKE) all CFLAGS="-pg -O2"
debug: debug:
$(MAKE) all CFLAGS="-g -DDEBUG" $(MAKE) all CFLAGS="-ggdb -DDEBUG"
hardened-debug:
$(MAKE) all CFLAGS="-ggdb -DDEBUG" LDFLAGS="-nopie"
debuglite: debuglite:
$(MAKE) all CFLAGS="-g -DDEBUGLITE" $(MAKE) all CFLAGS="-ggdb -DDEBUGLITE"

View File

@ -126,12 +126,14 @@ Process* Process_new(struct ProcessList_ *pl) {
Object_setClass(this, PROCESS_CLASS); Object_setClass(this, PROCESS_CLASS);
((Object*)this)->display = Process_display; ((Object*)this)->display = Process_display;
((Object*)this)->delete = Process_delete; ((Object*)this)->delete = Process_delete;
this->pid = 0;
this->pl = pl; this->pl = pl;
this->tag = false; this->tag = false;
this->updated = false; this->updated = false;
this->utime = 0; this->utime = 0;
this->stime = 0; this->stime = 0;
this->comm = NULL; this->comm = NULL;
this->indent = 0;
if (Process_getuid == -1) Process_getuid = getuid(); if (Process_getuid == -1) Process_getuid = getuid();
return this; return this;
} }
@ -139,13 +141,15 @@ Process* Process_new(struct ProcessList_ *pl) {
Process* Process_clone(Process* this) { Process* Process_clone(Process* this) {
Process* clone = malloc(sizeof(Process)); Process* clone = malloc(sizeof(Process));
memcpy(clone, this, sizeof(Process)); memcpy(clone, this, sizeof(Process));
this->comm = NULL;
this->pid = 0;
return clone; return clone;
} }
void Process_delete(Object* cast) { void Process_delete(Object* cast) {
Process* this = (Process*) cast; Process* this = (Process*) cast;
if (this->comm) free(this->comm);
assert (this != NULL); assert (this != NULL);
if (this->comm) free(this->comm);
free(this); free(this);
} }
@ -182,26 +186,26 @@ void Process_sendSignal(Process* this, int signal) {
#define ONE_M (ONE_K * ONE_K) #define ONE_M (ONE_K * ONE_K)
#define ONE_G (ONE_M * ONE_K) #define ONE_G (ONE_M * ONE_K)
static void Process_printLargeNumber(Process* this, RichString *str, unsigned int number) { static void Process_printLargeNumber(Process* this, RichString *str, unsigned long number) {
char buffer[11]; char buffer[11];
int len; int len;
if(number >= (1000 * ONE_M)) { if(number >= (1000 * ONE_M)) {
len = snprintf(buffer, 10, "%4.2fG ", (float)number / ONE_M); len = snprintf(buffer, 10, "%4.2fG ", (float)number / ONE_M);
RichString_appendn(str, CRT_colors[LARGE_NUMBER], buffer, len); RichString_appendn(str, CRT_colors[LARGE_NUMBER], buffer, len);
} else if(number >= (100000)) { } else if(number >= (100000)) {
len = snprintf(buffer, 10, "%4dM ", number / ONE_K); len = snprintf(buffer, 10, "%4ldM ", number / ONE_K);
int attr = this->pl->highlightMegabytes int attr = this->pl->highlightMegabytes
? CRT_colors[PROCESS_MEGABYTES] ? CRT_colors[PROCESS_MEGABYTES]
: CRT_colors[PROCESS]; : CRT_colors[PROCESS];
RichString_appendn(str, attr, buffer, len); RichString_appendn(str, attr, buffer, len);
} else if (this->pl->highlightMegabytes && number >= 1000) { } else if (this->pl->highlightMegabytes && number >= 1000) {
len = snprintf(buffer, 10, "%2d", number/1000); len = snprintf(buffer, 10, "%2ld", number/1000);
RichString_appendn(str, CRT_colors[PROCESS_MEGABYTES], buffer, len); RichString_appendn(str, CRT_colors[PROCESS_MEGABYTES], buffer, len);
number %= 1000; number %= 1000;
len = snprintf(buffer, 10, "%03d ", number); len = snprintf(buffer, 10, "%03ld ", number);
RichString_appendn(str, CRT_colors[PROCESS], buffer, len); RichString_appendn(str, CRT_colors[PROCESS], buffer, len);
} else { } else {
len = snprintf(buffer, 10, "%5d ", number); len = snprintf(buffer, 10, "%5ld ", number);
RichString_appendn(str, CRT_colors[PROCESS], buffer, len); RichString_appendn(str, CRT_colors[PROCESS], buffer, len);
} }
} }

View File

@ -52,11 +52,15 @@ in the source distribution for its full text.
#define MAX_READ 2048 #define MAX_READ 2048
#endif #endif
#ifndef PER_PROCESSOR_FIELDS
#define PER_PROCESSOR_FIELDS 20
#endif
}*/ }*/
/*{ /*{
#ifdef DEBUG #ifdef DEBUG_PROC
typedef int(*vxscanf)(void*, const char*, va_list); typedef int(*vxscanf)(void*, const char*, va_list);
#endif #endif
@ -71,16 +75,27 @@ typedef struct ProcessList_ {
int totalTasks; int totalTasks;
int runningTasks; int runningTasks;
// Must match number of PER_PROCESSOR_FIELDS constant
unsigned long long int* totalTime; unsigned long long int* totalTime;
unsigned long long int* userTime; unsigned long long int* userTime;
unsigned long long int* systemTime; unsigned long long int* systemTime;
unsigned long long int* systemAllTime;
unsigned long long int* idleTime; unsigned long long int* idleTime;
unsigned long long int* niceTime; unsigned long long int* niceTime;
unsigned long long int* ioWaitTime;
unsigned long long int* irqTime;
unsigned long long int* softIrqTime;
unsigned long long int* stealTime;
unsigned long long int* totalPeriod; unsigned long long int* totalPeriod;
unsigned long long int* userPeriod; unsigned long long int* userPeriod;
unsigned long long int* systemPeriod; unsigned long long int* systemPeriod;
unsigned long long int* systemAllPeriod;
unsigned long long int* idlePeriod; unsigned long long int* idlePeriod;
unsigned long long int* nicePeriod; unsigned long long int* nicePeriod;
unsigned long long int* ioWaitPeriod;
unsigned long long int* irqPeriod;
unsigned long long int* softIrqPeriod;
unsigned long long int* stealPeriod;
unsigned long long int totalMem; unsigned long long int totalMem;
unsigned long long int usedMem; unsigned long long int usedMem;
@ -102,7 +117,8 @@ typedef struct ProcessList_ {
bool treeView; bool treeView;
bool highlightBaseName; bool highlightBaseName;
bool highlightMegabytes; bool highlightMegabytes;
#ifdef DEBUG bool expandSystemTime;
#ifdef DEBUG_PROC
FILE* traceFile; FILE* traceFile;
#endif #endif
@ -111,7 +127,7 @@ typedef struct ProcessList_ {
static ProcessField defaultHeaders[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 }; static ProcessField defaultHeaders[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
#ifdef DEBUG #ifdef DEBUG_PROC
#define ProcessList_read(this, buffer, format, ...) ProcessList_xread(this, (vxscanf) vsscanf, buffer, format, ## __VA_ARGS__ ) #define ProcessList_read(this, buffer, format, ...) ProcessList_xread(this, (vxscanf) vsscanf, buffer, format, ## __VA_ARGS__ )
#define ProcessList_fread(this, file, format, ...) ProcessList_xread(this, (vxscanf) vfscanf, file, format, ## __VA_ARGS__ ) #define ProcessList_fread(this, file, format, ...) ProcessList_xread(this, (vxscanf) vfscanf, file, format, ## __VA_ARGS__ )
@ -173,18 +189,29 @@ static inline int ProcessList_xread(ProcessList* this, vxscanf fn, void* buffer,
#endif #endif
static inline void ProcessList_allocatePerProcessorBuffers(ProcessList* this, int procs) {
unsigned long long int** bufferPtr = &(this->totalTime);
unsigned long long int* buffer = calloc(procs * PER_PROCESSOR_FIELDS, sizeof(unsigned long long int));
for (int i = 0; i < PER_PROCESSOR_FIELDS; i++) {
*bufferPtr = buffer;
bufferPtr++;
buffer += procs;
}
}
ProcessList* ProcessList_new(UsersTable* usersTable) { ProcessList* ProcessList_new(UsersTable* usersTable) {
ProcessList* this; ProcessList* this;
this = malloc(sizeof(ProcessList)); this = malloc(sizeof(ProcessList));
this->processes = Vector_new(PROCESS_CLASS, true, DEFAULT_SIZE, Process_compare); this->processes = Vector_new(PROCESS_CLASS, true, DEFAULT_SIZE, Process_compare);
this->processTable = Hashtable_new(70, false); this->processTable = Hashtable_new(70, false);
assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
this->prototype = Process_new(this); this->prototype = Process_new(this);
this->usersTable = usersTable; this->usersTable = usersTable;
/* tree-view auxiliary buffers */ /* tree-view auxiliary buffers */
this->processes2 = Vector_new(PROCESS_CLASS, true, DEFAULT_SIZE, Process_compare); this->processes2 = Vector_new(PROCESS_CLASS, true, DEFAULT_SIZE, Process_compare);
#ifdef DEBUG #ifdef DEBUG_PROC
this->traceFile = fopen("/tmp/htop-proc-trace", "w"); this->traceFile = fopen("/tmp/htop-proc-trace", "w");
#endif #endif
@ -198,16 +225,9 @@ ProcessList* ProcessList_new(UsersTable* usersTable) {
} while (String_startsWith(buffer, "cpu")); } while (String_startsWith(buffer, "cpu"));
fclose(status); fclose(status);
this->processorCount = procs - 1; this->processorCount = procs - 1;
this->totalTime = calloc(procs, sizeof(long long int));
this->userTime = calloc(procs, sizeof(long long int)); ProcessList_allocatePerProcessorBuffers(this, procs);
this->systemTime = calloc(procs, sizeof(long long int));
this->niceTime = calloc(procs, sizeof(long long int));
this->idleTime = calloc(procs, sizeof(long long int));
this->totalPeriod = calloc(procs, sizeof(long long int));
this->userPeriod = calloc(procs, sizeof(long long int));
this->systemPeriod = calloc(procs, sizeof(long long int));
this->nicePeriod = calloc(procs, sizeof(long long int));
this->idlePeriod = calloc(procs, sizeof(long long int));
for (int i = 0; i < procs; i++) { for (int i = 0; i < procs; i++) {
this->totalTime[i] = 1; this->totalTime[i] = 1;
this->totalPeriod[i] = 1; this->totalPeriod[i] = 1;
@ -228,6 +248,7 @@ ProcessList* ProcessList_new(UsersTable* usersTable) {
this->treeView = false; this->treeView = false;
this->highlightBaseName = false; this->highlightBaseName = false;
this->highlightMegabytes = false; this->highlightMegabytes = false;
this->expandSystemTime = false;
return this; return this;
} }
@ -238,18 +259,11 @@ void ProcessList_delete(ProcessList* this) {
Vector_delete(this->processes2); Vector_delete(this->processes2);
Process_delete((Object*)this->prototype); Process_delete((Object*)this->prototype);
// Free first entry only;
// other fields are offsets of the same buffer
free(this->totalTime); free(this->totalTime);
free(this->userTime);
free(this->systemTime);
free(this->niceTime);
free(this->idleTime);
free(this->totalPeriod);
free(this->userPeriod);
free(this->systemPeriod);
free(this->nicePeriod);
free(this->idlePeriod);
#ifdef DEBUG #ifdef DEBUG_PROC
fclose(this->traceFile); fclose(this->traceFile);
#endif #endif
@ -284,14 +298,26 @@ void ProcessList_prune(ProcessList* this) {
} }
void ProcessList_add(ProcessList* this, Process* p) { void ProcessList_add(ProcessList* this, Process* p) {
assert(Vector_indexOf(this->processes, p, Process_pidCompare) == -1);
assert(Hashtable_get(this->processTable, p->pid) == NULL);
Vector_add(this->processes, p); Vector_add(this->processes, p);
Hashtable_put(this->processTable, p->pid, p); Hashtable_put(this->processTable, p->pid, p);
assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1);
assert(Hashtable_get(this->processTable, p->pid) != NULL);
assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
} }
void ProcessList_remove(ProcessList* this, Process* p) { void ProcessList_remove(ProcessList* this, Process* p) {
Hashtable_remove(this->processTable, p->pid); assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1);
assert(Hashtable_get(this->processTable, p->pid) != NULL);
Process* pp = Hashtable_remove(this->processTable, p->pid);
assert(pp == p); (void)pp;
int pid = p->pid;
int index = Vector_indexOf(this->processes, p, Process_pidCompare); int index = Vector_indexOf(this->processes, p, Process_pidCompare);
assert(index != -1);
Vector_remove(this->processes, index); Vector_remove(this->processes, index);
assert(Hashtable_get(this->processTable, pid) == NULL); (void)pid;
assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
} }
Process* ProcessList_get(ProcessList* this, int index) { Process* ProcessList_get(ProcessList* this, int index) {
@ -305,21 +331,22 @@ int ProcessList_size(ProcessList* this) {
static void ProcessList_buildTree(ProcessList* this, int pid, int level, int indent, int direction) { static void ProcessList_buildTree(ProcessList* this, int pid, int level, int indent, int direction) {
Vector* children = Vector_new(PROCESS_CLASS, false, DEFAULT_SIZE, Process_compare); Vector* children = Vector_new(PROCESS_CLASS, false, DEFAULT_SIZE, Process_compare);
for (int i = 0; i < Vector_size(this->processes); i++) { for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
Process* process = (Process*) (Vector_get(this->processes, i)); Process* process = (Process*) (Vector_get(this->processes, i));
if (process->ppid == pid) { if (process->ppid == pid) {
Process* process = (Process*) (Vector_take(this->processes, i)); Process* process = (Process*) (Vector_take(this->processes, i));
Vector_add(children, process); Vector_add(children, process);
i--;
} }
} }
int size = Vector_size(children); int size = Vector_size(children);
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
Process* process = (Process*) (Vector_get(children, i)); Process* process = (Process*) (Vector_get(children, i));
int s = this->processes2->items;
if (direction == 1) if (direction == 1)
Vector_add(this->processes2, process); Vector_add(this->processes2, process);
else else
Vector_insert(this->processes2, 0, process); Vector_insert(this->processes2, 0, process);
assert(this->processes2->items == s+1); (void)s;
int nextIndent = indent; int nextIndent = indent;
if (i < size - 1) if (i < size - 1)
nextIndent = indent | (1 << level); nextIndent = indent | (1 << level);
@ -340,11 +367,19 @@ void ProcessList_sort(ProcessList* this) {
Vector_sort(this->processes); Vector_sort(this->processes);
this->sortKey = sortKey; this->sortKey = sortKey;
this->direction = direction; this->direction = direction;
int vsize = Vector_size(this->processes);
Process* init = (Process*) (Vector_take(this->processes, 0)); Process* init = (Process*) (Vector_take(this->processes, 0));
assert(init->pid == 1); assert(init->pid == 1);
init->indent = 0; init->indent = 0;
Vector_add(this->processes2, init); Vector_add(this->processes2, init);
ProcessList_buildTree(this, init->pid, 0, 0, direction); ProcessList_buildTree(this, init->pid, 0, 0, direction);
while (Vector_size(this->processes)) {
Process* p = (Process*) (Vector_take(this->processes, 0));
p->indent = 0;
Vector_add(this->processes2, p);
}
assert(Vector_size(this->processes2) == vsize); (void)vsize;
assert(Vector_size(this->processes) == 0);
Vector* t = this->processes; Vector* t = this->processes;
this->processes = this->processes2; this->processes = this->processes2;
this->processes2 = t; this->processes2 = t;
@ -358,7 +393,7 @@ static int ProcessList_readStatFile(ProcessList* this, Process *proc, FILE *f, c
int size = fread(buf, 1, MAX_READ, f); int size = fread(buf, 1, MAX_READ, f);
if(!size) return 0; if(!size) return 0;
proc->pid = atoi(buf); assert(proc->pid == atoi(buf));
char *location = strchr(buf, ' '); char *location = strchr(buf, ' ');
if(!location) return 0; if(!location) return 0;
@ -371,7 +406,7 @@ static int ProcessList_readStatFile(ProcessList* this, Process *proc, FILE *f, c
command[commsize] = '\0'; command[commsize] = '\0';
location = end + 2; location = end + 2;
#ifdef DEBUG #ifdef DEBUG_PROC
int num = ProcessList_read(this, location, int num = ProcessList_read(this, location,
"%c %d %d %d %d %d %lu %lu %lu %lu " "%c %d %d %d %d %d %lu %lu %lu %lu "
"%lu %lu %lu %ld %ld %ld %ld %ld %ld " "%lu %lu %lu %ld %ld %ld %ld %ld %ld "
@ -464,7 +499,7 @@ void ProcessList_processEntries(ProcessList* this, char* dirname, int parent, fl
Process* prototype = this->prototype; Process* prototype = this->prototype;
dir = opendir(dirname); dir = opendir(dirname);
assert(dir != NULL); if (!dir) return;
while ((entry = readdir(dir)) != NULL) { while ((entry = readdir(dir)) != NULL) {
char* name = entry->d_name; char* name = entry->d_name;
int pid; int pid;
@ -495,14 +530,17 @@ void ProcessList_processEntries(ProcessList* this, char* dirname, int parent, fl
char statusfilename[MAX_NAME+1]; char statusfilename[MAX_NAME+1];
char command[PROCESS_COMM_LEN + 1]; char command[PROCESS_COMM_LEN + 1];
Process* process; Process* process = NULL;
assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
Process* existingProcess = (Process*) Hashtable_get(this->processTable, pid); Process* existingProcess = (Process*) Hashtable_get(this->processTable, pid);
if (existingProcess) { if (existingProcess) {
assert(Vector_indexOf(this->processes, existingProcess, Process_pidCompare) != -1);
process = existingProcess; process = existingProcess;
assert(process->pid == pid);
} else { } else {
process = prototype; process = prototype;
process->comm = NULL; assert(process->comm == NULL);
process->pid = pid; process->pid = pid;
if (! ProcessList_readStatusFile(this, process, dirname, name)) if (! ProcessList_readStatusFile(this, process, dirname, name))
goto errorReadingProcess; goto errorReadingProcess;
@ -574,29 +612,28 @@ void ProcessList_processEntries(ProcessList* this, char* dirname, int parent, fl
} }
if (!existingProcess) { if (!existingProcess) {
process = Process_clone(process); ProcessList_add(this, Process_clone(process));
ProcessList_add(this, process);
} }
continue; continue;
// Exception handler. // Exception handler.
errorReadingProcess: { errorReadingProcess: {
if (process->comm) {
free(process->comm);
process->comm = NULL;
}
if (existingProcess) if (existingProcess)
ProcessList_remove(this, process); ProcessList_remove(this, process);
else { assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
if (process->comm)
free(process->comm);
}
} }
} }
} }
prototype->comm = NULL;
closedir(dir); closedir(dir);
} }
void ProcessList_scan(ProcessList* this) { void ProcessList_scan(ProcessList* this) {
unsigned long long int usertime, nicetime, systemtime, idletime, totaltime; unsigned long long int usertime, nicetime, systemtime, systemalltime, idletime, totaltime;
unsigned long long int swapFree; unsigned long long int swapFree;
FILE* status; FILE* status;
@ -656,22 +693,37 @@ void ProcessList_scan(ProcessList* this) {
} }
// Fields existing on kernels >= 2.6 // Fields existing on kernels >= 2.6
// (and RHEL's patched kernel 2.4...) // (and RHEL's patched kernel 2.4...)
systemtime += ioWait + irq + softIrq + steal; systemalltime = systemtime + ioWait + irq + softIrq + steal;
totaltime = usertime + nicetime + systemtime + idletime; totaltime = usertime + nicetime + systemalltime + idletime;
assert (usertime >= this->userTime[i]); assert (usertime >= this->userTime[i]);
assert (nicetime >= this->niceTime[i]); assert (nicetime >= this->niceTime[i]);
assert (systemtime >= this->systemTime[i]); assert (systemtime >= this->systemTime[i]);
assert (idletime >= this->idleTime[i]); assert (idletime >= this->idleTime[i]);
assert (totaltime >= this->totalTime[i]); assert (totaltime >= this->totalTime[i]);
assert (systemalltime >= this->systemAllTime[i]);
assert (ioWait >= this->ioWaitTime[i]);
assert (irq >= this->irqTime[i]);
assert (softIrq >= this->softIrqTime[i]);
assert (steal >= this->stealTime[i]);
this->userPeriod[i] = usertime - this->userTime[i]; this->userPeriod[i] = usertime - this->userTime[i];
this->nicePeriod[i] = nicetime - this->niceTime[i]; this->nicePeriod[i] = nicetime - this->niceTime[i];
this->systemPeriod[i] = systemtime - this->systemTime[i]; this->systemPeriod[i] = systemtime - this->systemTime[i];
this->systemAllPeriod[i] = systemalltime - this->systemAllTime[i];
this->idlePeriod[i] = idletime - this->idleTime[i]; this->idlePeriod[i] = idletime - this->idleTime[i];
this->ioWaitPeriod[i] = ioWait - this->ioWaitTime[i];
this->irqPeriod[i] = irq - this->irqTime[i];
this->softIrqPeriod[i] = softIrq - this->softIrqTime[i];
this->stealPeriod[i] = steal - this->stealTime[i];
this->totalPeriod[i] = totaltime - this->totalTime[i]; this->totalPeriod[i] = totaltime - this->totalTime[i];
this->userTime[i] = usertime; this->userTime[i] = usertime;
this->niceTime[i] = nicetime; this->niceTime[i] = nicetime;
this->systemTime[i] = systemtime; this->systemTime[i] = systemtime;
this->systemAllTime[i] = systemalltime;
this->idleTime[i] = idletime; this->idleTime[i] = idletime;
this->ioWaitTime[i] = ioWait;
this->irqTime[i] = irq;
this->softIrqTime[i] = softIrq;
this->stealTime[i] = steal;
this->totalTime[i] = totaltime; this->totalTime[i] = totaltime;
} }
float period = (float)this->totalPeriod[0] / this->processorCount; float period = (float)this->totalPeriod[0] / this->processorCount;

View File

@ -54,9 +54,13 @@ in the source distribution for its full text.
#define MAX_READ 2048 #define MAX_READ 2048
#endif #endif
#ifndef PER_PROCESSOR_FIELDS
#define PER_PROCESSOR_FIELDS 20
#endif
#ifdef DEBUG
#ifdef DEBUG_PROC
typedef int(*vxscanf)(void*, const char*, va_list); typedef int(*vxscanf)(void*, const char*, va_list);
#endif #endif
@ -71,16 +75,27 @@ typedef struct ProcessList_ {
int totalTasks; int totalTasks;
int runningTasks; int runningTasks;
// Must match number of PER_PROCESSOR_FIELDS constant
unsigned long long int* totalTime; unsigned long long int* totalTime;
unsigned long long int* userTime; unsigned long long int* userTime;
unsigned long long int* systemTime; unsigned long long int* systemTime;
unsigned long long int* systemAllTime;
unsigned long long int* idleTime; unsigned long long int* idleTime;
unsigned long long int* niceTime; unsigned long long int* niceTime;
unsigned long long int* ioWaitTime;
unsigned long long int* irqTime;
unsigned long long int* softIrqTime;
unsigned long long int* stealTime;
unsigned long long int* totalPeriod; unsigned long long int* totalPeriod;
unsigned long long int* userPeriod; unsigned long long int* userPeriod;
unsigned long long int* systemPeriod; unsigned long long int* systemPeriod;
unsigned long long int* systemAllPeriod;
unsigned long long int* idlePeriod; unsigned long long int* idlePeriod;
unsigned long long int* nicePeriod; unsigned long long int* nicePeriod;
unsigned long long int* ioWaitPeriod;
unsigned long long int* irqPeriod;
unsigned long long int* softIrqPeriod;
unsigned long long int* stealPeriod;
unsigned long long int totalMem; unsigned long long int totalMem;
unsigned long long int usedMem; unsigned long long int usedMem;
@ -102,13 +117,14 @@ typedef struct ProcessList_ {
bool treeView; bool treeView;
bool highlightBaseName; bool highlightBaseName;
bool highlightMegabytes; bool highlightMegabytes;
#ifdef DEBUG bool expandSystemTime;
#ifdef DEBUG_PROC
FILE* traceFile; FILE* traceFile;
#endif #endif
} ProcessList; } ProcessList;
#ifdef DEBUG #ifdef DEBUG_PROC
#define ProcessList_read(this, buffer, format, ...) ProcessList_xread(this, (vxscanf) vsscanf, buffer, format, ## __VA_ARGS__ ) #define ProcessList_read(this, buffer, format, ...) ProcessList_xread(this, (vxscanf) vsscanf, buffer, format, ## __VA_ARGS__ )
#define ProcessList_fread(this, file, format, ...) ProcessList_xread(this, (vxscanf) vfscanf, file, format, ## __VA_ARGS__ ) #define ProcessList_fread(this, file, format, ...) ProcessList_xread(this, (vxscanf) vfscanf, file, format, ## __VA_ARGS__ )

View File

@ -139,6 +139,8 @@ bool Settings_read(Settings* this, char* fileName) {
this->pl->highlightMegabytes = atoi(option[1]); this->pl->highlightMegabytes = atoi(option[1]);
} else if (String_eq(option[0], "header_margin")) { } else if (String_eq(option[0], "header_margin")) {
this->header->margin = atoi(option[1]); this->header->margin = atoi(option[1]);
} else if (String_eq(option[0], "expand_system_time")) {
this->pl->expandSystemTime = atoi(option[1]);
} else if (String_eq(option[0], "delay")) { } else if (String_eq(option[0], "delay")) {
this->delay = atoi(option[1]); this->delay = atoi(option[1]);
} else if (String_eq(option[0], "color_scheme")) { } else if (String_eq(option[0], "color_scheme")) {
@ -195,6 +197,7 @@ bool Settings_write(Settings* this) {
fprintf(fd, "highlight_megabytes=%d\n", (int) this->pl->highlightMegabytes); fprintf(fd, "highlight_megabytes=%d\n", (int) this->pl->highlightMegabytes);
fprintf(fd, "tree_view=%d\n", (int) this->pl->treeView); fprintf(fd, "tree_view=%d\n", (int) this->pl->treeView);
fprintf(fd, "header_margin=%d\n", (int) this->header->margin); fprintf(fd, "header_margin=%d\n", (int) this->header->margin);
fprintf(fd, "expand_system_time=%d\n", (int) this->pl->expandSystemTime);
fprintf(fd, "color_scheme=%d\n", (int) this->colorScheme); fprintf(fd, "color_scheme=%d\n", (int) this->colorScheme);
fprintf(fd, "delay=%d\n", (int) this->delay); fprintf(fd, "delay=%d\n", (int) this->delay);
fprintf(fd, "left_meters="); fprintf(fd, "left_meters=");

View File

@ -96,7 +96,7 @@ void String_printPointer(void* p) {
printf("%p", p); printf("%p", p);
} }
inline int String_eq(char* s1, char* s2) { inline int String_eq(const char* s1, const char* s2) {
if (s1 == NULL || s2 == NULL) { if (s1 == NULL || s2 == NULL) {
if (s1 == NULL && s2 == NULL) if (s1 == NULL && s2 == NULL)
return 1; return 1;

View File

@ -39,7 +39,7 @@ void String_printInt(int i);
void String_printPointer(void* p); void String_printPointer(void* p);
inline int String_eq(char* s1, char* s2); inline int String_eq(const char* s1, const char* s2);
char** String_split(char* s, char sep); char** String_split(char* s, char sep);

View File

@ -165,4 +165,5 @@ void TraceScreen_run(TraceScreen* this) {
kill(child, SIGTERM); kill(child, SIGTERM);
waitpid(child, NULL, 0); waitpid(child, NULL, 0);
fclose(strace); fclose(strace);
CRT_enableDelay();
} }

View File

@ -44,7 +44,7 @@ void UptimeMeter_setValues(Meter* this, char* buffer, int len) {
if (days > this->total) { if (days > this->total) {
this->total = days; this->total = days;
} }
char daysbuf[10]; char daysbuf[15];
if (days > 100) { if (days > 100) {
sprintf(daysbuf, "%d days(!), ", days); sprintf(daysbuf, "%d days(!), ", days);
} else if (days > 1) { } else if (days > 1) {

View File

@ -63,6 +63,7 @@ void Vector_delete(Vector* this) {
#ifdef DEBUG #ifdef DEBUG
static inline bool Vector_isConsistent(Vector* this) { static inline bool Vector_isConsistent(Vector* this) {
assert(this->items <= this->arraySize);
if (this->owner) { if (this->owner) {
for (int i = 0; i < this->items; i++) for (int i = 0; i < this->items; i++)
if (this->array[i] && this->array[i]->class != this->vectorType) if (this->array[i] && this->array[i]->class != this->vectorType)
@ -73,6 +74,16 @@ static inline bool Vector_isConsistent(Vector* this) {
} }
} }
int Vector_count(Vector* this) {
int items = 0;
for (int i = 0; i < this->items; i++) {
if (this->array[i])
items++;
}
assert(items == this->items);
return items;
}
#endif #endif
void Vector_prune(Vector* this) { void Vector_prune(Vector* this) {
@ -222,8 +233,9 @@ void Vector_add(Vector* this, void* data_) {
assert(data_ && ((Object*)data_)->class == this->vectorType); assert(data_ && ((Object*)data_)->class == this->vectorType);
Object* data = data_; Object* data = data_;
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
int i = this->items;
Vector_set(this, this->items, data); Vector_set(this, this->items, data);
assert(this->items == i+1); (void)(i);
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
} }

View File

@ -41,6 +41,8 @@ void Vector_delete(Vector* this);
#ifdef DEBUG #ifdef DEBUG
int Vector_count(Vector* this);
#endif #endif
void Vector_prune(Vector* this); void Vector_prune(Vector* this);

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.57) AC_PREREQ(2.57)
AC_INIT([htop],[0.6.3],[loderunner@users.sourceforge.net]) AC_INIT([htop],[0.6.5],[loderunner@users.sourceforge.net])
AM_INIT_AUTOMAKE AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([htop.c]) AC_CONFIG_SRCDIR([htop.c])
AC_CONFIG_HEADER([config.h]) AC_CONFIG_HEADER([config.h])
@ -15,7 +15,7 @@ AC_CHECK_LIB([ncurses], [refresh], [], [missing_libraries="$missing_libraries li
AC_CHECK_LIB([m], [ceil], [], [missing_libraries="$missing_libraries libm"]) AC_CHECK_LIB([m], [ceil], [], [missing_libraries="$missing_libraries libm"])
if test ! -z "$missing_libraries"; then if test ! -z "$missing_libraries"; then
AC_MSG_ERROR([missing libraries:$missing_headers]) AC_MSG_ERROR([missing libraries: $missing_libraries])
fi fi
# Checks for header files. # Checks for header files.
@ -26,7 +26,7 @@ AC_CHECK_HEADERS([stdlib.h string.h strings.h sys/param.h sys/time.h unistd.h cu
]) ])
if test ! -z "$missing_headers"; then if test ! -z "$missing_headers"; then
AC_MSG_ERROR([missing headers:$missing_headers]) AC_MSG_ERROR([missing headers: $missing_headers])
fi fi
# Checks for typedefs, structures, and compiler characteristics. # Checks for typedefs, structures, and compiler characteristics.

2
htop.1
View File

@ -1,4 +1,4 @@
.TH "htop" "1" "0.6.3" "Bartosz Fenski <fenio@o2.pl>" "Utils" .TH "htop" "1" "0.6.5" "Bartosz Fenski <fenio@o2.pl>" "Utils"
.SH "NAME" .SH "NAME"
htop \- interactive process viewer htop \- interactive process viewer
.SH "SYNTAX" .SH "SYNTAX"

99
htop.c
View File

@ -46,12 +46,13 @@ void printHelpFlag() {
printf("Released under the GNU GPL.\n\n"); printf("Released under the GNU GPL.\n\n");
printf("-d DELAY Delay between updates, in tenths of seconds\n\n"); printf("-d DELAY Delay between updates, in tenths of seconds\n\n");
printf("-u USERNAME Show only processes of a given user\n\n"); printf("-u USERNAME Show only processes of a given user\n\n");
printf("--sort-key COLUMN Sort by this column (use --sort-key help for a column list)\n\n");
printf("Press F1 inside htop for online help.\n"); printf("Press F1 inside htop for online help.\n");
printf("See the man page for full information.\n\n"); printf("See the man page for full information.\n\n");
exit(0); exit(0);
} }
void showHelp() { void showHelp(ProcessList* pl) {
clear(); clear();
attrset(CRT_colors[HELP_BOLD]); attrset(CRT_colors[HELP_BOLD]);
mvaddstr(0, 0, "htop " VERSION " - (C) 2004-2006 Hisham Muhammad."); mvaddstr(0, 0, "htop " VERSION " - (C) 2004-2006 Hisham Muhammad.");
@ -61,10 +62,20 @@ void showHelp() {
mvaddstr(3, 0, "CPU usage bar: "); mvaddstr(3, 0, "CPU usage bar: ");
#define addattrstr(a,s) attrset(a);addstr(s) #define addattrstr(a,s) attrset(a);addstr(s)
addattrstr(CRT_colors[BAR_BORDER], "["); addattrstr(CRT_colors[BAR_BORDER], "[");
addattrstr(CRT_colors[CPU_NICE], "low-priority"); addstr("/"); if (pl->expandSystemTime) {
addattrstr(CRT_colors[CPU_NORMAL], "normal"); addstr("/"); addattrstr(CRT_colors[CPU_NICE], "low"); addstr("/");
addattrstr(CRT_colors[CPU_KERNEL], "kernel"); addattrstr(CRT_colors[CPU_NORMAL], "normal"); addstr("/");
addattrstr(CRT_colors[BAR_SHADOW], " used%"); addattrstr(CRT_colors[CPU_KERNEL], "kernel"); addstr("/");
addattrstr(CRT_colors[CPU_IOWAIT], "io-wait"); addstr("/");
addattrstr(CRT_colors[CPU_IRQ], "irq"); addstr("/");
addattrstr(CRT_colors[CPU_SOFTIRQ], "soft-irq");
addattrstr(CRT_colors[BAR_SHADOW], " used%");
} else {
addattrstr(CRT_colors[CPU_NICE], "low-priority"); addstr("/");
addattrstr(CRT_colors[CPU_NORMAL], "normal"); addstr("/");
addattrstr(CRT_colors[CPU_KERNEL], "kernel");
addattrstr(CRT_colors[BAR_SHADOW], " used%");
}
addattrstr(CRT_colors[BAR_BORDER], "]"); addattrstr(CRT_colors[BAR_BORDER], "]");
attrset(CRT_colors[DEFAULT_COLOR]); attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(4, 0, "Memory bar: "); mvaddstr(4, 0, "Memory bar: ");
@ -72,45 +83,46 @@ void showHelp() {
addattrstr(CRT_colors[MEMORY_USED], "used"); addstr("/"); addattrstr(CRT_colors[MEMORY_USED], "used"); addstr("/");
addattrstr(CRT_colors[MEMORY_BUFFERS], "buffers"); addstr("/"); addattrstr(CRT_colors[MEMORY_BUFFERS], "buffers"); addstr("/");
addattrstr(CRT_colors[MEMORY_CACHE], "cache"); addattrstr(CRT_colors[MEMORY_CACHE], "cache");
addattrstr(CRT_colors[BAR_SHADOW], " used/total"); addattrstr(CRT_colors[BAR_SHADOW], " used/total");
addattrstr(CRT_colors[BAR_BORDER], "]"); addattrstr(CRT_colors[BAR_BORDER], "]");
attrset(CRT_colors[DEFAULT_COLOR]); attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(5, 0, "Swap bar: "); mvaddstr(5, 0, "Swap bar: ");
addattrstr(CRT_colors[BAR_BORDER], "["); addattrstr(CRT_colors[BAR_BORDER], "[");
addattrstr(CRT_colors[SWAP], "used"); addattrstr(CRT_colors[SWAP], "used");
addattrstr(CRT_colors[BAR_SHADOW], " used/total"); addattrstr(CRT_colors[BAR_SHADOW], " used/total");
addattrstr(CRT_colors[BAR_BORDER], "]"); addattrstr(CRT_colors[BAR_BORDER], "]");
attrset(CRT_colors[DEFAULT_COLOR]); attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(6,0, "Type and layout of header meters is configurable in the setup screen."); mvaddstr(6,0, "Type and layout of header meters are configurable in the setup screen.");
mvaddstr(7, 0, "Status: R: running; S: sleeping; T: traced/stopped; Z: zombie; D: disk sleep");
mvaddstr( 8, 0, " Arrows: scroll process list F5 t: tree view"); mvaddstr( 9, 0, " Arrows: scroll process list F5 t: tree view");
mvaddstr( 9, 0, " Digits: incremental PID search u: show processes of a single user"); mvaddstr(10, 0, " Digits: incremental PID search u: show processes of a single user");
mvaddstr(10, 0, " F3 /: incremental name search H: hide/show user threads"); mvaddstr(11, 0, " F3 /: incremental name search H: hide/show user threads");
mvaddstr(11, 0, " K: hide/show kernel threads"); mvaddstr(12, 0, " K: hide/show kernel threads");
mvaddstr(12, 0, " Space: tag processes F: cursor follows process"); mvaddstr(13, 0, " Space: tag processes F: cursor follows process");
mvaddstr(13, 0, " U: untag all processes"); mvaddstr(14, 0, " U: untag all processes");
mvaddstr(14, 0, " F9 k: kill process/tagged processes P: sort by CPU%"); mvaddstr(15, 0, " F9 k: kill process/tagged processes P: sort by CPU%");
mvaddstr(15, 0, " + [ F7: lower priority (+ nice) M: sort by MEM%"); mvaddstr(16, 0, " + [ F7: lower priority (+ nice) M: sort by MEM%");
mvaddstr(16, 0, " - ] F8: higher priority (root only) T: sort by TIME"); mvaddstr(17, 0, " - ] F8: higher priority (root only) T: sort by TIME");
mvaddstr(17, 0, " F4 I: invert sort order"); mvaddstr(18, 0, " F4 I: invert sort order");
mvaddstr(18, 0, " F2 S: setup F6 >: select sort column"); mvaddstr(19, 0, " F2 S: setup F6 >: select sort column");
mvaddstr(19, 0, " F1 h: show this help screen"); mvaddstr(20, 0, " F1 h: show this help screen");
mvaddstr(20, 0, " F10 q: quit s: trace syscalls with strace"); mvaddstr(21, 0, " F10 q: quit s: trace syscalls with strace");
attrset(CRT_colors[HELP_BOLD]); attrset(CRT_colors[HELP_BOLD]);
mvaddstr( 8, 0, " Arrows"); mvaddstr( 8,40, " F5 t"); mvaddstr( 9, 0, " Arrows"); mvaddstr( 9,40, " F5 t");
mvaddstr( 9, 0, " Digits"); mvaddstr( 9,40, " u"); mvaddstr(10, 0, " Digits"); mvaddstr(10,40, " u");
mvaddstr(10, 0, " F3 /"); mvaddstr(10,40, " H"); mvaddstr(11, 0, " F3 /"); mvaddstr(11,40, " H");
mvaddstr(11,40, " K"); mvaddstr(12,40, " K");
mvaddstr(12, 0, " Space"); mvaddstr(12,40, " F"); mvaddstr(13, 0, " Space"); mvaddstr(13,40, " F");
mvaddstr(13, 0, " U"); mvaddstr(14, 0, " U");
mvaddstr(14, 0, " F9 k"); mvaddstr(14,40, " P"); mvaddstr(15, 0, " F9 k"); mvaddstr(15,40, " P");
mvaddstr(15, 0, " + [ F7"); mvaddstr(15,40, " M"); mvaddstr(16, 0, " + [ F7"); mvaddstr(16,40, " M");
mvaddstr(16, 0, " - ] F8"); mvaddstr(16,40, " T"); mvaddstr(17, 0, " - ] F8"); mvaddstr(17,40, " T");
mvaddstr(17,40, " F4 I"); mvaddstr(18,40, " F4 I");
mvaddstr(18, 0, " F2 S"); mvaddstr(18,40, " F6 >"); mvaddstr(19, 0, " F2 S"); mvaddstr(19,40, " F6 >");
mvaddstr(19, 0, " F1 h"); mvaddstr(20, 0, " F1 h");
mvaddstr(20, 0, " F10 q"); mvaddstr(20,40, " s"); mvaddstr(21, 0, " F10 q"); mvaddstr(21,40, " s");
attrset(CRT_colors[DEFAULT_COLOR]); attrset(CRT_colors[DEFAULT_COLOR]);
attrset(CRT_colors[HELP_BOLD]); attrset(CRT_colors[HELP_BOLD]);
@ -194,12 +206,25 @@ int main(int argc, char** argv) {
int delay = -1; int delay = -1;
bool userOnly = false; bool userOnly = false;
uid_t userId = 0; uid_t userId = 0;
int sortKey = 0;
if (argc > 0) { if (argc > 0) {
if (String_eq(argv[1], "--help")) { if (String_eq(argv[1], "--help")) {
printHelpFlag(); printHelpFlag();
} else if (String_eq(argv[1], "--version")) { } else if (String_eq(argv[1], "--version")) {
printVersionFlag(); printVersionFlag();
} else if (String_eq(argv[1], "--sort-key")) {
if (argc < 2) printHelpFlag();
if (String_eq(argv[2], "help")) {
for (int j = 1; j < LAST_PROCESSFIELD; j++)
printf ("%s\n", Process_fieldNames[j]);
exit(0);
}
sortKey = ColumnsPanel_fieldNameToIndex(argv[2]);
if (sortKey == -1) {
fprintf(stderr, "Error: invalid column \"%s\".\n", argv[2]);
exit(1);
}
} else if (String_eq(argv[1], "-d")) { } else if (String_eq(argv[1], "-d")) {
if (argc < 2) printHelpFlag(); if (argc < 2) printHelpFlag();
sscanf(argv[2], "%d", &delay); sscanf(argv[2], "%d", &delay);
@ -237,6 +262,10 @@ int main(int argc, char** argv) {
Header* header = Header_new(pl); Header* header = Header_new(pl);
settings = Settings_new(pl, header); settings = Settings_new(pl, header);
if (sortKey > 0) {
pl->sortKey = sortKey;
pl->treeView = false;
}
int headerHeight = Header_calculateHeight(header); int headerHeight = Header_calculateHeight(header);
// FIXME: move delay code to settings // FIXME: move delay code to settings
@ -455,7 +484,7 @@ int main(int argc, char** argv) {
case KEY_F(1): case KEY_F(1):
case 'h': case 'h':
{ {
showHelp(); showHelp(pl);
FunctionBar_draw(defaultBar, NULL); FunctionBar_draw(defaultBar, NULL);
refreshTimeout = 0; refreshTimeout = 0;
break; break;

View File

@ -1,6 +1,6 @@
[Desktop Entry] [Desktop Entry]
Encoding=UTF-8 Encoding=UTF-8
Version=0.6.3 Version=0.6.5
Name=Htop Name=Htop
Type=Application Type=Application
Comment=Show System Processes Comment=Show System Processes