diff options
-rw-r--r-- | Action.c | 59 | ||||
-rw-r--r-- | Action.h | 42 | ||||
-rw-r--r-- | CRT.c | 27 | ||||
-rw-r--r-- | CRT.h | 5 | ||||
-rw-r--r-- | Makefile.am | 36 | ||||
-rw-r--r-- | Process.c | 48 | ||||
-rw-r--r-- | Process.h | 21 | ||||
-rw-r--r-- | ProcessList.c | 684 | ||||
-rw-r--r-- | ProcessList.h | 45 | ||||
-rw-r--r-- | RichString.c | 2 | ||||
-rw-r--r-- | configure.ac | 36 | ||||
-rw-r--r-- | htop.c | 99 | ||||
-rw-r--r-- | htop.h | 25 |
13 files changed, 210 insertions, 919 deletions
diff --git a/Action.c b/Action.c new file mode 100644 index 00000000..23f0c840 --- /dev/null +++ b/Action.c @@ -0,0 +1,59 @@ +/* +htop - Action.c +(C) 2014 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. +*/ + +#include "Process.h" +#include "Panel.h" +#include "Action.h" + +/*{ + +#include "IncSet.h" +#include "Settings.h" +#include "UsersTable.h" + +typedef enum { + HTOP_OK = 0x00, + HTOP_REFRESH = 0x01, + HTOP_RECALCULATE = 0x03, // implies HTOP_REFRESH + HTOP_SAVE_SETTINGS = 0x04, + HTOP_KEEP_FOLLOWING = 0x08, + HTOP_QUIT = 0x10, + HTOP_REDRAW_BAR = 0x20, + HTOP_UPDATE_PANELHDR = 0x41, // implies HTOP_REFRESH +} Htop_Reaction; + +typedef Htop_Reaction (*Htop_Action)(); + +typedef struct State_ { + IncSet* inc; + Settings* settings; + UsersTable* ut; +} State; + +typedef bool(*Action_ForeachProcessFn)(Process*, size_t); + +}*/ + +bool Action_foreachProcess(Panel* panel, Action_ForeachProcessFn fn, int arg, bool* wasAnyTagged) { + bool ok = true; + bool anyTagged = false; + for (int i = 0; i < Panel_size(panel); i++) { + Process* p = (Process*) Panel_get(panel, i); + if (p->tag) { + ok = fn(p, arg) && ok; + anyTagged = true; + } + } + if (!anyTagged) { + Process* p = (Process*) Panel_getSelected(panel); + if (p) ok = fn(p, arg) && ok; + } + if (wasAnyTagged) + *wasAnyTagged = anyTagged; + return ok; +} + diff --git a/Action.h b/Action.h new file mode 100644 index 00000000..5a2ce1ce --- /dev/null +++ b/Action.h @@ -0,0 +1,42 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_Action +#define HEADER_Action +/* +htop - Action.h +(C) 2014 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. +*/ + + +#include "IncSet.h" +#include "Settings.h" +#include "UsersTable.h" + +typedef enum { + HTOP_OK = 0x00, + HTOP_REFRESH = 0x01, + HTOP_RECALCULATE = 0x03, // implies HTOP_REFRESH + HTOP_SAVE_SETTINGS = 0x04, + HTOP_KEEP_FOLLOWING = 0x08, + HTOP_QUIT = 0x10, + HTOP_REDRAW_BAR = 0x20, + HTOP_UPDATE_PANELHDR = 0x41, // implies HTOP_REFRESH +} Htop_Reaction; + +typedef Htop_Reaction (*Htop_Action)(); + +typedef struct State_ { + IncSet* inc; + Settings* settings; + UsersTable* ut; +} State; + +typedef bool(*Action_ForeachProcessFn)(Process*, size_t); + + +bool Action_foreachProcess(Panel* panel, Action_ForeachProcessFn fn, int arg, bool* wasAnyTagged); + + +#endif @@ -7,7 +7,6 @@ in the source distribution for its full text. #include "CRT.h" -#include "config.h" #include "String.h" #include "RichString.h" @@ -16,9 +15,6 @@ in the source distribution for its full text. #include <signal.h> #include <stdlib.h> #include <string.h> -#ifdef HAVE_EXECINFO_H -#include <execinfo.h> -#endif #define ColorPair(i,j) COLOR_PAIR((7-i)*8+j) @@ -112,6 +108,8 @@ typedef enum ColorElements_ { void CRT_fatalError(const char* note) __attribute__ ((noreturn)); +void CRT_handleSIGSEGV(int sgn); + }*/ // TODO: centralize these in Settings. @@ -134,27 +132,6 @@ char* CRT_termType; void *backtraceArray[128]; -static void CRT_handleSIGSEGV(int sgn) { - (void) sgn; - CRT_done(); - #if __linux - fprintf(stderr, "\n\nhtop " VERSION " aborting. Please report bug at http://hisham.hm/htop\n"); - #ifdef HAVE_EXECINFO_H - size_t size = backtrace(backtraceArray, sizeof(backtraceArray) / sizeof(void *)); - fprintf(stderr, "\n Please include in your report the following backtrace: \n"); - backtrace_symbols_fd(backtraceArray, size, 2); - fprintf(stderr, "\nAdditionally, in order to make the above backtrace useful,"); - fprintf(stderr, "\nplease also run the following command to generate a disassembly of your binary:"); - fprintf(stderr, "\n\n objdump -d `which htop` > ~/htop.objdump"); - fprintf(stderr, "\n\nand then attach the file ~/htop.objdump to your bug report."); - fprintf(stderr, "\n\nThank you for helping to improve htop!\n\n"); - #endif - #else - fprintf(stderr, "\n\nhtop " VERSION " aborting. Unsupported platform.\n"); - #endif - abort(); -} - static void CRT_handleSIGTERM(int sgn) { (void) sgn; CRT_done(); @@ -9,9 +9,6 @@ Released under the GNU GPL, see the COPYING file in the source distribution for its full text. */ -#ifdef HAVE_EXECINFO_H -#endif - #define ColorPair(i,j) COLOR_PAIR((7-i)*8+j) #define COLORSCHEME_DEFAULT 0 @@ -103,6 +100,8 @@ typedef enum ColorElements_ { void CRT_fatalError(const char* note) __attribute__ ((noreturn)); +void CRT_handleSIGSEGV(int sgn); + // TODO: centralize these in Settings. diff --git a/Makefile.am b/Makefile.am index 820e2e54..9eb31a79 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,9 @@ ACLOCAL_AMFLAGS = -I m4 +AUTOMAKE_OPTIONS = subdir-objects bin_PROGRAMS = htop + dist_man_MANS = htop.1 EXTRA_DIST = $(dist_man_MANS) htop.desktop htop.png scripts/MakeHeader.py \ install-sh autogen.sh missing @@ -10,7 +12,7 @@ applications_DATA = htop.desktop pixmapdir = $(datadir)/pixmaps pixmap_DATA = htop.png -htop_CFLAGS = -pedantic -Wall -Wextra -std=c99 -rdynamic -D_XOPEN_SOURCE_EXTENDED -DSYSCONFDIR=\"$(sysconfdir)\" +htop_CFLAGS = -pedantic -Wall -Wextra -std=c99 -rdynamic -D_XOPEN_SOURCE_EXTENDED -DSYSCONFDIR=\"$(sysconfdir)\" -I"$(my_htop_platform)" AM_CPPFLAGS = -DNDEBUG myhtopsources = AvailableMetersPanel.c CategoriesPanel.c CheckItem.c \ @@ -18,23 +20,42 @@ ClockMeter.c ColorsPanel.c ColumnsPanel.c CPUMeter.c CRT.c \ DisplayOptionsPanel.c FunctionBar.c Hashtable.c Header.c htop.c ListItem.c \ LoadAverageMeter.c MemoryMeter.c Meter.c MetersPanel.c Object.c Panel.c \ BatteryMeter.c Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \ -IOPriorityPanel.c SignalsPanel.c String.c SwapMeter.c TasksMeter.c TraceScreen.c \ +SignalsPanel.c String.c SwapMeter.c TasksMeter.c TraceScreen.c \ UptimeMeter.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c \ -HostnameMeter.c OpenFilesScreen.c Affinity.c IOPriority.c IncSet.c +HostnameMeter.c OpenFilesScreen.c Affinity.c IncSet.c Action.c myhtopheaders = AvailableColumnsPanel.h AvailableMetersPanel.h \ CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.h \ -IOPriorityPanel.h CPUMeter.h CRT.h DisplayOptionsPanel.h FunctionBar.h \ +CPUMeter.h CRT.h DisplayOptionsPanel.h FunctionBar.h \ Hashtable.h Header.h htop.h ListItem.h LoadAverageMeter.h MemoryMeter.h \ BatteryMeter.h Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \ ScreenManager.h Settings.h SignalsPanel.h String.h SwapMeter.h TasksMeter.h \ TraceScreen.h UptimeMeter.h UsersTable.h Vector.h Process.h AffinityPanel.h \ -HostnameMeter.h OpenFilesScreen.h Affinity.h IOPriority.h IncSet.h +HostnameMeter.h OpenFilesScreen.h Affinity.h IncSet.h Action.h + +if HTOP_LINUX +myhtopplatsources = linux/Platform.c linux/IOPriorityPanel.c linux/IOPriority.c \ +linux/LinuxProcessList.c linux/LinuxCRT.c + +myhtopplatheaders = linux/Platform.h linux/IOPriorityPanel.h linux/IOPriority.h \ +linux/LinuxProcessList.h linux/LinuxCRT.h +endif + +if HTOP_UNSUPPORTED +myhtopplatsources = unsupported/Platform.c unsupported/UnsupportedProcessList.c \ +unsupported/UnsupportedCRT.c + +myhtopplatheaders = unsupported/Platform.h unsupported/UnsupportedProcessList.h \ +unsupported/UnsupportedCRT.h +endif SUFFIXES = .h -BUILT_SOURCES = $(myhtopheaders) -htop_SOURCES = $(myhtopheaders) $(myhtopsources) config.h +BUILT_SOURCES = $(myhtopheaders) $(myhtopplatheaders) +htop_SOURCES = $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources) config.h + +target: + echo $(htop_SOURCES) profile: $(MAKE) all CFLAGS="-pg" AM_CPPFLAGS="-pg -O2 -DNDEBUG" @@ -47,3 +68,4 @@ debug: cppcheck: cppcheck -q -v . --enable=all -DHAVE_CGROUP -DHAVE_OPENVZ -DHAVE_TASKSTATS + @@ -1,6 +1,6 @@ /* htop - Process.c -(C) 2004-2011 Hisham H. Muhammad +(C) 2004-2014 Hisham H. Muhammad Released under the GNU GPL, see the COPYING file in the source distribution for its full text. */ @@ -32,7 +32,7 @@ in the source distribution for its full text. #include <hwloc/linux.h> #endif -// This works only with glibc 2.1+. On earlier versions +// On Linux, this works only with glibc 2.1+. On earlier versions // the behavior is similar to have a hardcoded page size. #ifndef PAGE_SIZE #define PAGE_SIZE ( sysconf(_SC_PAGESIZE) ) @@ -42,7 +42,7 @@ in the source distribution for its full text. /*{ #include "Object.h" #include "Affinity.h" -#include "IOPriority.h" + #include <sys/types.h> #define PROCESS_FLAG_IO 1 @@ -122,7 +122,6 @@ typedef struct Process_ { long int priority; long int nice; long int nlwp; - IOPriority ioPriority; char starttime_show[8]; time_t starttime_ctime; @@ -628,24 +627,6 @@ static void Process_writeField(Process* this, RichString* str, ProcessField fiel #ifdef HAVE_OOM case OOM: snprintf(buffer, n, Process_pidFormat, this->oom); break; #endif - case IO_PRIORITY: { - int klass = IOPriority_class(this->ioPriority); - if (klass == IOPRIO_CLASS_NONE) { - // see note [1] above - snprintf(buffer, n, "B%1d ", (int) (this->nice + 20) / 5); - } else if (klass == IOPRIO_CLASS_BE) { - snprintf(buffer, n, "B%1d ", IOPriority_data(this->ioPriority)); - } else if (klass == IOPRIO_CLASS_RT) { - attr = CRT_colors[PROCESS_HIGH_PRIORITY]; - snprintf(buffer, n, "R%1d ", IOPriority_data(this->ioPriority)); - } else if (this->ioPriority == IOPriority_Idle) { - attr = CRT_colors[PROCESS_LOW_PRIORITY]; - snprintf(buffer, n, "id "); - } else { - snprintf(buffer, n, "?? "); - } - break; - } default: snprintf(buffer, n, "- "); } @@ -720,27 +701,6 @@ bool Process_changePriorityBy(Process* this, size_t delta) { return Process_setPriority(this, this->nice + delta); } -IOPriority Process_updateIOPriority(Process* this) { - IOPriority ioprio = syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, this->pid); - this->ioPriority = ioprio; - return ioprio; -} - -bool Process_setIOPriority(Process* this, IOPriority ioprio) { - syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, this->pid, ioprio); - return (Process_updateIOPriority(this) == ioprio); -} - -/* -[1] Note that before kernel 2.6.26 a process that has not asked for -an io priority formally uses "none" as scheduling class, but the -io scheduler will treat such processes as if it were in the best -effort class. The priority within the best effort class will be -dynamically derived from the cpu nice level of the process: -io_priority = (cpu_nice + 20) / 5. -- From ionice(1) man page -*/ -#define Process_effectiveIOPriority(p_) (IOPriority_class(p_->ioPriority) == IOPRIO_CLASS_NONE ? IOPriority_tuple(IOPRIO_CLASS_BE, (p_->nice + 20) / 5) : p_->ioPriority) - #ifdef HAVE_LIBHWLOC Affinity* Process_getAffinity(Process* this) { @@ -902,8 +862,6 @@ long Process_compare(const void* v1, const void* v2) { case OOM: return (p1->oom - p2->oom); #endif - case IO_PRIORITY: - return Process_effectiveIOPriority(p1) - Process_effectiveIOPriority(p2); default: return (p1->pid - p2->pid); } @@ -4,7 +4,7 @@ #define HEADER_Process /* htop - Process.h -(C) 2004-2011 Hisham H. Muhammad +(C) 2004-2014 Hisham H. Muhammad Released under the GNU GPL, see the COPYING file in the source distribution for its full text. */ @@ -12,7 +12,7 @@ in the source distribution for its full text. #ifdef HAVE_LIBHWLOC #endif -// This works only with glibc 2.1+. On earlier versions +// On Linux, this works only with glibc 2.1+. On earlier versions // the behavior is similar to have a hardcoded page size. #ifndef PAGE_SIZE #define PAGE_SIZE ( sysconf(_SC_PAGESIZE) ) @@ -21,7 +21,7 @@ in the source distribution for its full text. #include "Object.h" #include "Affinity.h" -#include "IOPriority.h" + #include <sys/types.h> #define PROCESS_FLAG_IO 1 @@ -101,7 +101,6 @@ typedef struct Process_ { long int priority; long int nice; long int nlwp; - IOPriority ioPriority; char starttime_show[8]; time_t starttime_ctime; @@ -202,20 +201,6 @@ bool Process_setPriority(Process* this, int priority); bool Process_changePriorityBy(Process* this, size_t delta); -IOPriority Process_updateIOPriority(Process* this); - -bool Process_setIOPriority(Process* this, IOPriority ioprio); - -/* -[1] Note that before kernel 2.6.26 a process that has not asked for -an io priority formally uses "none" as scheduling class, but the -io scheduler will treat such processes as if it were in the best -effort class. The priority within the best effort class will be -dynamically derived from the cpu nice level of the process: -extern io_priority; -*/ -#define Process_effectiveIOPriority(p_) (IOPriority_class(p_->ioPriority) == IOPRIO_CLASS_NONE ? IOPriority_tuple(IOPRIO_CLASS_BE, (p_->nice + 20) / 5) : p_->ioPriority) - #ifdef HAVE_LIBHWLOC Affinity* Process_getAffinity(Process* this); diff --git a/ProcessList.c b/ProcessList.c index 7841e0a3..16a52a59 100644 --- a/ProcessList.c +++ b/ProcessList.c @@ -35,18 +35,6 @@ in the source distribution for its full text. #include "Panel.h" #include "Process.h" -#ifndef PROCDIR -#define PROCDIR "/proc" -#endif - -#ifndef PROCSTATFILE -#define PROCSTATFILE PROCDIR "/stat" -#endif - -#ifndef PROCMEMINFOFILE -#define PROCMEMINFOFILE PROCDIR "/meminfo" -#endif - #ifndef MAX_NAME #define MAX_NAME 128 #endif @@ -155,6 +143,9 @@ typedef struct ProcessList_ { } ProcessList; +ProcessList* ProcessList_new(UsersTable* ut, Hashtable* pidWhiteList); +void ProcessList_scan(ProcessList* pl); + }*/ static ProcessField defaultHeaders[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 }; @@ -179,45 +170,18 @@ const char *ProcessList_treeStrUtf8[TREE_STR_COUNT] = { "\xe2\x94\x80", // TREE_STR_SHUT ─ }; -static ssize_t xread(int fd, void *buf, size_t count) { - // Read some bytes. Retry on EINTR and when we don't get as many bytes as we requested. - size_t alreadyRead = 0; - for(;;) { - ssize_t res = read(fd, buf, count); - if (res == -1 && errno == EINTR) continue; - if (res > 0) { - buf = ((char*)buf)+res; - count -= res; - alreadyRead += res; - } - if (res == -1) return -1; - if (count == 0 || res == 0) return alreadyRead; - } -} - -ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList) { - ProcessList* this; - this = calloc(1, sizeof(ProcessList)); +ProcessList* ProcessList_init(ProcessList* this, UsersTable* usersTable, Hashtable* pidWhiteList) { this->processes = Vector_new(Class(Process), true, DEFAULT_SIZE); this->processTable = Hashtable_new(140, false); this->usersTable = usersTable; this->pidWhiteList = pidWhiteList; - /* tree-view auxiliary buffers */ + // tree-view auxiliary buffers this->processes2 = Vector_new(Class(Process), true, DEFAULT_SIZE); - FILE* file = fopen(PROCSTATFILE, "r"); - if (file == NULL) { - CRT_fatalError("Cannot open " PROCSTATFILE); - } - char buffer[256]; - int cpus = -1; - do { - cpus++; - fgets(buffer, 255, file); - } while (String_startsWith(buffer, "cpu")); - fclose(file); - this->cpuCount = MAX(cpus - 1, 1); + // set later by platform-specific code + this->cpuCount = 0; + this->cpus = NULL; #ifdef HAVE_LIBHWLOC this->topologyOk = false; @@ -229,12 +193,6 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList) { this->topologyOk = true; } #endif - this->cpus = calloc(cpus, sizeof(CPUData)); - - for (int i = 0; i < cpus; i++) { - this->cpus[i].totalTime = 1; - this->cpus[i].totalPeriod = 1; - } this->fields = calloc(LAST_PROCESSFIELD+1, sizeof(ProcessField)); // TODO: turn 'fields' into a Vector, @@ -245,10 +203,6 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList) { this->flags |= Process_fieldFlags[defaultHeaders[i]]; } - #ifdef HAVE_OPENVZ - this->flags |= PROCESS_FLAG_OPENVZ; - #endif - this->sortKey = PERCENT_CPU; this->direction = 1; this->hideThreads = false; @@ -304,7 +258,7 @@ void ProcessList_printHeader(ProcessList* this, RichString* header) { } } -static void ProcessList_add(ProcessList* this, Process* p) { +void ProcessList_add(ProcessList* this, Process* p) { assert(Vector_indexOf(this->processes, p, Process_pidCompare) == -1); assert(Hashtable_get(this->processTable, p->pid) == NULL); @@ -316,7 +270,7 @@ static void ProcessList_add(ProcessList* this, Process* p) { assert(Hashtable_count(this->processTable) == Vector_count(this->processes)); } -static void ProcessList_remove(ProcessList* this, Process* p) { +void ProcessList_remove(ProcessList* this, Process* p) { assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1); assert(Hashtable_get(this->processTable, p->pid) != NULL); Process* pp = Hashtable_remove(this->processTable, p->pid); @@ -385,6 +339,7 @@ void ProcessList_sort(ProcessList* this) { // Take PID 1 as root and add to the new listing int vsize = Vector_size(this->processes); Process* init = (Process*) (Vector_take(this->processes, 0)); + if (!init) return; // This assertion crashes on hardened kernels. // I wonder how well tree view works on those systems. // assert(init->pid == 1); @@ -408,622 +363,6 @@ void ProcessList_sort(ProcessList* this) { } } -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); - int fd = open(filename, O_RDONLY); - if (fd == -1) - return false; - - static char buf[MAX_READ+1]; - - int size = xread(fd, buf, MAX_READ); - close(fd); - if (size <= 0) return false; - buf[size] = '\0'; - - assert(process->pid == atoi(buf)); - char *location = strchr(buf, ' '); - if (!location) return false; - - location += 2; - char *end = strrchr(location, ')'); - if (!end) return false; - - int commsize = end - location; - memcpy(command, location, commsize); - command[commsize] = '\0'; - location = end + 2; - - process->state = location[0]; - location += 2; - process->ppid = strtol(location, &location, 10); - location += 1; - process->pgrp = strtoul(location, &location, 10); - location += 1; - process->session = strtoul(location, &location, 10); - location += 1; - process->tty_nr = strtoul(location, &location, 10); - location += 1; - process->tpgid = strtol(location, &location, 10); - location += 1; - process->flags = strtoul(location, &location, 10); - location += 1; - process->minflt = strtoull(location, &location, 10); - location += 1; - process->cminflt = strtoull(location, &location, 10); - location += 1; - process->majflt = strtoull(location, &location, 10); - location += 1; - process->cmajflt = strtoull(location, &location, 10); - location += 1; - process->utime = strtoull(location, &location, 10); - location += 1; - process->stime = strtoull(location, &location, 10); - location += 1; - process->cutime = strtoull(location, &location, 10); - location += 1; - process->cstime = strtoull(location, &location, 10); - location += 1; - process->priority = strtol(location, &location, 10); - location += 1; - process->nice = strtol(location, &location, 10); - location += 1; - process->nlwp = strtol(location, &location, 10); - location += 1; - for (int i=0; i<17; i++) location = strchr(location, ' ')+1; - process->exit_signal = strtol(location, &location, 10); - location += 1; - assert(location != NULL); - process->processor = strtol(location, &location, 10); - assert(location == NULL); - - return true; -} - -static bool ProcessList_statProcessDir(Process* process, const char* dirname, char* name, time_t curTime) { - char filename[MAX_NAME+1]; - filename[MAX_NAME] = '\0'; - - snprintf(filename, MAX_NAME, "%s/%s", dirname, name); - struct stat sstat; - int statok = stat(filename, &sstat); - if (statok == -1) - return false; - 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 > curTime - 86400) ? "%R " : "%b%d "), &date); - - return true; -} - -#ifdef HAVE_TASKSTATS - -static void ProcessList_readIoFile(Process* process, const char* dirname, char* name, unsigned long long now) { - char filename[MAX_NAME+1]; - filename[MAX_NAME] = '\0'; - - snprintf(filename, MAX_NAME, "%s/%s/io", dirname, name); - int fd = open(filename, O_RDONLY); - if (fd == -1) - return; - - char buffer[1024]; - ssize_t buflen = xread(fd, buffer, 1023); - close(fd); - if (buflen < 1) return; - buffer[buflen] = '\0'; - unsigned long long last_read = process->io_read_bytes; - unsigned long long last_write = process->io_write_bytes; - char *buf = buffer; - char *line = NULL; - while ((line = strsep(&buf, "\n")) != NULL) { - switch (line[0]) { - case 'r': - if (line[1] == 'c' && strncmp(line+2, "har: ", 5) == 0) - process->io_rchar = strtoull(line+7, NULL, 10); - else if (strncmp(line+1, "ead_bytes: ", 11) == 0) { - process->io_read_bytes = strtoull(line+12, NULL, 10); - 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; - } - break; - case 'w': - if (line[1] == 'c' && strncmp(line+2, "har: ", 5) == 0) - process->io_wchar = strtoull(line+7, NULL, 10); - else if (strncmp(line+1, "rite_bytes: ", 12) == 0) { - process->io_write_bytes = strtoull(line+13, NULL, 10); - 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; - } - break; - case 's': - if (line[5] == 'r' && strncmp(line+1, "yscr: ", 6) == 0) - process->io_syscr = strtoull(line+7, NULL, 10); - else if (strncmp(line+1, "yscw: ", 6) == 0) - sscanf(line, "syscw: %32llu", &process->io_syscw); - process->io_syscw = strtoull(line+7, NULL, 10); - break; - case 'c': - if (strncmp(line+1, "ancelled_write_bytes: ", 22) == 0) - process->io_cancelled_write_bytes = strtoull(line+23, NULL, 10); - } - } -} - -#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); - int fd = open(filename, O_RDONLY); - if (fd == -1) - return false; - char buf[256]; - ssize_t rres = xread(fd, buf, 255); - close(fd); - if (rres < 1) return false; - - char *p = buf; - errno = 0; - process->m_size = strtol(p, &p, 10); if (*p == ' ') p++; - process->m_resident = strtol(p, &p, 10); if (*p == ' ') p++; - process->m_share = strtol(p, &p, 10); if (*p == ' ') p++; - process->m_trs = strtol(p, &p, 10); if (*p == ' ') p++; - process->m_lrs = strtol(p, &p, 10); if (*p == ' ') p++; - process->m_drs = strtol(p, &p, 10); if (*p == ' ') p++; - process->m_dt = strtol(p, &p, 10); - return (errno == 0); -} - -#ifdef HAVE_OPENVZ - -static void ProcessList_readOpenVZData(ProcessList* this, Process* process, const char* dirname, const char* name) { - if ( (!(this->flags & PROCESS_FLAG_OPENVZ)) || (access("/proc/vz", R_OK) != 0)) { - process->vpid = process->pid; - process->ctid = 0; - this->flags |= ~PROCESS_FLAG_OPENVZ; - 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, - "%*32u %*32s %*1c %*32u %*32u %*32u %*32u %*32u %*32u %*32u " - "%*32u %*32u %*32u %*32u %*32u %*32u %*32u %*32u " - "%*32u %*32u %*32u %*32u %*32u %*32u %*32u %*32u " - "%*32u %*32u %*32u %*32u %*32u %*32u %*32u %*32u " - "%*32u %*32u %*32u %*32u %*32u %*32u %*32u %*32u " - "%*32u %*32u %*32u %*32u %*32u %*32u %*32u " - "%*32u %*32u %32u %32u", - &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); - int nFields; - char** fields = String_split(trimmed, ':', &nFields); - free(trimmed); - if (nFields >= 3) { - process->cgroup = strndup(fields[2] + 1, 10); - } else { - process->cgroup = strdup(""); - } - 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%32d", &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%32d", &vxid); - if (ok >= 1) { - process->vxid = vxid; - } - } - #endif - } - fclose(file); -} - -#endif - -#ifdef HAVE_OOM - -static void ProcessList_readOomData(Process* process, const char* dirname, const char* name) { - char filename[MAX_NAME+1]; - snprintf(filename, MAX_NAME, "%s/%s/oom_score", dirname, name); - FILE* file = fopen(filename, "r"); - if (!file) - return; - char buffer[256]; - if (fgets(buffer, 255, file)) { - unsigned int oom; - int ok = sscanf(buffer, "%32u", &oom); - if (ok >= 1) { - process->oom = oom; - } - } - 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); - int fd = open(filename, O_RDONLY); - if (fd == -1) - return false; - - char command[4096+1]; // max cmdline length on Linux - int amtRead = xread(fd, command, sizeof(command) - 1); - close(fd); - int tokenEnd = 0; - if (amtRead > 0) { - for (int i = 0; i < amtRead; i++) - if (command[i] == '\0' || command[i] == '\n') { - if (tokenEnd == 0) { - tokenEnd = i; - } - command[i] = ' '; - } - } - if (tokenEnd == 0) { - tokenEnd = amtRead; - } - command[amtRead] = '\0'; - free(process->comm); - process->comm = strdup(command); - process->basenameOffset = tokenEnd; - - return true; -} - - -static bool ProcessList_processEntries(ProcessList* this, const char* dirname, Process* parent, double period, struct timeval tv) { - DIR* dir; - struct dirent* entry; - - time_t curTime = tv.tv_sec; - #ifdef HAVE_TASKSTATS - unsigned long long now = tv.tv_sec*1000LL+tv.tv_usec/1000LL; - #endif - - dir = opendir(dirname); - if (!dir) return false; - int cpus = this->cpuCount; - bool hideKernelThreads = this->hideKernelThreads; - bool hideUserlandThreads = this->hideUserlandThreads; - while ((entry = readdir(dir)) != NULL) { - char* name = entry->d_name; - - // The RedHat kernel hides threads with a dot. - // I believe this is non-standard. - if ((!this->hideThreads) && name[0] == '.') { - name++; - } - - // Just skip all non-number directories. - if (name[0] < '0' || name[0] > '9') { - continue; - } - - // filename is a number: process directory - int pid = atoi(name); - - if (parent && pid == parent->pid) - continue; - - if (pid <= 0) - continue; - - 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, tv); - - #ifdef HAVE_TASKSTATS - if (this->flags & PROCESS_FLAG_IO) - ProcessList_readIoFile(process, dirname, name, now); - #endif - - if (! ProcessList_readStatmFile(process, dirname, name)) - goto errorReadingProcess; - - process->show = ! ((hideKernelThreads && Process_isKernelThread(process)) || (hideUserlandThreads && Process_isUserlandThread(process))); - - char command[MAX_NAME+1]; - unsigned long long int lasttimes = (process->utime + process->stime); - if (! ProcessList_readStatFile(process, dirname, name, command)) - goto errorReadingProcess; - if (this->flags & PROCESS_FLAG_IOPRIO) - Process_updateIOPriority(process); - float 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) / (double)(this->totalMem) * 100.0; - - if(!existingProcess) { - - if (! ProcessList_statProcessDir(process, dirname, name, curTime)) - goto errorReadingProcess; - - process->user = UsersTable_getRef(this->usersTable, process->st_uid); - - #ifdef HAVE_OPENVZ - ProcessList_readOpenVZData(this, process, dirname, name); - #endif - - #ifdef HAVE_VSERVER - if (this->flags & PROCESS_FLAG_VSERVER) - ProcessList_readVServerData(process, dirname, name); - #endif - - if (! ProcessList_readCmdlineFile(process, dirname, name)) - goto errorReadingProcess; - - ProcessList_add(this, process); - } else { - if (this->updateProcessNames) { - if (! ProcessList_readCmdlineFile(process, dirname, name)) - goto errorReadingProcess; - } - } - - #ifdef HAVE_CGROUP - if (this->flags & PROCESS_FLAG_CGROUP) - ProcessList_readCGroupFile(process, dirname, name); - #endif - - #ifdef HAVE_OOM - ProcessList_readOomData(process, dirname, name); - #endif - - if (process->state == 'Z') { - free(process->comm); |