From 283707c5e5bc436b78ea23bf5500cb6b16a01148 Mon Sep 17 00:00:00 2001 From: Daniel Lange Date: Mon, 11 Apr 2016 13:00:27 +0200 Subject: Imported Upstream version 0.9 --- ProcessList.c | 936 +++++++++++++++++++++++++++------------------------------- 1 file changed, 443 insertions(+), 493 deletions(-) (limited to 'ProcessList.c') diff --git a/ProcessList.c b/ProcessList.c index 24e0810..c234357 100644 --- a/ProcessList.c +++ b/ProcessList.c @@ -27,11 +27,13 @@ in the source distribution for its full text. #include #include #include +#include #include "debug.h" #include /*{ + #ifndef PROCDIR #define PROCDIR "/proc" #endif @@ -52,52 +54,51 @@ in the source distribution for its full text. #define MAX_READ 2048 #endif -#ifndef PER_PROCESSOR_FIELDS -#define PER_PROCESSOR_FIELDS 22 -#endif - }*/ /*{ -#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; + unsigned long long int systemTime; + unsigned long long int systemAllTime; + unsigned long long int idleAllTime; + unsigned long long int idleTime; + unsigned long long int niceTime; + unsigned long long int ioWaitTime; + unsigned long long int irqTime; + unsigned long long int softIrqTime; + unsigned long long int stealTime; + unsigned long long int guestTime; + + unsigned long long int totalPeriod; + unsigned long long int userPeriod; + unsigned long long int systemPeriod; + unsigned long long int systemAllPeriod; + unsigned long long int idleAllPeriod; + unsigned long long int idlePeriod; + unsigned long long int nicePeriod; + unsigned long long int ioWaitPeriod; + unsigned long long int irqPeriod; + unsigned long long int softIrqPeriod; + unsigned long long int stealPeriod; + unsigned long long int guestPeriod; +} CPUData; typedef struct ProcessList_ { Vector* processes; Vector* processes2; Hashtable* processTable; - Process* prototype; UsersTable* usersTable; - int processorCount; + int cpuCount; int totalTasks; + int userlandThreads; + int kernelThreads; int runningTasks; - // Must match number of PER_PROCESSOR_FIELDS constant - unsigned long long int* totalTime; - unsigned long long int* userTime; - unsigned long long int* systemTime; - unsigned long long int* systemAllTime; - unsigned long long int* idleAllTime; - unsigned long long int* idleTime; - unsigned long long int* niceTime; - unsigned long long int* ioWaitTime; - unsigned long long int* irqTime; - unsigned long long int* softIrqTime; - unsigned long long int* stealTime; - unsigned long long int* totalPeriod; - unsigned long long int* userPeriod; - unsigned long long int* systemPeriod; - unsigned long long int* systemAllPeriod; - unsigned long long int* idleAllPeriod; - unsigned long long int* idlePeriod; - unsigned long long int* nicePeriod; - unsigned long long int* ioWaitPeriod; - unsigned long long int* irqPeriod; - unsigned long long int* softIrqPeriod; - unsigned long long int* stealPeriod; + CPUData* cpus; unsigned long long int totalMem; unsigned long long int usedMem; @@ -114,6 +115,8 @@ typedef struct ProcessList_ { int direction; bool hideThreads; bool shadowOtherUsers; + bool showThreadNames; + bool showingThreadNames; bool hideKernelThreads; bool hideUserlandThreads; bool treeView; @@ -121,119 +124,39 @@ 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 - -static inline void ProcessList_allocatePerProcessorBuffers(ProcessList* this, int procs) { - unsigned long long int** bufferPtr = &(this->totalTime); - unsigned long long int* buffer = calloc(procs * PER_PROCESSOR_FIELDS, sizeof(unsigned long long int)); - for (int i = 0; i < PER_PROCESSOR_FIELDS; i++) { - *bufferPtr = buffer; - bufferPtr++; - buffer += procs; - } -} - ProcessList* ProcessList_new(UsersTable* usersTable) { ProcessList* this; this = malloc(sizeof(ProcessList)); this->processes = Vector_new(PROCESS_CLASS, true, DEFAULT_SIZE, Process_compare); this->processTable = Hashtable_new(70, false); assert(Hashtable_count(this->processTable) == Vector_count(this->processes)); - this->prototype = Process_new(this); this->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 procs = -1; + int cpus = -1; do { - procs++; - fgets(buffer, 255, status); + cpus++; + fgets(buffer, 255, file); } while (String_startsWith(buffer, "cpu")); - fclose(status); - this->processorCount = procs - 1; + fclose(file); + this->cpuCount = cpus - 1; - ProcessList_allocatePerProcessorBuffers(this, procs); + this->cpus = calloc(sizeof(CPUData), cpus); - for (int i = 0; i < procs; i++) { - this->totalTime[i] = 1; - this->totalPeriod[i] = 1; + for (int i = 0; i < cpus; i++) { + this->cpus[i].totalTime = 1; + this->cpus[i].totalPeriod = 1; } this->fields = calloc(sizeof(ProcessField), LAST_PROCESSFIELD+1); @@ -246,6 +169,8 @@ ProcessList* ProcessList_new(UsersTable* usersTable) { this->direction = 1; this->hideThreads = false; this->shadowOtherUsers = false; + this->showThreadNames = false; + this->showingThreadNames = false; this->hideKernelThreads = false; this->hideUserlandThreads = false; this->treeView = false; @@ -260,16 +185,7 @@ void ProcessList_delete(ProcessList* this) { Hashtable_delete(this->processTable); Vector_delete(this->processes); Vector_delete(this->processes2); - Process_delete((Object*)this->prototype); - - // Free first entry only; - // other fields are offsets of the same buffer - free(this->totalTime); - - #ifdef DEBUG_PROC - fclose(this->traceFile); - #endif - + free(this->cpus); free(this->fields); free(this); } @@ -281,25 +197,25 @@ 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++) { - char* field = Process_fieldTitles[fields[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) { assert(Vector_indexOf(this->processes, p, Process_pidCompare) == -1); assert(Hashtable_get(this->processTable, p->pid) == NULL); + Vector_add(this->processes, p); Hashtable_put(this->processTable, p->pid, p); + assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1); assert(Hashtable_get(this->processTable, p->pid) != NULL); assert(Hashtable_count(this->processTable) == Vector_count(this->processes)); @@ -311,45 +227,45 @@ static void ProcessList_remove(ProcessList* this, Process* p) { Process* pp = Hashtable_remove(this->processTable, p->pid); assert(pp == p); (void)pp; unsigned int pid = p->pid; - int index = Vector_indexOf(this->processes, p, Process_pidCompare); - assert(index != -1); - Vector_remove(this->processes, index); + int idx = Vector_indexOf(this->processes, p, Process_pidCompare); + assert(idx != -1); + if (idx >= 0) Vector_remove(this->processes, idx); assert(Hashtable_get(this->processTable, pid) == NULL); (void)pid; assert(Hashtable_count(this->processTable) == Vector_count(this->processes)); } -Process* ProcessList_get(ProcessList* this, int index) { - return (Process*) (Vector_get(this->processes, index)); +Process* ProcessList_get(ProcessList* this, int idx) { + return (Process*) (Vector_get(this->processes, idx)); } int ProcessList_size(ProcessList* this) { return (Vector_size(this->processes)); } -static void ProcessList_buildTree(ProcessList* this, int pid, int level, int indent, int direction) { +static void ProcessList_buildTree(ProcessList* this, pid_t pid, int level, int indent, int direction, bool show) { Vector* children = Vector_new(PROCESS_CLASS, false, DEFAULT_SIZE, Process_compare); for (int i = Vector_size(this->processes) - 1; i >= 0; i--) { Process* process = (Process*) (Vector_get(this->processes, i)); if (process->tgid == pid || (process->tgid == process->pid && process->ppid == pid)) { - Process* process = (Process*) (Vector_take(this->processes, i)); + process = (Process*) (Vector_take(this->processes, i)); Vector_add(children, process); } } int size = Vector_size(children); for (int i = 0; i < size; i++) { Process* process = (Process*) (Vector_get(children, i)); + if (!show) + process->show = 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->indent = indent | (1 << level); + int nextIndent = indent | (1 << level); + ProcessList_buildTree(this, process->pid, level+1, (i < size - 1) ? nextIndent : indent, direction, show ? process->showChildren : false); + process->indent = nextIndent; } Vector_delete(children); } @@ -377,13 +293,13 @@ void ProcessList_sort(ProcessList* this) { init->indent = 0; Vector_add(this->processes2, init); // Recursively empty list - ProcessList_buildTree(this, init->pid, 0, 0, direction); + ProcessList_buildTree(this, init->pid, 0, 0, direction, true); // Add leftovers while (Vector_size(this->processes)) { Process* p = (Process*) (Vector_take(this->processes, 0)); p->indent = 0; Vector_add(this->processes2, p); - ProcessList_buildTree(this, p->pid, 0, 0, direction); + ProcessList_buildTree(this, p->pid, 0, 0, direction, p->showChildren); } assert(Vector_size(this->processes2) == vsize); (void)vsize; assert(Vector_size(this->processes) == 0); @@ -394,334 +310,353 @@ void ProcessList_sort(ProcessList* this) { } } -static int ProcessList_readStatFile(ProcessList* this, 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 " - "%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, - &proc->starttime, &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 %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, - &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(ProcessList* this, Process* proc, 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; + process->starttime_ctime = ctime; + (void) localtime_r((time_t*) &ctime, &date); + strftime(process->starttime_show, 7, ((ctime > time(NULL) - 86400) ? "%R " : "%b%d "), &date); + return true; } #ifdef HAVE_TASKSTATS -static void ProcessList_readIoFile(ProcessList* this, Process* proc, 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 (!feof(io)) { - char* ok = fgets(buffer, 255, io); - if (!ok) - break; - 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; + 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; + } + 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_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 (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; + } + #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; } - ProcessList_read(this, buffer, "cancelled_write_bytes: %llu", &proc->io_cancelled_write_bytes); } - fclose(io); + #endif } + fclose(file); } #endif -static bool ProcessList_processEntries(ProcessList* this, char* dirname, Process* parent, float period) { +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; - Process* prototype = this->prototype; dir = opendir(dirname); if (!dir) return false; - int processors = this->processorCount; - bool showUserlandThreads = !this->hideUserlandThreads; + int cpus = this->cpuCount; + 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 (parent && pid == parent->pid) + continue; // 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; + pid = atoi(name + 1); } + if (pid <= 0) + continue; - 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 = prototype; - assert(process->comm == NULL); - process->pid = pid; - } - } + 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; + } - if (showUserlandThreads && (!parent || pid != parent->pid)) { - char subdirname[MAX_NAME+1]; - snprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name); - - if (ProcessList_processEntries(this, subdirname, process, period)) - continue; - } + 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(this, process, dirname, name); - #endif + #ifdef HAVE_TASKSTATS + ProcessList_readIoFile(process, dirname, name); + #endif - process->updated = true; + if (! ProcessList_readStatmFile(process, dirname, name)) + goto errorReadingProcess; - if (!existingProcess) - if (! ProcessList_readStatusFile(this, process, dirname, name)) - goto errorReadingProcess; + process->show = ! ((hideKernelThreads && Process_isKernelThread(process)) || (hideUserlandThreads && Process_isUserlandThread(process))); - snprintf(statusfilename, MAX_NAME, "%s/%s/statm", dirname, name); - status = ProcessList_fopen(this, statusfilename, "r"); + 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(!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); + if(!existingProcess) { - fclose(status); - if(num != 7) + if (! ProcessList_statProcessDir(process, dirname, name)) goto errorReadingProcess; - if (this->hideKernelThreads && process->m_size == 0) - goto errorReadingProcess; + process->user = UsersTable_getRef(this->usersTable, process->st_uid); - int lasttimes = (process->utime + process->stime); + #ifdef HAVE_OPENVZ + ProcessList_readOpenVZData(process, dirname, name); + #endif - snprintf(statusfilename, MAX_NAME, "%s/%s/stat", dirname, name); + #ifdef HAVE_CGROUP + ProcessList_readCGroupFile(process, dirname, name); + #endif - status = ProcessList_fopen(this, statusfilename, "r"); - if (status == NULL) + #ifdef HAVE_VSERVER + ProcessList_readVServerData(process, dirname, name); + #endif + + if (! ProcessList_readCmdlineFile(process, dirname, name)) goto errorReadingProcess; - int success = ProcessList_readStatFile(this, process, status, command); - fclose(status); - if(!success) { - goto errorReadingProcess; - } + ProcessList_add(this, process); + } - 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_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 (!feof(status)) { - char* ok = fgets(buffer, 255, status); - if (!ok) - break; - - 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 - - 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'; - } - command[PROCESS_COMM_LEN] = '\0'; + if (Process_isThread(process)) { + if (this->showThreadNames || Process_isKernelThread(process) || process->state == 'Z') { + free(process->comm); process->comm = String_copy(command); - fclose(status); + } else if (this->showingThreadNames) { + if (! ProcessList_readCmdlineFile(process, dirname, name)) + goto errorReadingProcess; } - - int percent_cpu = (process->utime + process->stime - lasttimes) / - period * 100.0; - process->percent_cpu = MAX(MIN(percent_cpu, processors*100.0), 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 (Process_isKernelThread(process)) { + this->kernelThreads++; + } else { + this->userlandThreads++; } + } - if (!existingProcess) { - process = Process_clone(process); - ProcessList_add(this, process); - } + this->totalTasks++; + if (process->state == 'R') + this->runningTasks++; + process->updated = true; - continue; + continue; - // Exception handler. - errorReadingProcess: { - if (process->comm) { - free(process->comm); - process->comm = NULL; - } - if (existingProcess) - ProcessList_remove(this, process); - assert(Hashtable_count(this->processTable) == Vector_count(this->processes)); + // 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); @@ -729,106 +664,109 @@ static bool ProcessList_processEntries(ProcessList* this, char* dirname, Process } void ProcessList_scan(ProcessList* this) { - unsigned long long int usertime, nicetime, systemtime, systemalltime, idlealltime, idletime, totaltime; - unsigned long long int swapFree; - - FILE* status; - char buffer[128]; - status = ProcessList_fopen(this, PROCMEMINFOFILE, "r"); - assert(status != NULL); - int processors = this->processorCount; - while (!feof(status)) { - fgets(buffer, 128, status); - - switch (buffer[0]) { - case 'M': - if (String_startsWith(buffer, "MemTotal:")) - ProcessList_read(this, buffer, "MemTotal: %llu kB", &this->totalMem); - else if (String_startsWith(buffer, "MemFree:")) - ProcessList_read(this, buffer, "MemFree: %llu kB", &this->freeMem); - else if (String_startsWith(buffer, "MemShared:")) - ProcessList_read(this, buffer, "MemShared: %llu kB", &this->sharedMem); - break; - case 'B': - if (String_startsWith(buffer, "Buffers:")) - ProcessList_read(this, buffer, "Buffers: %llu kB", &this->buffersMem); - break; - case 'C': - if (String_startsWith(buffer, "Cached:")) - ProcessList_read(this, buffer, "Cached: %llu kB", &this->cachedMem); - break; - case 'S': - if (String_startsWith(buffer, "SwapTotal:")) - ProcessList_read(this, buffer, "SwapTotal: %llu kB", &this->totalSwap); - if (String_startsWith(buffer, "SwapFree:")) - ProcessList_read(this, buffer, "SwapFree: %llu kB", &swapFree); - break; + unsigned long long int usertime, nicetime, systemtime, systemalltime, idlealltime, idletime, totaltime, virtalltime; + unsigned long long int swapFree = 0; + + FILE* file = fopen(PROCMEMINFOFILE, "r"); + assert(file != NULL); + int cpus = this->cpuCount; + { + char buffer[128]; + while (fgets(buffer, 128, file)) { + + switch (buffer[0]) { + case 'M': + if (String_startsWith(buffer, "MemTotal:")) + sscanf(buffer, "MemTotal: %llu kB", &this->totalMem); + else if (String_startsWith(buffer, "MemFree:")) + sscanf(buffer, "MemFree: %llu kB", &this->freeMem); + else if (String_startsWith(buffer, "MemShared:")) + sscanf(buffer, "MemShared: %llu kB", &this->sharedMem); + break; + case 'B': + if (String_startsWith(buffer, "Buffers:")) + sscanf(buffer, "Buffers: %llu kB", &this->buffersMem); + break; + case 'C': + if (String_startsWith(buffer, "Cached:")) + sscanf(buffer, "Cached: %llu kB", &this->cachedMem); + break; + case 'S': + if (String_startsWith(buffer, "SwapTotal:")) + sscanf(buffer, "SwapTotal: %llu kB", &this->totalSwap); + if (String_startsWith(buffer, "SwapFree:")) + sscanf(buffer, "SwapFree: %llu kB", &swapFree); + break; + } } } this->usedMem = this->totalMem - this->freeMem; this->usedSwap = this->totalSwap - swapFree; - fclose(status); - - status = ProcessList_fopen(this, PROCSTATFILE, "r"); + fclose(file); - assert(status != NULL); - for (int i = 0; i <= processors; i++) { + file = fopen(PROCSTATFILE, "r"); + assert(file != NULL); + for (int i = 0; i <= cpus; i++) { char buffer[256]; int cpuid; - unsigned long long int ioWait, irq, softIrq, steal; - ioWait = irq = softIrq = steal = 0; + unsigned long long int ioWait, irq, softIrq, steal, guest; + ioWait = irq = softIrq = steal = guest = 0; // 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", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal); + 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", &cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal); + 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 // (and RHEL's patched kernel 2.4...) idlealltime = idletime + ioWait; - systemalltime = systemtime + irq + softIrq + steal; - totaltime = usertime + nicetime + systemalltime + idlealltime; - assert (usertime >= this->userTime[i]); - assert (nicetime >= this->niceTime[i]); - assert (systemtime >= this->systemTime[i]); - assert (idletime >= this->idleTime[i]); - assert (totaltime >= this->totalTime[i]); - assert (systemalltime >= this->systemAllTime[i]); - assert (idlealltime >= this->idleAllTime[i]); - assert (ioWait >= this->ioWaitTime[i]); - assert (irq >= this->irqTime[i]); - assert (softIrq >= this->softIrqTime[i]); - assert (steal >= this->stealTime[i]); - this->userPeriod[i] = usertime - this->userTime[i]; - this->nicePeriod[i] = nicetime - this->niceTime[i]; - this->systemPeriod[i] = systemtime - this->systemTime[i]; - this->systemAllPeriod[i] = systemalltime - this->systemAllTime[i]; - this->idleAllPeriod[i] = idlealltime - this->idleAllTime[i]; - this->idlePeriod[i] = idletime - this->idleTime[i]; - this->ioWaitPeriod[i] = ioWait - this->ioWaitTime[i]; - this->irqPeriod[i] = irq - this->irqTime[i]; - this->softIrqPeriod[i] = softIrq - this->softIrqTime[i]; - this->stealPeriod[i] = steal - this->stealTime[i]; - this->totalPeriod[i] = totaltime - this->totalTime[i]; - this->userTime[i] = usertime; - this->niceTime[i] = nicetime; - this->systemTime[i] = systemtime; - this->systemAllTime[i] = systemalltime; - this->idleAllTime[i] = idlealltime; - this->idleTime[i] = idletime; - this->ioWaitTime[i] = ioWait; - this->irqTime[i] = irq; - this->softIrqTime[i] = softIrq; - this->stealTime[i] = steal; - this->totalTime[i] = totaltime; + systemalltime = systemtime + irq + softIrq; + virtalltime = steal + guest; + totaltime = usertime + nicetime + systemalltime + idlealltime + virtalltime; + CPUData* cpuData = &(this->cpus[i]); + assert (usertime >= cpuData->userTime); + assert (nicetime >= cpuData->niceTime); + assert (systemtime >= cpuData->systemTime); + assert (idletime >= cpuData->idleTime); + assert (totaltime >= cpuData->totalTime); + assert (systemalltime >= cpuData->systemAllTime); + assert (idlealltime >= cpuData->idleAllTime); + assert (ioWait >= cpuData->ioWaitTime); + assert (irq >= cpuData->irqTime); + assert (softIrq >= cpuData->softIrqTime); + assert (steal >= cpuData->stealTime); + assert (guest >= cpuData->guestTime); + cpuData->userPeriod = usertime - cpuData->userTime; + cpuData->nicePeriod = nicetime - cpuData->niceTime; + cpuData->systemPeriod = systemtime - cpuData->systemTime; + cpuData->systemAllPeriod = systemalltime - cpuData->systemAllTime; + cpuData->idleAllPeriod = idlealltime - cpuData->idleAllTime; + cpuData->idlePeriod = idletime - cpuData->idleTime; + cpuData->ioWaitPeriod = ioWait - cpuData->ioWaitTime; + cpuData->irqPeriod = irq - cpuData->irqTime; + cpuData->softIrqPeriod = softIrq - cpuData->softIrqTime; + cpuData->stealPeriod = steal - cpuData->stealTime; + cpuData->guestPeriod = guest - cpuData->guestTime; + cpuData->totalPeriod = totaltime - cpuData->totalTime; + cpuData->userTime = usertime; + cpuData->niceTime = nicetime; + cpuData->systemTime = systemtime; + cpuData->systemAllTime = systemalltime; + cpuData->idleAllTime = idlealltime; + cpuData->idleTime = idletime; + cpuData->ioWaitTime = ioWait; + cpuData->irqTime = irq; + cpuData->softIrqTime = softIrq; + cpuData->stealTime = steal; + cpuData->guestTime = guest; + cpuData->totalTime = totaltime; } - float period = (float)this->totalPeriod[0] / processors; - 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++) { @@ -837,10 +775,14 @@ void ProcessList_scan(ProcessList* this) { } this->totalTasks = 0; + this->userlandThreads = 0; + this->kernelThreads = 0; this->runningTasks = 0; ProcessList_processEntries(this, PROCDIR, NULL, period); + this->showingThreadNames = this->showThreadNames; + for (int i = Vector_size(this->processes) - 1; i >= 0; i--) { Process* p = (Process*) Vector_get(this->processes, i); if (p->updated == false) @@ -864,3 +806,11 @@ ProcessField ProcessList_keyAt(ProcessList* this, int at) { } return COMM; } + +void ProcessList_expandTree(ProcessList* this) { + int size = Vector_size(this->processes); + for (int i = 0; i < size; i++) { + Process* process = (Process*) Vector_get(this->processes, i); + process->showChildren = true; + } +} -- cgit v1.2.3