Remove arbitrary limit from rich strings

Fix subtree hiding
Fix reading of CPU values in hidden threads
Fix hiding of zombie processes as kernel threads
Remove "debug proc" code
Code cleanup in processElements
This commit is contained in:
Hisham Muhammad 2010-11-22 12:40:20 +00:00
parent 25551d44c1
commit d8e1480a27
15 changed files with 535 additions and 594 deletions

View File

@ -75,7 +75,7 @@ static void CPUMeter_setValues(Meter* this, char* buffer, int size) {
static void CPUMeter_display(Object* cast, RichString* out) {
char buffer[50];
Meter* this = (Meter*)cast;
RichString_init(out);
RichString_prune(out);
if (this->param > this->pl->cpuCount) {
RichString_append(out, CRT_colors[METER_TEXT], "absent");
return;

View File

@ -36,9 +36,8 @@ static void LoadAverageMeter_setValues(Meter* this, char* buffer, int size) {
static void LoadAverageMeter_display(Object* cast, RichString* out) {
Meter* this = (Meter*)cast;
char buffer[20];
RichString_init(out);
sprintf(buffer, "%.2f ", this->values[2]);
RichString_append(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer);
RichString_write(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer);
sprintf(buffer, "%.2f ", this->values[1]);
RichString_append(out, CRT_colors[LOAD_AVERAGE_FIVE], buffer);
sprintf(buffer, "%.2f ", this->values[0]);
@ -57,9 +56,8 @@ static void LoadMeter_setValues(Meter* this, char* buffer, int size) {
static void LoadMeter_display(Object* cast, RichString* out) {
Meter* this = (Meter*)cast;
char buffer[20];
RichString_init(out);
sprintf(buffer, "%.2f ", ((Meter*)this)->values[0]);
RichString_append(out, CRT_colors[LOAD], buffer);
RichString_write(out, CRT_colors[LOAD], buffer);
}
MeterType LoadAverageMeter = {

View File

@ -43,8 +43,7 @@ static void MemoryMeter_display(Object* cast, RichString* out) {
long int usedMem = this->values[0] / k;
long int buffersMem = this->values[1] / k;
long int cachedMem = this->values[2] / k;
RichString_init(out);
RichString_append(out, CRT_colors[METER_TEXT], ":");
RichString_write(out, CRT_colors[METER_TEXT], ":");
sprintf(buffer, format, totalMem);
RichString_append(out, CRT_colors[METER_VALUE], buffer);
sprintf(buffer, format, usedMem);

24
Meter.c
View File

@ -128,8 +128,6 @@ MeterType* Meter_types[] = {
NULL
};
static RichString Meter_stringBuffer;
Meter* Meter_new(ProcessList* pl, int param, MeterType* type) {
Meter* this = calloc(sizeof(Meter), 1);
Object_setClass(this, METER_CLASS);
@ -166,14 +164,13 @@ void Meter_setCaption(Meter* this, const char* caption) {
this->caption = strdup(caption);
}
static inline void Meter_displayToStringBuffer(Meter* this, char* buffer) {
static inline void Meter_displayBuffer(Meter* this, char* buffer, RichString* out) {
MeterType* type = this->type;
Object_Display display = ((Object*)this)->display;
if (display) {
display((Object*)this, &Meter_stringBuffer);
display((Object*)this, out);
} else {
RichString_initVal(Meter_stringBuffer);
RichString_append(&Meter_stringBuffer, CRT_colors[type->attributes[0]], buffer);
RichString_write(out, CRT_colors[type->attributes[0]], buffer);
}
}
@ -229,10 +226,12 @@ static void TextMeterMode_draw(Meter* this, int x, int y, int w) {
int captionLen = strlen(this->caption);
w -= captionLen;
x += captionLen;
Meter_displayToStringBuffer(this, buffer);
mvhline(y, x, ' ', CRT_colors[DEFAULT_COLOR]);
attrset(CRT_colors[RESET_COLOR]);
RichString_printVal(Meter_stringBuffer, y, x);
RichString_begin(out);
Meter_displayBuffer(this, buffer, &out);
RichString_printVal(out, y, x);
RichString_end(out);
}
/* ---------- BarMeterMode ---------- */
@ -379,13 +378,15 @@ static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
char buffer[METER_BUFFER_LEN];
type->setValues(this, buffer, METER_BUFFER_LEN - 1);
Meter_displayToStringBuffer(this, buffer);
RichString_begin(out);
Meter_displayBuffer(this, buffer, &out);
attrset(CRT_colors[LED_COLOR]);
mvaddstr(y+2, x, this->caption);
int xx = x + strlen(this->caption);
for (int i = 0; i < Meter_stringBuffer.len; i++) {
char c = RichString_getCharVal(Meter_stringBuffer, i);
int len = RichString_sizeVal(out);
for (int i = 0; i < len; i++) {
char c = RichString_getCharVal(out, i);
if (c >= '0' && c <= '9') {
LEDMeterMode_drawDigit(xx, y, c-48);
xx += 4;
@ -395,6 +396,7 @@ static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
}
}
attrset(CRT_colors[RESET_COLOR]);
RichString_end(out);
}
#endif

62
Panel.c
View File

@ -98,7 +98,7 @@ void Panel_init(Panel* this, int x, int y, int w, int h, char* type, bool owner)
this->selected = 0;
this->oldSelected = 0;
this->needsRedraw = true;
RichString_prune(&(this->header));
RichString_beginAllocated(this->header);
if (String_eq(CRT_termType, "linux"))
this->scrollHAmount = 20;
else
@ -108,17 +108,19 @@ void Panel_init(Panel* this, int x, int y, int w, int h, char* type, bool owner)
void Panel_done(Panel* this) {
assert (this != NULL);
Vector_delete(this->items);
RichString_end(this->header);
}
inline void Panel_setRichHeader(Panel* this, RichString header) {
RichString* Panel_getHeader(Panel* this) {
assert (this != NULL);
this->header = header;
this->needsRedraw = true;
return &(this->header);
}
inline void Panel_setHeader(Panel* this, const char* header) {
Panel_setRichHeader(this, RichString_quickString(CRT_colors[PANEL_HEADER_FOCUS], header));
RichString_write(&(this->header), CRT_colors[PANEL_HEADER_FOCUS], header);
this->needsRedraw = true;
}
void Panel_setEventHandler(Panel* this, Panel_EventHandler eh) {
@ -136,7 +138,7 @@ void Panel_move(Panel* this, int x, int y) {
void Panel_resize(Panel* this, int w, int h) {
assert (this != NULL);
if (this->header.len > 0)
if (RichString_sizeVal(this->header) > 0)
h--;
this->w = w;
this->h = h;
@ -262,15 +264,16 @@ void Panel_draw(Panel* this, bool focus) {
assert(first >= 0);
assert(last <= itemCount);
if (this->header.len > 0) {
int headerLen = RichString_sizeVal(this->header);
if (headerLen > 0) {
int attr = focus
? CRT_colors[PANEL_HEADER_FOCUS]
: CRT_colors[PANEL_HEADER_UNFOCUS];
attrset(attr);
mvhline(y, x, ' ', this->w);
if (scrollH < this->header.len) {
if (scrollH < headerLen) {
RichString_printoffnVal(this->header, y, x, scrollH,
MIN(this->header.len - scrollH, this->w));
MIN(headerLen - scrollH, this->w));
}
attrset(CRT_colors[RESET_COLOR]);
y++;
@ -284,22 +287,23 @@ void Panel_draw(Panel* this, bool focus) {
for(int i = first, j = 0; j < this->h && i < last; i++, j++) {
Object* itemObj = Vector_get(this->items, i);
RichString itemRef;
RichString_initVal(itemRef);
itemObj->display(itemObj, &itemRef);
int amt = MIN(itemRef.len - scrollH, this->w);
RichString_begin(item);
itemObj->display(itemObj, &item);
int itemLen = RichString_sizeVal(item);
int amt = MIN(itemLen - scrollH, this->w);
if (i == this->selected) {
attrset(highlight);
RichString_setAttr(&itemRef, highlight);
RichString_setAttr(&item, highlight);
mvhline(y + j, x+0, ' ', this->w);
if (amt > 0)
RichString_printoffnVal(itemRef, y+j, x+0, scrollH, amt);
RichString_printoffnVal(item, y+j, x+0, scrollH, amt);
attrset(CRT_colors[RESET_COLOR]);
} else {
mvhline(y+j, x+0, ' ', this->w);
if (amt > 0)
RichString_printoffnVal(itemRef, y+j, x+0, scrollH, amt);
RichString_printoffnVal(item, y+j, x+0, scrollH, amt);
}
RichString_end(item);
}
for (int i = y + (last - first); i < y + this->h; i++)
mvhline(i, x+0, ' ', this->w);
@ -307,24 +311,26 @@ void Panel_draw(Panel* this, bool focus) {
} else {
Object* oldObj = Vector_get(this->items, this->oldSelected);
RichString oldRef;
RichString_initVal(oldRef);
oldObj->display(oldObj, &oldRef);
RichString_begin(old);
oldObj->display(oldObj, &old);
int oldLen = RichString_sizeVal(old);
Object* newObj = Vector_get(this->items, this->selected);
RichString newRef;
RichString_initVal(newRef);
newObj->display(newObj, &newRef);
RichString_begin(new);
newObj->display(newObj, &new);
int newLen = RichString_sizeVal(new);
mvhline(y+ this->oldSelected - this->scrollV, x+0, ' ', this->w);
if (scrollH < oldRef.len)
RichString_printoffnVal(oldRef, y+this->oldSelected - this->scrollV, x,
this->scrollH, MIN(oldRef.len - scrollH, this->w));
if (scrollH < oldLen)
RichString_printoffnVal(old, y+this->oldSelected - this->scrollV, x,
this->scrollH, MIN(oldLen - scrollH, this->w));
attrset(highlight);
mvhline(y+this->selected - this->scrollV, x+0, ' ', this->w);
RichString_setAttr(&newRef, highlight);
if (scrollH < newRef.len)
RichString_printoffnVal(newRef, y+this->selected - this->scrollV, x,
this->scrollH, MIN(newRef.len - scrollH, this->w));
RichString_setAttr(&new, highlight);
if (scrollH < newLen)
RichString_printoffnVal(new, y+this->selected - this->scrollV, x,
this->scrollH, MIN(newLen - scrollH, this->w));
attrset(CRT_colors[RESET_COLOR]);
RichString_end(new);
RichString_end(old);
}
this->oldSelected = this->selected;
move(0, 0);

View File

@ -78,7 +78,7 @@ void Panel_init(Panel* this, int x, int y, int w, int h, char* type, bool owner)
void Panel_done(Panel* this);
extern void Panel_setRichHeader(Panel* this, RichString header);
RichString* Panel_getHeader(Panel* this);
extern void Panel_setHeader(Panel* this, const char* header);

View File

@ -40,12 +40,18 @@ in the source distribution for its full text.
#endif
#define PAGE_SIZE_KB ( PAGE_SIZE / ONE_K )
#define PROCESS_COMM_LEN 300
/*{
#ifndef Process_isKernelThread
#define Process_isKernelThread(_process) (_process->pgrp == 0)
#endif
#ifndef Process_isUserlandThread
#define Process_isUserlandThread(_process) (_process->pid != _process->tgid)
#endif
#ifndef Process_isThread
#define Process_isThread(_process) (_process->pid != _process->tgid || _process->m_size == 0)
#define Process_isThread(_process) (Process_isUserlandThread(_process) || Process_isKernelThread(_process))
#endif
typedef enum ProcessField_ {
@ -83,6 +89,7 @@ typedef struct Process_ {
char state;
bool tag;
bool showChildren;
bool show;
pid_t ppid;
unsigned int pgrp;
unsigned int session;
@ -279,10 +286,10 @@ static void Process_printTime(RichString* str, unsigned long t) {
}
static inline void Process_writeCommand(Process* this, int attr, int baseattr, RichString* str) {
int start = str->len;
int start = RichString_size(str);
RichString_append(str, attr, this->comm);
if (this->pl->highlightBaseName) {
int finish = str->len - 1;
int finish = RichString_size(str) - 1;
int space = RichString_findChar(str, ' ', start);
if (space != -1)
finish = space - 1;
@ -312,10 +319,10 @@ static inline void Process_outputRate(Process* this, RichString* str, int attr,
}
static void Process_writeField(Process* this, RichString* str, ProcessField field) {
char buffer[PROCESS_COMM_LEN];
char buffer[128]; buffer[127] = '\0';
int attr = CRT_colors[DEFAULT_COLOR];
int baseattr = CRT_colors[PROCESS_BASENAME];
int n = PROCESS_COMM_LEN;
int n = sizeof(buffer) - 1;
switch (field) {
case PID: snprintf(buffer, n, "%5u ", this->pid); break;
@ -457,7 +464,7 @@ static void Process_writeField(Process* this, RichString* str, ProcessField fiel
static void Process_display(Object* cast, RichString* out) {
Process* this = (Process*) cast;
ProcessField* fields = this->pl->fields;
RichString_init(out);
RichString_prune(out);
for (int i = 0; fields[i]; i++)
Process_writeField(this, out, fields[i]);
if (this->pl->shadowOtherUsers && (int)this->st_uid != Process_getuid)
@ -486,6 +493,7 @@ Process* Process_new(struct ProcessList_ *pl) {
this->pl = pl;
this->tag = false;
this->showChildren = true;
this->show = true;
this->updated = false;
this->utime = 0;
this->stime = 0;

View File

@ -43,11 +43,17 @@ in the source distribution for its full text.
#endif
#define PAGE_SIZE_KB ( PAGE_SIZE / ONE_K )
#define PROCESS_COMM_LEN 300
#ifndef Process_isKernelThread
#define Process_isKernelThread(_process) (_process->pgrp == 0)
#endif
#ifndef Process_isUserlandThread
#define Process_isUserlandThread(_process) (_process->pid != _process->tgid)
#endif
#ifndef Process_isThread
#define Process_isThread(_process) (_process->pid != _process->tgid || _process->m_size == 0)
#define Process_isThread(_process) (Process_isUserlandThread(_process) || Process_isKernelThread(_process))
#endif
typedef enum ProcessField_ {
@ -85,6 +91,7 @@ typedef struct Process_ {
char state;
bool tag;
bool showChildren;
bool show;
pid_t ppid;
unsigned int pgrp;
unsigned int session;

View File

@ -58,10 +58,6 @@ in the source distribution for its full text.
/*{
#ifdef DEBUG_PROC
typedef int(*vxscanf)(void*, const char*, va_list);
#endif
typedef struct CPUData_ {
unsigned long long int totalTime;
unsigned long long int userTime;
@ -126,77 +122,12 @@ typedef struct ProcessList_ {
bool highlightMegabytes;
bool highlightThreads;
bool detailedCPUTime;
#ifdef DEBUG_PROC
FILE* traceFile;
#endif
} ProcessList;
}*/
static ProcessField defaultHeaders[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
#ifdef DEBUG_PROC
#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__ )
static FILE* ProcessList_fopen(ProcessList* this, const char* path, const char* mode) {
fprintf(this->traceFile, "[%s]\n", path);
return fopen(path, mode);
}
static inline int ProcessList_xread(ProcessList* this, vxscanf fn, void* buffer, char* format, ...) {
va_list ap;
va_start(ap, format);
int num = fn(buffer, format, ap);
va_end(format);
va_start(ap, format);
while (*format) {
char ch = *format;
char* c; int* d;
long int* ld; unsigned long int* lu;
long long int* lld; unsigned long long int* llu;
char** s;
if (ch != '%') {
fprintf(this->traceFile, "%c", ch);
format++;
continue;
}
format++;
switch(*format) {
case 'c': c = va_arg(ap, char*); fprintf(this->traceFile, "%c", *c); break;
case 'd': d = va_arg(ap, int*); fprintf(this->traceFile, "%d", *d); break;
case 's': s = va_arg(ap, char**); fprintf(this->traceFile, "%s", *s); break;
case 'l':
format++;
switch (*format) {
case 'd': ld = va_arg(ap, long int*); fprintf(this->traceFile, "%ld", *ld); break;
case 'u': lu = va_arg(ap, unsigned long int*); fprintf(this->traceFile, "%lu", *lu); break;
case 'l':
format++;
switch (*format) {
case 'd': lld = va_arg(ap, long long int*); fprintf(this->traceFile, "%lld", *lld); break;
case 'u': llu = va_arg(ap, unsigned long long int*); fprintf(this->traceFile, "%llu", *llu); break;
}
}
}
format++;
}
fprintf(this->traceFile, "\n");
va_end(format);
return num;
}
#else
#ifndef ProcessList_read
#define ProcessList_fopen(this, path, mode) fopen(path, mode)
#define ProcessList_read(this, buffer, format, ...) sscanf(buffer, format, ## __VA_ARGS__ )
#define ProcessList_fread(this, file, format, ...) fscanf(file, format, ## __VA_ARGS__ )
#endif
#endif
ProcessList* ProcessList_new(UsersTable* usersTable) {
ProcessList* this;
this = malloc(sizeof(ProcessList));
@ -208,19 +139,15 @@ ProcessList* ProcessList_new(UsersTable* usersTable) {
/* tree-view auxiliary buffers */
this->processes2 = Vector_new(PROCESS_CLASS, true, DEFAULT_SIZE, Process_compare);
#ifdef DEBUG_PROC
this->traceFile = fopen("/tmp/htop-proc-trace", "w");
#endif
FILE* status = fopen(PROCSTATFILE, "r");
assert(status != NULL);
FILE* file = fopen(PROCSTATFILE, "r");
assert(file != NULL);
char buffer[256];
int cpus = -1;
do {
cpus++;
fgets(buffer, 255, status);
fgets(buffer, 255, file);
} while (String_startsWith(buffer, "cpu"));
fclose(status);
fclose(file);
this->cpuCount = cpus - 1;
this->cpus = calloc(sizeof(CPUData), cpus);
@ -240,8 +167,8 @@ ProcessList* ProcessList_new(UsersTable* usersTable) {
this->direction = 1;
this->hideThreads = false;
this->shadowOtherUsers = false;
this->showThreadNames = true;
this->showingThreadNames = true;
this->showThreadNames = false;
this->showingThreadNames = false;
this->hideKernelThreads = false;
this->hideUserlandThreads = false;
this->treeView = false;
@ -256,13 +183,7 @@ void ProcessList_delete(ProcessList* this) {
Hashtable_delete(this->processTable);
Vector_delete(this->processes);
Vector_delete(this->processes2);
free(this->cpus);
#ifdef DEBUG_PROC
fclose(this->traceFile);
#endif
free(this->fields);
free(this);
}
@ -274,18 +195,16 @@ void ProcessList_invertSortOrder(ProcessList* this) {
this->direction = 1;
}
RichString ProcessList_printHeader(ProcessList* this) {
RichString out;
RichString_initVal(out);
void ProcessList_printHeader(ProcessList* this, RichString* header) {
RichString_prune(header);
ProcessField* fields = this->fields;
for (int i = 0; fields[i]; i++) {
const char* field = Process_fieldTitles[fields[i]];
if (this->sortKey == fields[i])
RichString_append(&out, CRT_colors[PANEL_HIGHLIGHT_FOCUS], field);
RichString_append(header, CRT_colors[PANEL_HIGHLIGHT_FOCUS], field);
else
RichString_append(&out, CRT_colors[PANEL_HEADER_FOCUS], field);
RichString_append(header, CRT_colors[PANEL_HEADER_FOCUS], field);
}
return out;
}
static void ProcessList_add(ProcessList* this, Process* p) {
@ -334,21 +253,18 @@ static void ProcessList_buildTree(ProcessList* this, pid_t pid, int level, int i
int size = Vector_size(children);
for (int i = 0; i < size; i++) {
Process* process = (Process*) (Vector_get(children, i));
if (show) {
if (!show)
process->show = false;
show = show ? process->showChildren : false;
int s = this->processes2->items;
if (direction == 1)
Vector_add(this->processes2, process);
else
Vector_insert(this->processes2, 0, process);
assert(this->processes2->items == s+1); (void)s;
int nextIndent = indent;
if (i < size - 1)
nextIndent = indent | (1 << level);
ProcessList_buildTree(this, process->pid, level+1, nextIndent, direction, process->showChildren);
process->indent = indent | (1 << level);
} else {
ProcessList_remove(this, process);
}
int nextIndent = indent | (1 << level);
ProcessList_buildTree(this, process->pid, level+1, (i < size - 1) ? nextIndent : indent, direction, show);
process->indent = nextIndent;
}
Vector_delete(children);
}
@ -393,164 +309,262 @@ void ProcessList_sort(ProcessList* this) {
}
}
static int ProcessList_readStatFile(Process *proc, FILE *f, char *command) {
static bool ProcessList_readStatFile(Process *process, const char* dirname, const char* name, char* command) {
char filename[MAX_NAME+1];
snprintf(filename, MAX_NAME, "%s/%s/stat", dirname, name);
FILE* file = fopen(filename, "r");
if (!file)
return false;
static char buf[MAX_READ];
unsigned long int zero;
int size = fread(buf, 1, MAX_READ, f);
if(!size) return 0;
int size = fread(buf, 1, MAX_READ, file);
if (!size) { fclose(file); return false; }
assert(proc->pid == atoi(buf));
assert(process->pid == atoi(buf));
char *location = strchr(buf, ' ');
if(!location) return 0;
if (!location) { fclose(file); return false; }
location += 2;
char *end = strrchr(location, ')');
if(!end) return 0;
if (!end) { fclose(file); return false; }
int commsize = end - location;
memcpy(command, location, commsize);
command[commsize] = '\0';
location = end + 2;
#ifdef DEBUG_PROC
int num = ProcessList_read(this, location,
"%c %u %u %u %u %d %lu %lu %lu %lu "
"%lu %lu %lu %ld %ld %ld %ld %ld %ld "
"%lu %lu %ld %lu %lu %lu %lu %lu "
"%lu %lu %lu %lu %lu %lu %lu %lu "
int num = sscanf(location,
"%c %d %u %u %u "
"%d %lu "
"%*u %*u %*u %*u "
"%lu %lu %ld %ld "
"%ld %ld %ld "
"%*d %*u %*u %*d %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u "
"%d %d",
&proc->state, &proc->ppid, &proc->pgrp, &proc->session, &proc->tty_nr,
&proc->tpgid, &proc->flags,
&proc->minflt, &proc->cminflt, &proc->majflt, &proc->cmajflt,
&proc->utime, &proc->stime, &proc->cutime, &proc->cstime,
&proc->priority, &proc->nice, &proc->nlwp, &proc->itrealvalue,
&zero, &proc->vsize, &proc->rss, &proc->rlim,
&proc->startcode, &proc->endcode, &proc->startstack, &proc->kstkesp,
&proc->kstkeip, &proc->signal, &proc->blocked, &proc->sigignore,
&proc->sigcatch, &proc->wchan, &proc->nswap, &proc->cnswap,
&proc->exit_signal, &proc->processor);
#else
long int uzero;
int num = ProcessList_read(this, location,
"%c %d %u %u %u %d %lu %lu %lu %lu "
"%lu %lu %lu %ld %ld %ld %ld %ld %ld "
"%lu %lu %ld %lu %lu %lu %lu %lu "
"%lu %lu %lu %lu %lu %lu %lu %lu "
"%d %d",
&proc->state, &proc->ppid, &proc->pgrp, &proc->session, &proc->tty_nr,
&proc->tpgid, &proc->flags,
&zero, &zero, &zero, &zero,
&proc->utime, &proc->stime, &proc->cutime, &proc->cstime,
&proc->priority, &proc->nice, &proc->nlwp, &uzero,
&zero, &zero, &uzero, &zero,
&zero, &zero, &zero, &zero,
&zero, &zero, &zero, &zero,
&zero, &zero, &zero, &zero,
&proc->exit_signal, &proc->processor);
#endif
// This assert is always valid on 2.4, but reportedly not always valid on 2.6.
// TODO: Check if the semantics of this field has changed.
// assert(zero == 0);
if(num != 37) return 0;
return 1;
&process->state, &process->ppid, &process->pgrp, &process->session, &process->tty_nr,
&process->tpgid, &process->flags,
&process->utime, &process->stime, &process->cutime, &process->cstime,
&process->priority, &process->nice, &process->nlwp,
&process->exit_signal, &process->processor);
fclose(file);
return (num == 16);
}
static bool ProcessList_readStatusFile(Process* proc, const char* dirname, char* name) {
char statusfilename[MAX_NAME+1];
statusfilename[MAX_NAME] = '\0';
static bool ProcessList_statProcessDir(Process* process, const char* dirname, char* name) {
char filename[MAX_NAME+1];
filename[MAX_NAME] = '\0';
snprintf(statusfilename, MAX_NAME, "%s/%s", dirname, name);
snprintf(filename, MAX_NAME, "%s/%s", dirname, name);
struct stat sstat;
int statok = stat(statusfilename, &sstat);
int statok = stat(filename, &sstat);
if (statok == -1)
return false;
proc->st_uid = sstat.st_uid;
process->st_uid = sstat.st_uid;
struct tm date;
time_t ctime = sstat.st_ctime;
proc->starttime_ctime = ctime;
process->starttime_ctime = ctime;
(void) localtime_r((time_t*) &ctime, &date);
strftime(proc->starttime_show, 7, ((ctime > time(NULL) - 86400) ? "%R " : "%b%d "), &date);
strftime(process->starttime_show, 7, ((ctime > time(NULL) - 86400) ? "%R " : "%b%d "), &date);
return true;
}
#ifdef HAVE_TASKSTATS
static void ProcessList_readIoFile(Process* proc, const char* dirname, char* name) {
char iofilename[MAX_NAME+1];
iofilename[MAX_NAME] = '\0';
static void ProcessList_readIoFile(Process* process, const char* dirname, char* name) {
char filename[MAX_NAME+1];
filename[MAX_NAME] = '\0';
snprintf(filename, MAX_NAME, "%s/%s/io", dirname, name);
FILE* file = fopen(filename, "r");
if (!file)
return;
snprintf(iofilename, MAX_NAME, "%s/%s/io", dirname, name);
FILE* io = ProcessList_fopen(this, iofilename, "r");
if (io) {
char buffer[256];
buffer[255] = '\0';
struct timeval tv;
gettimeofday(&tv,NULL);
unsigned long long now = tv.tv_sec*1000+tv.tv_usec/1000;
unsigned long long last_read = proc->io_read_bytes;
unsigned long long last_write = proc->io_write_bytes;
while (fgets(buffer, 255, io)) {
if (ProcessList_read(this, buffer, "rchar: %llu", &proc->io_rchar)) continue;
if (ProcessList_read(this, buffer, "wchar: %llu", &proc->io_wchar)) continue;
if (ProcessList_read(this, buffer, "syscr: %llu", &proc->io_syscr)) continue;
if (ProcessList_read(this, buffer, "syscw: %llu", &proc->io_syscw)) continue;
if (ProcessList_read(this, buffer, "read_bytes: %llu", &proc->io_read_bytes)) {
proc->io_rate_read_bps =
((double)(proc->io_read_bytes - last_read))/(((double)(now - proc->io_rate_read_time))/1000);
proc->io_rate_read_time = now;
unsigned long long last_read = process->io_read_bytes;
unsigned long long last_write = process->io_write_bytes;
while (fgets(buffer, 255, file)) {
if (sscanf(buffer, "rchar: %llu", &process->io_rchar)) continue;
if (sscanf(buffer, "wchar: %llu", &process->io_wchar)) continue;
if (sscanf(buffer, "syscr: %llu", &process->io_syscr)) continue;
if (sscanf(buffer, "syscw: %llu", &process->io_syscw)) continue;
if (sscanf(buffer, "read_bytes: %llu", &process->io_read_bytes)) {
process->io_rate_read_bps =
((double)(process->io_read_bytes - last_read))/(((double)(now - process->io_rate_read_time))/1000);
process->io_rate_read_time = now;
continue;
}
if (ProcessList_read(this, buffer, "write_bytes: %llu", &proc->io_write_bytes)) {
proc->io_rate_write_bps =
((double)(proc->io_write_bytes - last_write))/(((double)(now - proc->io_rate_write_time))/1000);
proc->io_rate_write_time = now;
if (sscanf(buffer, "write_bytes: %llu", &process->io_write_bytes)) {
process->io_rate_write_bps =
((double)(process->io_write_bytes - last_write))/(((double)(now - process->io_rate_write_time))/1000);
process->io_rate_write_time = now;
continue;
}
ProcessList_read(this, buffer, "cancelled_write_bytes: %llu", &proc->io_cancelled_write_bytes);
}
fclose(io);
sscanf(buffer, "cancelled_write_bytes: %llu", &process->io_cancelled_write_bytes);
}
fclose(file);
}
#endif
static bool ProcessList_processEntries(ProcessList* this, const char* dirname, Process* parent, pid_t parentPid, float period) {
static bool ProcessList_readStatmFile(Process* process, const char* dirname, const char* name) {
char filename[MAX_NAME+1];
snprintf(filename, MAX_NAME, "%s/%s/statm", dirname, name);
FILE* file = fopen(filename, "r");
if (!file)
return false;
int num = fscanf(file, "%d %d %d %d %d %d %d",
&process->m_size, &process->m_resident, &process->m_share,
&process->m_trs, &process->m_lrs, &process->m_drs,
&process->m_dt);
fclose(file);
return (num == 7);
}
#ifdef HAVE_OPENVZ
static void ProcessList_readOpenVZData(Process* process, const char* dirname, const char* name) {
if (access("/proc/vz", R_OK) != 0) {
process->vpid = process->pid;
process->ctid = 0;
return;
}
char filename[MAX_NAME+1];
snprintf(filename, MAX_NAME, "%s/%s/stat", dirname, name);
FILE* file = fopen(filename, "r");
if (!file)
return;
fscanf(file,
"%*u %*s %*c %*u %*u %*u %*u %*u %*u %*u "
"%*u %*u %*u %*u %*u %*u %*u %*u "
"%*u %*u %*u %*u %*u %*u %*u %*u "
"%*u %*u %*u %*u %*u %*u %*u %*u "
"%*u %*u %*u %*u %*u %*u %*u %*u "
"%*u %*u %*u %*u %*u %*u %*u "
"%*u %*u %u %u",
&process->vpid, &process->ctid);
fclose(file);
}
#endif
#ifdef HAVE_CGROUP
static void ProcessList_readCGroupFile(Process* process, const char* dirname, const char* name) {
char filename[MAX_NAME+1];
snprintf(filename, MAX_NAME, "%s/%s/cgroup", dirname, name);
FILE* file = fopen(filename, "r");
if (!file) {
process->cgroup = strdup("");
return;
}
char buffer[256];
char *ok = fgets(buffer, 255, file);
if (ok) {
char* trimmed = String_trim(buffer);
char** fields = String_split(trimmed, ':');
free(trimmed);
process->cgroup = strndup(fields[2] + 1, 10);
String_freeArray(fields);
}
fclose(file);
}
#endif
#ifdef HAVE_VSERVER
static void ProcessList_readVServerData(Process* process, const char* dirname, const char* name) {
char filename[MAX_NAME+1];
snprintf(filename, MAX_NAME, "%s/%s/status", dirname, name);
FILE* file = fopen(filename, "r");
if (!file)
return;
char buffer[256];
process->vxid = 0;
while (fgets(buffer, 255, file)) {
if (String_startsWith(buffer, "VxID:")) {
int vxid;
int ok = sscanf(buffer, "VxID:\t%d", &vxid);
if (ok >= 1) {
process->vxid = vxid;
}
}
#if defined HAVE_ANCIENT_VSERVER
else if (String_startsWith(buffer, "s_context:")) {
int vxid;
int ok = sscanf(buffer, "s_context:\t%d", &vxid);
if (ok >= 1) {
process->vxid = vxid;
}
}
#endif
}
fclose(file);
}
#endif
static bool ProcessList_readCmdlineFile(Process* process, const char* dirname, const char* name) {
if (Process_isKernelThread(process))
return true;
char filename[MAX_NAME+1];
snprintf(filename, MAX_NAME, "%s/%s/cmdline", dirname, name);
FILE* file = fopen(filename, "r");
if (!file)
return false;
char command[4096+1]; // max cmdline length on Linux
int amtRead = fread(command, 1, sizeof(command) - 1, file);
if (amtRead > 0) {
for (int i = 0; i < amtRead; i++)
if (command[i] == '\0' || command[i] == '\n') {
command[i] = ' ';
}
}
command[amtRead] = '\0';
fclose(file);
free(process->comm);
process->comm = String_copy(command);
return true;
}
static bool ProcessList_processEntries(ProcessList* this, const char* dirname, Process* parent, float period) {
DIR* dir;
struct dirent* entry;
dir = opendir(dirname);
if (!dir) return false;
int cpus = this->cpuCount;
bool showUserlandThreads = !this->hideUserlandThreads;
bool hideKernelThreads = this->hideKernelThreads;
bool hideUserlandThreads = this->hideUserlandThreads;
while ((entry = readdir(dir)) != NULL) {
char* name = entry->d_name;
int pid;
// filename is a number: process directory
pid = atoi(name);
int pid = atoi(name);
if (pid == parentPid)
if (parent && pid == parent->pid)
continue;
bool isThread = parent;
// The RedHat kernel hides threads with a dot.
// I believe this is non-standard.
bool isThread = false;
if ((!this->hideThreads) && pid == 0 && name[0] == '.') {
char* tname = name + 1;
pid = atoi(tname);
if (pid > 0)
isThread = true;
}
if (pid > 0) {
FILE* status;
char statusfilename[MAX_NAME+1];
char command[PROCESS_COMM_LEN + 1];
if (pid <= 0)
continue;
Process* process = NULL;
Process* existingProcess = (Process*) Hashtable_get(this->processTable, pid);
@ -559,185 +573,75 @@ static bool ProcessList_processEntries(ProcessList* this, const char* dirname, P
assert(Vector_indexOf(this->processes, existingProcess, Process_pidCompare) != -1);
process = existingProcess;
assert(process->pid == pid);
} else {
if (parent && parent->pid == pid) {
process = parent;
} else {
process = Process_new(this);
assert(process->comm == NULL);
process->pid = pid;
}
}
process->tgid = parent ? parent->pid : pid;
}
if (showUserlandThreads && (!parent || pid != parent->pid)) {
char subdirname[MAX_NAME+1];
snprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name);
ProcessList_processEntries(this, subdirname, process, pid, period);
}
ProcessList_processEntries(this, subdirname, process, period);
#ifdef HAVE_TASKSTATS
ProcessList_readIoFile(process, dirname, name);
#endif
process->updated = true;
if (!existingProcess)
if (! ProcessList_readStatusFile(process, dirname, name))
if (! ProcessList_readStatmFile(process, dirname, name))
goto errorReadingProcess;
snprintf(statusfilename, MAX_NAME, "%s/%s/statm", dirname, name);
status = ProcessList_fopen(this, statusfilename, "r");
if(!status) {
goto errorReadingProcess;
}
int num = ProcessList_fread(this, status, "%d %d %d %d %d %d %d",
&process->m_size, &process->m_resident, &process->m_share,
&process->m_trs, &process->m_lrs, &process->m_drs,
&process->m_dt);
fclose(status);
if(num != 7)
goto errorReadingProcess;
if (this->hideKernelThreads && process->m_size == 0)
goto errorReadingProcess;
isThread = Process_isThread(process);
process->show = ! ((hideKernelThreads && Process_isKernelThread(process)) || (hideUserlandThreads && Process_isUserlandThread(process)));
char command[MAX_NAME+1];
int lasttimes = (process->utime + process->stime);
snprintf(statusfilename, MAX_NAME, "%s/%s/stat", dirname, name);
status = ProcessList_fopen(this, statusfilename, "r");
if (status == NULL)
if (! ProcessList_readStatFile(process, dirname, name, command))
goto errorReadingProcess;
int success = ProcessList_readStatFile(process, status, command);
fclose(status);
if(!success) {
goto errorReadingProcess;
}
int percent_cpu = (process->utime + process->stime - lasttimes) / period * 100.0;
process->percent_cpu = MAX(MIN(percent_cpu, cpus*100.0), 0.0);
if (isnan(process->percent_cpu)) process->percent_cpu = 0.0;
process->percent_mem = (process->m_resident * PAGE_SIZE_KB) / (float)(this->totalMem) * 100.0;
if(!existingProcess) {
process->user = UsersTable_getRef(this->usersTable, process->st_uid);
#ifdef HAVE_OPENVZ
if (access("/proc/vz", R_OK) != 0) {
process->vpid = process->pid;
process->ctid = 0;
} else {
snprintf(statusfilename, MAX_NAME, "%s/%s/stat", dirname, name);
status = ProcessList_fopen(this, statusfilename, "r");
if (status == NULL)
if (! ProcessList_statProcessDir(process, dirname, name))
goto errorReadingProcess;
num = ProcessList_fread(this, status,
"%*u %*s %*c %*u %*u %*u %*u %*u %*u %*u "
"%*u %*u %*u %*u %*u %*u %*u %*u "
"%*u %*u %*u %*u %*u %*u %*u %*u "
"%*u %*u %*u %*u %*u %*u %*u %*u "
"%*u %*u %*u %*u %*u %*u %*u %*u "
"%*u %*u %*u %*u %*u %*u %*u "
"%*u %*u %u %u",
&process->vpid, &process->ctid);
fclose(status);
}
#ifdef HAVE_OPENVZ
ProcessList_readOpenVZData(process, dirname, name);
#endif
#ifdef HAVE_CGROUP
snprintf(statusfilename, MAX_NAME, "%s/%s/cgroup", dirname, name);
status = ProcessList_fopen(this, statusfilename, "r");
if (status) {
char buffer[256];
char *ok = fgets(buffer, 255, status);
if (ok) {
char* trimmed = String_trim(buffer);
char** fields = String_split(trimmed, ':');
free(trimmed);
process->cgroup = strndup(fields[2] + 1, 10);
String_freeArray(fields);
}
fclose(status);
} else {
process->cgroup = strdup("");
}
ProcessList_readCGroupFile(process, dirname, name);
#endif
#ifdef HAVE_VSERVER
snprintf(statusfilename, MAX_NAME, "%s/%s/status", dirname, name);
status = ProcessList_fopen(this, statusfilename, "r");
if (status == NULL)
goto errorReadingProcess;
else {
char buffer[256];
process->vxid = 0;
while (fgets(buffer, 255, status)) {
if (String_startsWith(buffer, "VxID:")) {
int vxid;
int ok = ProcessList_read(this, buffer, "VxID:\t%d", &vxid);
if (ok >= 1) {
process->vxid = vxid;
}
}
#if defined HAVE_ANCIENT_VSERVER
else if (String_startsWith(buffer, "s_context:")) {
int vxid;
int ok = ProcessList_read(this, buffer, "s_context:\t%d", &vxid);
if (ok >= 1) {
process->vxid = vxid;
}
}
ProcessList_readVServerData(process, dirname, name);
#endif
}
fclose(status);
}
#endif
}
if ( ((!existingProcess) && (!showUserlandThreads || pid == parentPid || !this->showThreadNames))
|| (this->showingThreadNames && !this->showThreadNames) ) {
snprintf(statusfilename, MAX_NAME, "%s/%s/cmdline", dirname, name);
status = ProcessList_fopen(this, statusfilename, "r");
if (!status) {
if (! ProcessList_readCmdlineFile(process, dirname, name))
goto errorReadingProcess;
}
int amtRead = fread(command, 1, PROCESS_COMM_LEN - 1, status);
if (amtRead > 0) {
for (int i = 0; i < amtRead; i++)
if (command[i] == '\0' || command[i] == '\n')
command[i] = ' ';
command[amtRead] = '\0';
}
fclose(status);
command[PROCESS_COMM_LEN] = '\0';
free(process->comm);
process->comm = String_copy(command);
} else if (pid != parentPid && this->showThreadNames) {
free(process->comm);
process->comm = String_copy(command);
}
int percent_cpu = (process->utime + process->stime - lasttimes) /
period * 100.0;
process->percent_cpu = MAX(MIN(percent_cpu, cpus*100.0), 0.0);
if (isnan(process->percent_cpu)) process->percent_cpu = 0.0;
process->percent_mem = (process->m_resident * PAGE_SIZE_KB) /
(float)(this->totalMem) *
100.0;
this->totalTasks++;
if (process->state == 'R') {
this->runningTasks++;
}
if (!existingProcess) {
ProcessList_add(this, process);
}
if (isThread) {
if (this->showThreadNames || Process_isKernelThread(process) || process->state == 'Z') {
free(process->comm);
process->comm = String_copy(command);
} else if (this->showingThreadNames) {
if (! ProcessList_readCmdlineFile(process, dirname, name))
goto errorReadingProcess;
}
}
this->totalTasks++;
if (process->state == 'R')
this->runningTasks++;
process->updated = true;
continue;
// Exception handler.
@ -752,7 +656,6 @@ static bool ProcessList_processEntries(ProcessList* this, const char* dirname, P
Process_delete((Object*)process);
}
}
}
closedir(dir);
return true;
}
@ -761,36 +664,35 @@ void ProcessList_scan(ProcessList* this) {
unsigned long long int usertime, nicetime, systemtime, systemalltime, idlealltime, idletime, totaltime, virtalltime;
unsigned long long int swapFree = 0;
FILE* status;
status = ProcessList_fopen(this, PROCMEMINFOFILE, "r");
assert(status != NULL);
FILE* file = fopen(PROCMEMINFOFILE, "r");
assert(file != NULL);
int cpus = this->cpuCount;
{
char buffer[128];
while (fgets(buffer, 128, status)) {
while (fgets(buffer, 128, file)) {
switch (buffer[0]) {
case 'M':
if (String_startsWith(buffer, "MemTotal:"))
ProcessList_read(this, buffer, "MemTotal: %llu kB", &this->totalMem);
sscanf(buffer, "MemTotal: %llu kB", &this->totalMem);
else if (String_startsWith(buffer, "MemFree:"))
ProcessList_read(this, buffer, "MemFree: %llu kB", &this->freeMem);
sscanf(buffer, "MemFree: %llu kB", &this->freeMem);
else if (String_startsWith(buffer, "MemShared:"))
ProcessList_read(this, buffer, "MemShared: %llu kB", &this->sharedMem);
sscanf(buffer, "MemShared: %llu kB", &this->sharedMem);
break;
case 'B':
if (String_startsWith(buffer, "Buffers:"))
ProcessList_read(this, buffer, "Buffers: %llu kB", &this->buffersMem);
sscanf(buffer, "Buffers: %llu kB", &this->buffersMem);
break;
case 'C':
if (String_startsWith(buffer, "Cached:"))
ProcessList_read(this, buffer, "Cached: %llu kB", &this->cachedMem);
sscanf(buffer, "Cached: %llu kB", &this->cachedMem);
break;
case 'S':
if (String_startsWith(buffer, "SwapTotal:"))
ProcessList_read(this, buffer, "SwapTotal: %llu kB", &this->totalSwap);
sscanf(buffer, "SwapTotal: %llu kB", &this->totalSwap);
if (String_startsWith(buffer, "SwapFree:"))
ProcessList_read(this, buffer, "SwapFree: %llu kB", &swapFree);
sscanf(buffer, "SwapFree: %llu kB", &swapFree);
break;
}
}
@ -798,11 +700,10 @@ void ProcessList_scan(ProcessList* this) {
this->usedMem = this->totalMem - this->freeMem;
this->usedSwap = this->totalSwap - swapFree;
fclose(status);
fclose(file);
status = ProcessList_fopen(this, PROCSTATFILE, "r");
assert(status != NULL);
file = fopen(PROCSTATFILE, "r");
assert(file != NULL);
for (int i = 0; i <= cpus; i++) {
char buffer[256];
int cpuid;
@ -811,11 +712,11 @@ void ProcessList_scan(ProcessList* this) {
// Dependending on your kernel version,
// 5, 7 or 8 of these fields will be set.
// The rest will remain at zero.
fgets(buffer, 255, status);
fgets(buffer, 255, file);
if (i == 0)
ProcessList_read(this, buffer, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest);
sscanf(buffer, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest);
else {
ProcessList_read(this, buffer, "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu", &cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest);
sscanf(buffer, "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu", &cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest);
assert(cpuid == i - 1);
}
// Fields existing on kernels >= 2.6
@ -862,7 +763,7 @@ void ProcessList_scan(ProcessList* this) {
cpuData->guestTime = guest;
cpuData->totalTime = totaltime;
}
float period = (float)this->cpus[0].totalPeriod / cpus; fclose(status);
float period = (float)this->cpus[0].totalPeriod / cpus; fclose(file);
// mark all process as "dirty"
for (int i = 0; i < Vector_size(this->processes); i++) {
@ -873,7 +774,7 @@ void ProcessList_scan(ProcessList* this) {
this->totalTasks = 0;
this->runningTasks = 0;
ProcessList_processEntries(this, PROCDIR, NULL, 0, period);
ProcessList_processEntries(this, PROCDIR, NULL, period);
this->showingThreadNames = this->showThreadNames;

View File

@ -58,10 +58,6 @@ in the source distribution for its full text.
#ifdef DEBUG_PROC
typedef int(*vxscanf)(void*, const char*, va_list);
#endif
typedef struct CPUData_ {
unsigned long long int totalTime;
unsigned long long int userTime;
@ -126,34 +122,16 @@ typedef struct ProcessList_ {
bool highlightMegabytes;
bool highlightThreads;
bool detailedCPUTime;
#ifdef DEBUG_PROC
FILE* traceFile;
#endif
} ProcessList;
#ifdef DEBUG_PROC
#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__ )
#else
#ifndef ProcessList_read
#define ProcessList_fopen(this, path, mode) fopen(path, mode)
#define ProcessList_read(this, buffer, format, ...) sscanf(buffer, format, ## __VA_ARGS__ )
#define ProcessList_fread(this, file, format, ...) fscanf(file, format, ## __VA_ARGS__ )
#endif
#endif
ProcessList* ProcessList_new(UsersTable* usersTable);
void ProcessList_delete(ProcessList* this);
void ProcessList_invertSortOrder(ProcessList* this);
RichString ProcessList_printHeader(ProcessList* this);
void ProcessList_printHeader(ProcessList* this, RichString* header);
Process* ProcessList_get(ProcessList* this, int idx);
@ -165,6 +143,19 @@ void ProcessList_sort(ProcessList* this);
#endif
#ifdef HAVE_OPENVZ
#endif
#ifdef HAVE_CGROUP
#endif
#ifdef HAVE_VSERVER
#endif
void ProcessList_scan(ProcessList* this);
ProcessField ProcessList_keyAt(ProcessList* this, int at);

View File

@ -22,26 +22,31 @@
/*{
#define RichString_init(this) (this)->len = 0
#define RichString_initVal(this) (this).len = 0
#define RichString_size(this) ((this)->chlen)
#define RichString_sizeVal(this) ((this).chlen)
#define RichString_begin(this) RichString (this); (this).chlen = 0; (this).chptr = (this).chstr;
#define RichString_beginAllocated(this) (this).chlen = 0; (this).chptr = (this).chstr;
#define RichString_end(this) RichString_prune(&(this));
#ifdef HAVE_LIBNCURSESW
#define RichString_printVal(this, y, x) mvadd_wchstr(y, x, this.chstr)
#define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, this.chstr + off, n)
#define RichString_getCharVal(this, i) (this.chstr[i].chars[0] & 255)
#define RichString_printVal(this, y, x) mvadd_wchstr(y, x, (this).chptr)
#define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, (this).chptr + off, n)
#define RichString_getCharVal(this, i) ((this).chptr[i].chars[0] & 255)
#define RichString_setChar(this, at, ch) do{ (this)->chptr[(at)].chars[0] = ch; } while(0)
#define CharType cchar_t
#else
#define RichString_printVal(this, y, x) mvaddchstr(y, x, this.chstr)
#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, this.chstr + off, n)
#define RichString_getCharVal(this, i) (this.chstr[i])
#define RichString_printVal(this, y, x) mvaddchstr(y, x, (this).chptr)
#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, (this).chptr + off, n)
#define RichString_getCharVal(this, i) ((this).chptr[i])
#define RichString_setChar(this, at, ch) do{ (this)->chptr[(at)] = ch; } while(0)
#define CharType chtype
#endif
typedef struct RichString_ {
int len;
#ifdef HAVE_LIBNCURSESW
cchar_t chstr[RICHSTRING_MAXLEN+1];
#else
chtype chstr[RICHSTRING_MAXLEN+1];
#endif
int chlen;
CharType chstr[RICHSTRING_MAXLEN+1];
CharType* chptr;
} RichString;
}*/
@ -50,25 +55,47 @@ typedef struct RichString_ {
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#define charBytes(n) (sizeof(CharType) * (n))
static inline void RichString_setLen(RichString* this, int len) {
if (this->chlen <= RICHSTRING_MAXLEN) {
if (len > RICHSTRING_MAXLEN) {
this->chptr = malloc(charBytes(len+1));
memcpy(this->chptr, this->chstr, charBytes(this->chlen+1));
}
} else {
if (len <= RICHSTRING_MAXLEN) {
memcpy(this->chstr, this->chptr, charBytes(this->chlen));
free(this->chptr);
this->chptr = this->chstr;
} else {
this->chptr = realloc(this->chptr, charBytes(len+1));
}
}
RichString_setChar(this, len, 0);
this->chlen = len;
}
#ifdef HAVE_LIBNCURSESW
inline void RichString_appendn(RichString* this, int attrs, const char* data_c, int len) {
wchar_t data[RICHSTRING_MAXLEN];
len = mbstowcs(data, data_c, RICHSTRING_MAXLEN);
wchar_t data[len+1];
len = mbstowcs(data, data_c, len);
if (len<0)
return;
int last = MIN(RICHSTRING_MAXLEN - 1, len + this->len);
for (int i = this->len, j = 0; i < last; i++, j++) {
memset(&this->chstr[i], 0, sizeof(this->chstr[i]));
this->chstr[i].chars[0] = data[j];
this->chstr[i].attr = attrs;
int oldLen = this->chlen;
int newLen = len + oldLen;
RichString_setLen(this, newLen);
for (int i = oldLen, j = 0; i < newLen; i++, j++) {
memset(&this->chptr[i], 0, sizeof(this->chptr[i]));
this->chptr[i].chars[0] = data[j];
this->chptr[i].attr = attrs;
}
this->chstr[last].chars[0] = 0;
this->len = last;
this->chptr[newLen].chars[0] = 0;
}
inline void RichString_setAttrn(RichString* this, int attrs, int start, int finish) {
cchar_t* ch = this->chstr + start;
cchar_t* ch = this->chptr + start;
for (int i = start; i <= finish; i++) {
ch->attr = attrs;
ch++;
@ -77,8 +104,8 @@ inline void RichString_setAttrn(RichString *this, int attrs, int start, int fini
int RichString_findChar(RichString* this, char c, int start) {
wchar_t wc = btowc(c);
cchar_t* ch = this->chstr + start;
for (int i = start; i < this->len; i++) {
cchar_t* ch = this->chptr + start;
for (int i = start; i < this->chlen; i++) {
if (ch->chars[0] == wc)
return i;
ch++;
@ -89,16 +116,16 @@ int RichString_findChar(RichString *this, char c, int start) {
#else
inline void RichString_appendn(RichString* this, int attrs, const char* data_c, int len) {
int last = MIN(RICHSTRING_MAXLEN - 1, len + this->len);
for (int i = this->len, j = 0; i < last; i++, j++)
this->chstr[i] = (isprint(data_c[j]) ? data_c[j] : '?') | attrs;
this->chstr[last] = 0;
this->len = last;
int oldLen = this->chlen;
int newLen = len + oldLen;
RichString_setLen(this, newLen);
for (int i = oldLen, j = 0; i < newLen; i++, j++)
this->chptr[i] = (isprint(data_c[j]) ? data_c[j] : '?') | attrs;
this->chptr[newLen] = 0;
}
void RichString_setAttrn(RichString* this, int attrs, int start, int finish) {
chtype* ch = this->chstr + start;
chtype* ch = this->chptr + start;
for (int i = start; i <= finish; i++) {
*ch = (*ch & 0xff) | attrs;
ch++;
@ -106,8 +133,8 @@ void RichString_setAttrn(RichString *this, int attrs, int start, int finish) {
}
int RichString_findChar(RichString* this, char c, int start) {
chtype* ch = this->chstr + start;
for (int i = start; i < this->len; i++) {
chtype* ch = this->chptr + start;
for (int i = start; i < this->chlen; i++) {
if ((*ch & 0xff) == (chtype) c)
return i;
ch++;
@ -118,11 +145,14 @@ int RichString_findChar(RichString *this, char c, int start) {
#endif
void RichString_prune(RichString* this) {
this->len = 0;
if (this->chlen > RICHSTRING_MAXLEN)
free(this->chptr);
this->chptr = this->chstr;
this->chlen = 0;
}
void RichString_setAttr(RichString* this, int attrs) {
RichString_setAttrn(this, attrs, 0, this->len - 1);
RichString_setAttrn(this, attrs, 0, this->chlen - 1);
}
inline void RichString_append(RichString* this, int attrs, const char* data) {
@ -130,13 +160,6 @@ inline void RichString_append(RichString* this, int attrs, const char* data) {
}
void RichString_write(RichString* this, int attrs, const char* data) {
RichString_init(this);
RichString_append(this, attrs, data);
}
RichString RichString_quickString(int attrs, const char* data) {
RichString str;
RichString_initVal(str);
RichString_write(&str, attrs, data);
return str;
RichString_setLen(this, 0);
RichString_appendn(this, attrs, data, strlen(data));
}

View File

@ -24,26 +24,31 @@
#define RICHSTRING_MAXLEN 300
#define RichString_init(this) (this)->len = 0
#define RichString_initVal(this) (this).len = 0
#define RichString_size(this) ((this)->chlen)
#define RichString_sizeVal(this) ((this).chlen)
#define RichString_begin(this) RichString (this); (this).chlen = 0; (this).chptr = (this).chstr;
#define RichString_beginAllocated(this) (this).chlen = 0; (this).chptr = (this).chstr;
#define RichString_end(this) RichString_prune(&(this));
#ifdef HAVE_LIBNCURSESW
#define RichString_printVal(this, y, x) mvadd_wchstr(y, x, this.chstr)
#define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, this.chstr + off, n)
#define RichString_getCharVal(this, i) (this.chstr[i].chars[0] & 255)
#define RichString_printVal(this, y, x) mvadd_wchstr(y, x, (this).chptr)
#define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, (this).chptr + off, n)
#define RichString_getCharVal(this, i) ((this).chptr[i].chars[0] & 255)
#define RichString_setChar(this, at, ch) do{ (this)->chptr[(at)].chars[0] = ch; } while(0)
#define CharType cchar_t
#else
#define RichString_printVal(this, y, x) mvaddchstr(y, x, this.chstr)
#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, this.chstr + off, n)
#define RichString_getCharVal(this, i) (this.chstr[i])
#define RichString_printVal(this, y, x) mvaddchstr(y, x, (this).chptr)
#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, (this).chptr + off, n)
#define RichString_getCharVal(this, i) ((this).chptr[i])
#define RichString_setChar(this, at, ch) do{ (this)->chptr[(at)] = ch; } while(0)
#define CharType chtype
#endif
typedef struct RichString_ {
int len;
#ifdef HAVE_LIBNCURSESW
cchar_t chstr[RICHSTRING_MAXLEN+1];
#else
chtype chstr[RICHSTRING_MAXLEN+1];
#endif
int chlen;
CharType chstr[RICHSTRING_MAXLEN+1];
CharType* chptr;
} RichString;
@ -51,6 +56,8 @@ typedef struct RichString_ {
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#define charBytes(n) (sizeof(CharType) * (n))
#ifdef HAVE_LIBNCURSESW
extern void RichString_appendn(RichString* this, int attrs, const char* data_c, int len);
@ -77,6 +84,4 @@ extern void RichString_append(RichString* this, int attrs, const char* data);
void RichString_write(RichString* this, int attrs, const char* data);
RichString RichString_quickString(int attrs, const char* data);
#endif

View File

@ -34,8 +34,7 @@ static void SwapMeter_display(Object* cast, RichString* out) {
char buffer[50];
Meter* this = (Meter*)cast;
long int swap = (long int) this->values[0];
RichString_init(out);
RichString_append(out, CRT_colors[METER_TEXT], ":");
RichString_write(out, CRT_colors[METER_TEXT], ":");
sprintf(buffer, "%ldM ", (long int) this->total / 1024);
RichString_append(out, CRT_colors[METER_VALUE], buffer);
sprintf(buffer, "%ldk", swap);

View File

@ -26,10 +26,9 @@ static void TasksMeter_setValues(Meter* this, char* buffer, int len) {
static void TasksMeter_display(Object* cast, RichString* out) {
Meter* this = (Meter*)cast;
RichString_init(out);
char buffer[20];
sprintf(buffer, "%d", (int)this->total);
RichString_append(out, CRT_colors[METER_VALUE], buffer);
RichString_write(out, CRT_colors[METER_VALUE], buffer);
RichString_append(out, CRT_colors[METER_TEXT], " total, ");
sprintf(buffer, "%d", (int)this->values[0]);
RichString_append(out, CRT_colors[TASKS_RUNNING], buffer);

19
htop.c
View File

@ -241,7 +241,7 @@ static inline void setSortKey(ProcessList* pl, ProcessField sortKey, Panel* pane
pl->direction = 1;
pl->treeView = false;
settings->changed = true;
Panel_setRichHeader(panel, ProcessList_printHeader(pl));
ProcessList_printHeader(pl, Panel_getHeader(panel));
}
int main(int argc, char** argv) {
@ -352,7 +352,7 @@ int main(int argc, char** argv) {
pl->treeView = false;
pl->direction = 1;
}
Panel_setRichHeader(panel, ProcessList_printHeader(pl));
ProcessList_printHeader(pl, Panel_getHeader(panel));
const char* searchFunctions[] = {"Next ", "Exit ", " Search: ", NULL};
const char* searchKeys[] = {"F3", "Esc", " "};
@ -395,7 +395,7 @@ int main(int argc, char** argv) {
ProcessList_scan(pl);
doRecalculate = false;
}
if (refreshTimeout == 0) {
if (refreshTimeout == 0 || pl->treeView) {
ProcessList_sort(pl);
refreshTimeout = 1;
}
@ -404,7 +404,7 @@ int main(int argc, char** argv) {
int idx = 0;
for (int i = 0; i < size; i++) {
Process* p = ProcessList_get(pl, i);
if (!userOnly || (p->st_uid == userId)) {
if (p->show && (!userOnly || (p->st_uid == userId))) {
Panel_set(panel, idx, (Object*)p);
if ((!follow && idx == currPos) || (follow && p->pid == currPid)) {
Panel_setSelected(panel, idx);
@ -608,7 +608,7 @@ int main(int argc, char** argv) {
{
Setup_run(settings, headerHeight);
// TODO: shouldn't need this, colors should be dynamic
Panel_setRichHeader(panel, ProcessList_printHeader(pl));
ProcessList_printHeader(pl, Panel_getHeader(panel));
headerHeight = Header_calculateHeight(header);
Panel_move(panel, 0, headerHeight);
Panel_resize(panel, COLS, LINES-headerHeight-1);
@ -680,7 +680,7 @@ int main(int argc, char** argv) {
napms(500);
}
}
Panel_setRichHeader(panel, ProcessList_printHeader(pl));
ProcessList_printHeader(pl, Panel_getHeader(panel));
refreshTimeout = 0;
break;
}
@ -715,7 +715,7 @@ int main(int argc, char** argv) {
beep();
}
((Object*)affinityPanel)->delete((Object*)affinityPanel);
Panel_setRichHeader(panel, ProcessList_printHeader(pl));
ProcessList_printHeader(pl, Panel_getHeader(panel));
refreshTimeout = 0;
break;
}
@ -747,7 +747,7 @@ int main(int argc, char** argv) {
settings->changed = true;
setSortKey(pl, field->key, panel, settings);
} else {
Panel_setRichHeader(panel, ProcessList_printHeader(pl));
ProcessList_printHeader(pl, Panel_getHeader(panel));
}
((Object*)sortPanel)->delete((Object*)sortPanel);
refreshTimeout = 0;
@ -825,6 +825,9 @@ int main(int argc, char** argv) {
((Object*)killPanel)->delete((Object*)killPanel);
UsersTable_delete(ut);
Settings_delete(settings);
#ifdef HAVE_PLPA
plpa_finalize();
#endif
debug_done();
return 0;
}