summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Action.c59
-rw-r--r--Action.h42
-rw-r--r--CRT.c27
-rw-r--r--CRT.h5
-rw-r--r--Makefile.am36
-rw-r--r--Process.c48
-rw-r--r--Process.h21
-rw-r--r--ProcessList.c684
-rw-r--r--ProcessList.h45
-rw-r--r--RichString.c2
-rw-r--r--configure.ac36
-rw-r--r--htop.c99
-rw-r--r--htop.h25
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
diff --git a/CRT.c b/CRT.c
index 14a30d0f..c06c3caf 100644
--- a/CRT.c
+++ b/CRT.c
@@ -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();
diff --git a/CRT.h b/CRT.h
index 260d0874..b77a83a7 100644
--- a/CRT.h
+++ b/CRT.h
@@ -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
+
diff --git a/Process.c b/Process.c
index 5501b3e9..dd08521b 100644
--- a/Process.c
+++ b/Process.c
@@ -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);
}
diff --git a/Process.h b/Process.h
index 87196eee..c4ef808d 100644
--- a/Process.h
+++ b/Process.h
@@ -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);