diff --git a/CPUMeter.c b/CPUMeter.c index bed6266c..a1144ea9 100644 --- a/CPUMeter.c +++ b/CPUMeter.c @@ -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; diff --git a/LoadAverageMeter.c b/LoadAverageMeter.c index c8e38ff6..1109dab4 100644 --- a/LoadAverageMeter.c +++ b/LoadAverageMeter.c @@ -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 = { diff --git a/MemoryMeter.c b/MemoryMeter.c index 66c4fa5c..e3e18ec0 100644 --- a/MemoryMeter.c +++ b/MemoryMeter.c @@ -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); diff --git a/Meter.c b/Meter.c index b65b0ee1..341be721 100644 --- a/Meter.c +++ b/Meter.c @@ -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 ---------- */ @@ -378,14 +377,16 @@ static void LEDMeterMode_draw(Meter* this, int x, int y, int w) { MeterType* type = this->type; 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 diff --git a/Panel.c b/Panel.c index f4f286e5..c90a1674 100644 --- a/Panel.c +++ b/Panel.c @@ -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); diff --git a/Panel.h b/Panel.h index 66723251..c6f74336 100644 --- a/Panel.h +++ b/Panel.h @@ -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); diff --git a/Process.c b/Process.c index 30e243b1..0f2f1f58 100644 --- a/Process.c +++ b/Process.c @@ -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; @@ -225,7 +232,7 @@ static int Process_getuid = -1; #define ONE_M (ONE_K * ONE_K) #define ONE_G (ONE_M * ONE_K) -static void Process_printLargeNumber(Process* this, RichString *str, unsigned long number) { +static void Process_printLargeNumber(Process* this, RichString* str, unsigned long number) { char buffer[11]; int len; if(number >= (10 * ONE_M)) { @@ -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; diff --git a/Process.h b/Process.h index f7d1adf3..88e825e9 100644 --- a/Process.h +++ b/Process.h @@ -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; diff --git a/ProcessList.c b/ProcessList.c index cd265361..c37919ba 100644 --- a/ProcessList.c +++ b/ProcessList.c @@ -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) { - 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); - } + 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 | (1 << level); + ProcessList_buildTree(this, process->pid, level+1, (i < size - 1) ? nextIndent : indent, direction, show); + process->indent = nextIndent; } Vector_delete(children); } @@ -393,365 +309,352 @@ 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(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; - 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; - continue; - } - ProcessList_read(this, buffer, "cancelled_write_bytes: %llu", &proc->io_cancelled_write_bytes); + snprintf(filename, MAX_NAME, "%s/%s/io", dirname, name); + FILE* file = fopen(filename, "r"); + if (!file) + return; + + 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 = 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; } - fclose(io); + 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; + } + 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); - - if (pid == parentPid) + int pid = atoi(name); + + 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; + isThread = true; } - - if (pid > 0) { - - FILE* status; - char statusfilename[MAX_NAME+1]; - char command[PROCESS_COMM_LEN + 1]; - - Process* process = NULL; - Process* existingProcess = (Process*) Hashtable_get(this->processTable, pid); - - if (existingProcess) { - 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); - } - - #ifdef HAVE_TASKSTATS - ProcessList_readIoFile(process, dirname, name); - #endif - - process->updated = true; - - if (!existingProcess) - if (! ProcessList_readStatusFile(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; - - int lasttimes = (process->utime + process->stime); - - snprintf(statusfilename, MAX_NAME, "%s/%s/stat", dirname, name); - - status = ProcessList_fopen(this, statusfilename, "r"); - if (status == NULL) - goto errorReadingProcess; - - int success = ProcessList_readStatFile(process, status, command); - fclose(status); - if(!success) { - goto errorReadingProcess; - } - - 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) - 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); - } - #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(""); - } - #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; - } - } - #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) { - 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 (pid <= 0) continue; - // Exception handler. - errorReadingProcess: { - if (process->comm) { - free(process->comm); - process->comm = NULL; - } - if (existingProcess) - ProcessList_remove(this, process); - else - Process_delete((Object*)process); + Process* process = NULL; + Process* existingProcess = (Process*) Hashtable_get(this->processTable, pid); + + if (existingProcess) { + assert(Vector_indexOf(this->processes, existingProcess, Process_pidCompare) != -1); + process = existingProcess; + assert(process->pid == pid); + } else { + process = Process_new(this); + assert(process->comm == NULL); + process->pid = pid; + process->tgid = parent ? parent->pid : pid; + } + + char subdirname[MAX_NAME+1]; + snprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name); + ProcessList_processEntries(this, subdirname, process, period); + + #ifdef HAVE_TASKSTATS + ProcessList_readIoFile(process, dirname, name); + #endif + + if (! ProcessList_readStatmFile(process, dirname, name)) + 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); + if (! ProcessList_readStatFile(process, dirname, name, command)) + 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); + + if (! ProcessList_statProcessDir(process, dirname, name)) + goto errorReadingProcess; + + #ifdef HAVE_OPENVZ + ProcessList_readOpenVZData(process, dirname, name); + #endif + + #ifdef HAVE_CGROUP + ProcessList_readCGroupFile(process, dirname, name); + #endif + + #ifdef HAVE_VSERVER + ProcessList_readVServerData(process, dirname, name); + #endif + + if (! ProcessList_readCmdlineFile(process, dirname, name)) + goto errorReadingProcess; + + 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. + errorReadingProcess: { + if (process->comm) { + free(process->comm); + process->comm = NULL; + } + if (existingProcess) + ProcessList_remove(this, process); + else + 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; diff --git a/ProcessList.h b/ProcessList.h index 48456def..2442f351 100644 --- a/ProcessList.h +++ b/ProcessList.h @@ -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); diff --git a/RichString.c b/RichString.c index a62a053a..6d87cd84 100644 --- a/RichString.c +++ b/RichString.c @@ -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,35 +55,57 @@ 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; +inline void RichString_setAttrn(RichString* this, int attrs, int start, int finish) { + cchar_t* ch = this->chptr + start; for (int i = start; i <= finish; i++) { ch->attr = attrs; ch++; } } -int RichString_findChar(RichString *this, char c, int start) { +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,25 +116,25 @@ 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; +void RichString_setAttrn(RichString* this, int attrs, int start, int finish) { + chtype* ch = this->chptr + start; for (int i = start; i <= finish; i++) { *ch = (*ch & 0xff) | attrs; ch++; } } -int RichString_findChar(RichString *this, char c, int start) { - chtype* ch = this->chstr + start; - for (int i = start; i < this->len; i++) { +int RichString_findChar(RichString* this, char c, int start) { + 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); +void RichString_setAttr(RichString* this, int attrs) { + 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)); } diff --git a/RichString.h b/RichString.h index 7b2de38e..b6622a13 100644 --- a/RichString.h +++ b/RichString.h @@ -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,32 +56,32 @@ 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); -extern void RichString_setAttrn(RichString *this, int attrs, int start, int finish); +extern void RichString_setAttrn(RichString* this, int attrs, int start, int finish); -int RichString_findChar(RichString *this, char c, int start); +int RichString_findChar(RichString* this, char c, int start); #else extern void RichString_appendn(RichString* this, int attrs, const char* data_c, int len); -void RichString_setAttrn(RichString *this, int attrs, int start, int finish); +void RichString_setAttrn(RichString* this, int attrs, int start, int finish); -int RichString_findChar(RichString *this, char c, int start); +int RichString_findChar(RichString* this, char c, int start); #endif void RichString_prune(RichString* this); -void RichString_setAttr(RichString *this, int attrs); +void RichString_setAttr(RichString* this, int attrs); 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 diff --git a/SwapMeter.c b/SwapMeter.c index 0f42e080..ecbd129a 100644 --- a/SwapMeter.c +++ b/SwapMeter.c @@ -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); diff --git a/TasksMeter.c b/TasksMeter.c index e82f53c7..685489ab 100644 --- a/TasksMeter.c +++ b/TasksMeter.c @@ -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); diff --git a/htop.c b/htop.c index 79373894..0cc5eebc 100644 --- a/htop.c +++ b/htop.c @@ -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; }