aboutsummaryrefslogtreecommitdiffstats
path: root/linux
diff options
context:
space:
mode:
authorGraham Inggs <ginggs@debian.org>2018-02-05 14:48:51 +0200
committerGraham Inggs <ginggs@debian.org>2018-02-05 14:48:51 +0200
commit2ee50d030178cede83eb9d0005fbc19f819d30fe (patch)
tree67d75c0a7c47e15bed9d0735ecf12abec4f8157b /linux
parent31b71b67011fa52f091df6fe536a11d6d0bfb256 (diff)
downloaddebian_htop-2ee50d030178cede83eb9d0005fbc19f819d30fe.tar.gz
debian_htop-2ee50d030178cede83eb9d0005fbc19f819d30fe.tar.bz2
debian_htop-2ee50d030178cede83eb9d0005fbc19f819d30fe.zip
Imported Upstream version 2.1.0upstream/2.1.0
Diffstat (limited to 'linux')
-rw-r--r--linux/Battery.c53
-rw-r--r--linux/Battery.h7
-rw-r--r--linux/IOPriority.c2
-rw-r--r--linux/IOPriority.h2
-rw-r--r--linux/IOPriorityPanel.c4
-rw-r--r--linux/LinuxProcess.c85
-rw-r--r--linux/LinuxProcess.h21
-rw-r--r--linux/LinuxProcessList.c349
-rw-r--r--linux/LinuxProcessList.h33
-rw-r--r--linux/Platform.c6
-rw-r--r--linux/Platform.h4
11 files changed, 454 insertions, 112 deletions
diff --git a/linux/Battery.c b/linux/Battery.c
index 1068184..34a2401 100644
--- a/linux/Battery.c
+++ b/linux/Battery.c
@@ -41,11 +41,9 @@ static unsigned long int parseBatInfo(const char *fileName, const unsigned short
unsigned int nBatteries = 0;
memset(batteries, 0, MAX_BATTERIES * sizeof(char*));
- struct dirent result;
- struct dirent* dirEntry;
while (nBatteries < MAX_BATTERIES) {
- int err = readdir_r(batteryDir, &result, &dirEntry);
- if (err || !dirEntry)
+ struct dirent* dirEntry = readdir(batteryDir);
+ if (!dirEntry)
break;
char* entryName = dirEntry->d_name;
if (strncmp(entryName, "BAT", 3))
@@ -58,7 +56,7 @@ static unsigned long int parseBatInfo(const char *fileName, const unsigned short
unsigned long int total = 0;
for (unsigned int i = 0; i < nBatteries; i++) {
char infoPath[30];
- snprintf(infoPath, sizeof infoPath, "%s%s/%s", batteryPath, batteries[i], fileName);
+ xSnprintf(infoPath, sizeof infoPath, "%s%s/%s", batteryPath, batteries[i], fileName);
FILE* file = fopen(infoPath, "r");
if (!file) {
@@ -74,6 +72,8 @@ static unsigned long int parseBatInfo(const char *fileName, const unsigned short
fclose(file);
+ if (!line) break;
+
char *foundNumStr = String_getToken(line, wordNum);
const unsigned long int foundNum = atoi(foundNumStr);
free(foundNumStr);
@@ -97,11 +97,9 @@ static ACPresence procAcpiCheck() {
return AC_ERROR;
}
- struct dirent result;
- struct dirent* dirEntry;
for (;;) {
- int err = readdir_r((DIR *) dir, &result, &dirEntry);
- if (err || !dirEntry)
+ struct dirent* dirEntry = readdir((DIR *) dir);
+ if (!dirEntry)
break;
char* entryName = (char *) dirEntry->d_name;
@@ -110,7 +108,7 @@ static ACPresence procAcpiCheck() {
continue;
char statePath[50];
- snprintf((char *) statePath, sizeof statePath, "%s/%s/state", power_supplyPath, entryName);
+ xSnprintf((char *) statePath, sizeof statePath, "%s/%s/state", power_supplyPath, entryName);
FILE* file = fopen(statePath, "r");
if (!file) {
@@ -179,25 +177,6 @@ static inline ssize_t xread(int fd, void *buf, size_t count) {
}
}
-/**
- * Returns a pointer to the suffix of `str` if its beginning matches `prefix`.
- * Returns NULL if the prefix does not match.
- * Examples:
- * match("hello world", "hello "); -> "world"
- * match("hello world", "goodbye "); -> NULL
- */
-static inline const char* match(const char* str, const char* prefix) {
- for (;;) {
- if (*prefix == '\0') {
- return str;
- }
- if (*prefix != *str) {
- return NULL;
- }
- prefix++; str++;
- }
-}
-
static void Battery_getSysData(double* level, ACPresence* isOnAC) {
*level = 0;
@@ -210,18 +189,16 @@ static void Battery_getSysData(double* level, ACPresence* isOnAC) {
unsigned long int totalFull = 0;
unsigned long int totalRemain = 0;
- struct dirent result;
- struct dirent* dirEntry;
for (;;) {
- int err = readdir_r((DIR *) dir, &result, &dirEntry);
- if (err || !dirEntry)
+ struct dirent* dirEntry = readdir((DIR *) dir);
+ if (!dirEntry)
break;
char* entryName = (char *) dirEntry->d_name;
const char filePath[50];
if (entryName[0] == 'B' && entryName[1] == 'A' && entryName[2] == 'T') {
- snprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/uevent", entryName);
+ xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/uevent", entryName);
int fd = open(filePath, O_RDONLY);
if (fd == -1) {
closedir(dir);
@@ -240,6 +217,8 @@ static void Battery_getSysData(double* level, ACPresence* isOnAC) {
bool full = false;
bool now = false;
while ((line = strsep(&buf, "\n")) != NULL) {
+ #define match(str,prefix) \
+ (String_startsWith(str,prefix) ? (str) + strlen(prefix) : NULL)
const char* ps = match(line, "POWER_SUPPLY_");
if (!ps) {
continue;
@@ -266,12 +245,13 @@ static void Battery_getSysData(double* level, ACPresence* isOnAC) {
continue;
}
}
+ #undef match
} else if (entryName[0] == 'A') {
if (*isOnAC != AC_ERROR) {
continue;
}
- snprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/online", entryName);
+ xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/online", entryName);
int fd = open(filePath, O_RDONLY);
if (fd == -1) {
closedir(dir);
@@ -326,6 +306,9 @@ void Battery_getData(double* level, ACPresence* isOnAC) {
*level = -1;
*isOnAC = AC_ERROR;
}
+ if (*level > 100.0) {
+ *level = 100.0;
+ }
Battery_cacheLevel = *level;
Battery_cacheIsOnAC = *isOnAC;
Battery_cacheTime = now;
diff --git a/linux/Battery.h b/linux/Battery.h
index 4cb22a8..cfb6c32 100644
--- a/linux/Battery.h
+++ b/linux/Battery.h
@@ -29,13 +29,6 @@ Linux battery readings written by Ian P. Hands (iphands@gmail.com, ihands@redhat
// READ FROM /sys
// ----------------------------------------
-/**
- * Returns a pointer to the suffix of `str` if its beginning matches `prefix`.
- * Returns NULL if the prefix does not match.
- * Examples:
- * match("hello world", "hello "); -> "world"
- * match("hello world", "goodbye "); -> NULL
- */
void Battery_getData(double* level, ACPresence* isOnAC);
#endif
diff --git a/linux/IOPriority.c b/linux/IOPriority.c
index 7b19743..dd7c84a 100644
--- a/linux/IOPriority.c
+++ b/linux/IOPriority.c
@@ -35,7 +35,7 @@ typedef int IOPriority;
#define IOPriority_error 0xffffffff
#define IOPriority_None IOPriority_tuple(IOPRIO_CLASS_NONE, 0)
-#define IOPriority_Idle IOPriority_tuple(IOPRIO_CLASS_IDLE, 0)
+#define IOPriority_Idle IOPriority_tuple(IOPRIO_CLASS_IDLE, 7)
}*/
diff --git a/linux/IOPriority.h b/linux/IOPriority.h
index d69e30d..148e344 100644
--- a/linux/IOPriority.h
+++ b/linux/IOPriority.h
@@ -36,7 +36,7 @@ typedef int IOPriority;
#define IOPriority_error 0xffffffff
#define IOPriority_None IOPriority_tuple(IOPRIO_CLASS_NONE, 0)
-#define IOPriority_Idle IOPriority_tuple(IOPRIO_CLASS_IDLE, 0)
+#define IOPriority_Idle IOPriority_tuple(IOPRIO_CLASS_IDLE, 7)
diff --git a/linux/IOPriorityPanel.c b/linux/IOPriorityPanel.c
index 9e12c75..2b315b8 100644
--- a/linux/IOPriorityPanel.c
+++ b/linux/IOPriorityPanel.c
@@ -19,7 +19,7 @@ Panel* IOPriorityPanel_new(IOPriority currPrio) {
Panel_setHeader(this, "IO Priority:");
Panel_add(this, (Object*) ListItem_new("None (based on nice)", IOPriority_None));
if (currPrio == IOPriority_None) Panel_setSelected(this, 0);
- struct { int klass; const char* name; } classes[] = {
+ static const struct { int klass; const char* name; } classes[] = {
{ .klass = IOPRIO_CLASS_RT, .name = "Realtime" },
{ .klass = IOPRIO_CLASS_BE, .name = "Best-effort" },
{ .klass = 0, .name = NULL }
@@ -27,7 +27,7 @@ Panel* IOPriorityPanel_new(IOPriority currPrio) {
for (int c = 0; classes[c].name; c++) {
for (int i = 0; i < 8; i++) {
char name[50];
- snprintf(name, sizeof(name)-1, "%s %d %s", classes[c].name, i, i == 0 ? "(High)" : (i == 7 ? "(Low)" : ""));
+ xSnprintf(name, sizeof(name)-1, "%s %d %s", classes[c].name, i, i == 0 ? "(High)" : (i == 7 ? "(Low)" : ""));
IOPriority ioprio = IOPriority_tuple(classes[c].klass, i);
Panel_add(this, (Object*) ListItem_new(name, ioprio));
if (currPrio == ioprio) Panel_setSelected(this, Panel_size(this) - 1);
diff --git a/linux/LinuxProcess.c b/linux/LinuxProcess.c
index 43b5e38..39b5647 100644
--- a/linux/LinuxProcess.c
+++ b/linux/LinuxProcess.c
@@ -81,7 +81,12 @@ typedef enum LinuxProcessFields {
#endif
OOM = 114,
IO_PRIORITY = 115,
- LAST_PROCESSFIELD = 116,
+ #ifdef HAVE_DELAYACCT
+ PERCENT_CPU_DELAY = 116,
+ PERCENT_IO_DELAY = 117,
+ PERCENT_SWAP_DELAY = 118,
+ #endif
+ LAST_PROCESSFIELD = 119,
} LinuxProcessField;
#include "IOPriority.h"
@@ -124,6 +129,16 @@ typedef struct LinuxProcess_ {
char* cgroup;
#endif
unsigned int oom;
+ char* ttyDevice;
+ #ifdef HAVE_DELAYACCT
+ unsigned long long int delay_read_time;
+ unsigned long long cpu_delay_total;
+ unsigned long long blkio_delay_total;
+ unsigned long long swapin_delay_total;
+ float cpu_delay_percent;
+ float blkio_delay_percent;
+ float swapin_delay_percent;
+ #endif
} LinuxProcess;
#ifndef Process_isKernelThread
@@ -140,11 +155,11 @@ ProcessFieldData Process_fields[] = {
[0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
[PID] = { .name = "PID", .title = " PID ", .description = "Process/thread ID", .flags = 0, },
[COMM] = { .name = "Command", .title = "Command ", .description = "Command line", .flags = 0, },
- [STATE] = { .name = "STATE", .title = "S ", .description = "Process state (S sleeping, R running, D disk, Z zombie, T traced, W paging)", .flags = 0, },
+ [STATE] = { .name = "STATE", .title = "S ", .description = "Process state (S sleeping, R running, D disk, Z zombie, T traced, W paging, I idle)", .flags = 0, },
[PPID] = { .name = "PPID", .title = " PPID ", .description = "Parent process ID", .flags = 0, },
[PGRP] = { .name = "PGRP", .title = " PGRP ", .description = "Process group ID", .flags = 0, },
- [SESSION] = { .name = "SESSION", .title = " SESN ", .description = "Process's session ID", .flags = 0, },
- [TTY_NR] = { .name = "TTY_NR", .title = " TTY ", .description = "Controlling terminal", .flags = 0, },
+ [SESSION] = { .name = "SESSION", .title = " SID ", .description = "Process's session ID", .flags = 0, },
+ [TTY_NR] = { .name = "TTY_NR", .title = "TTY ", .description = "Controlling terminal", .flags = 0, },
[TPGID] = { .name = "TPGID", .title = " TPGID ", .description = "Process ID of the fg process group of the controlling terminal", .flags = 0, },
[FLAGS] = { .name = "FLAGS", .title = NULL, .description = NULL, .flags = 0, },
[MINFLT] = { .name = "MINFLT", .title = " MINFLT ", .description = "Number of minor faults which have not required loading a memory page from disk", .flags = 0, },
@@ -214,6 +229,11 @@ ProcessFieldData Process_fields[] = {
#endif
[OOM] = { .name = "OOM", .title = " OOM ", .description = "OOM (Out-of-Memory) killer score", .flags = PROCESS_FLAG_LINUX_OOM, },
[IO_PRIORITY] = { .name = "IO_PRIORITY", .title = "IO ", .description = "I/O priority", .flags = PROCESS_FLAG_LINUX_IOPRIO, },
+#ifdef HAVE_DELAYACCT
+ [PERCENT_CPU_DELAY] = { .name = "PERCENT_CPU_DELAY", .title = "CPUD% ", .description = "CPU delay %", .flags = 0, },
+ [PERCENT_IO_DELAY] = { .name = "PERCENT_IO_DELAY", .title = "IOD% ", .description = "Block I/O delay %", .flags = 0, },
+ [PERCENT_SWAP_DELAY] = { .name = "PERCENT_SWAP_DELAY", .title = "SWAPD% ", .description = "Swapin delay %", .flags = 0, },
+#endif
[LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
};
@@ -226,7 +246,7 @@ ProcessPidColumn Process_pidColumns[] = {
{ .id = TPGID, .label = "TPGID" },
{ .id = TGID, .label = "TGID" },
{ .id = PGRP, .label = "PGRP" },
- { .id = SESSION, .label = "SESN" },
+ { .id = SESSION, .label = "SID" },
{ .id = OOM, .label = "OOM" },
{ .id = 0, .label = NULL },
};
@@ -254,6 +274,7 @@ void Process_delete(Object* cast) {
#ifdef HAVE_CGROUP
free(this->cgroup);
#endif
+ free(this->ttyDevice);
free(this);
}
@@ -285,6 +306,16 @@ bool LinuxProcess_setIOPriority(LinuxProcess* this, IOPriority ioprio) {
return (LinuxProcess_updateIOPriority(this) == ioprio);
}
+#ifdef HAVE_DELAYACCT
+void LinuxProcess_printDelay(float delay_percent, char* buffer, int n) {
+ if (delay_percent == -1LL) {
+ xSnprintf(buffer, n, " N/A ");
+ } else {
+ xSnprintf(buffer, n, "%4.1f ", delay_percent);
+ }
+}
+#endif
+
void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field) {
LinuxProcess* lp = (LinuxProcess*) this;
bool coloring = this->settings->highlightMegabytes;
@@ -292,6 +323,15 @@ void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field)
int attr = CRT_colors[DEFAULT_COLOR];
int n = sizeof(buffer) - 1;
switch ((int)field) {
+ case TTY_NR: {
+ if (lp->ttyDevice) {
+ xSnprintf(buffer, n, "%-9s", lp->ttyDevice + 5 /* skip "/dev/" */);
+ } else {
+ attr = CRT_colors[PROCESS_SHADOW];
+ xSnprintf(buffer, n, "? ");
+ }
+ break;
+ }
case CMINFLT: Process_colorNumber(str, lp->cminflt, coloring); return;
case CMAJFLT: Process_colorNumber(str, lp->cmajflt, coloring); return;
case M_DRS: Process_humanNumber(str, lp->m_drs * PAGE_SIZE_KB, coloring); return;
@@ -321,34 +361,39 @@ void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field)
}
#endif
#ifdef HAVE_OPENVZ
- case CTID: snprintf(buffer, n, "%7u ", lp->ctid); break;
- case VPID: snprintf(buffer, n, Process_pidFormat, lp->vpid); break;
+ case CTID: xSnprintf(buffer, n, "%7u ", lp->ctid); break;
+ case VPID: xSnprintf(buffer, n, Process_pidFormat, lp->vpid); break;
#endif
#ifdef HAVE_VSERVER
- case VXID: snprintf(buffer, n, "%5u ", lp->vxid); break;
+ case VXID: xSnprintf(buffer, n, "%5u ", lp->vxid); break;
#endif
#ifdef HAVE_CGROUP
- case CGROUP: snprintf(buffer, n, "%-10s ", lp->cgroup); break;
+ case CGROUP: xSnprintf(buffer, n, "%-10s ", lp->cgroup); break;
#endif
- case OOM: snprintf(buffer, n, Process_pidFormat, lp->oom); break;
+ case OOM: xSnprintf(buffer, n, Process_pidFormat, lp->oom); break;
case IO_PRIORITY: {
int klass = IOPriority_class(lp->ioPriority);
if (klass == IOPRIO_CLASS_NONE) {
// see note [1] above
- snprintf(buffer, n, "B%1d ", (int) (this->nice + 20) / 5);
+ xSnprintf(buffer, n, "B%1d ", (int) (this->nice + 20) / 5);
} else if (klass == IOPRIO_CLASS_BE) {
- snprintf(buffer, n, "B%1d ", IOPriority_data(lp->ioPriority));
+ xSnprintf(buffer, n, "B%1d ", IOPriority_data(lp->ioPriority));
} else if (klass == IOPRIO_CLASS_RT) {
attr = CRT_colors[PROCESS_HIGH_PRIORITY];
- snprintf(buffer, n, "R%1d ", IOPriority_data(lp->ioPriority));
- } else if (lp->ioPriority == IOPriority_Idle) {
+ xSnprintf(buffer, n, "R%1d ", IOPriority_data(lp->ioPriority));
+ } else if (klass == IOPRIO_CLASS_IDLE) {
attr = CRT_colors[PROCESS_LOW_PRIORITY];
- snprintf(buffer, n, "id ");
+ xSnprintf(buffer, n, "id ");
} else {
- snprintf(buffer, n, "?? ");
+ xSnprintf(buffer, n, "?? ");
}
break;
}
+ #ifdef HAVE_DELAYACCT
+ case PERCENT_CPU_DELAY: LinuxProcess_printDelay(lp->cpu_delay_percent, buffer, n); break;
+ case PERCENT_IO_DELAY: LinuxProcess_printDelay(lp->blkio_delay_percent, buffer, n); break;
+ case PERCENT_SWAP_DELAY: LinuxProcess_printDelay(lp->swapin_delay_percent, buffer, n); break;
+ #endif
default:
Process_writeField((Process*)this, str, field);
return;
@@ -410,6 +455,14 @@ long LinuxProcess_compare(const void* v1, const void* v2) {
#endif
case OOM:
return (p2->oom - p1->oom);
+ #ifdef HAVE_DELAYACCT
+ case PERCENT_CPU_DELAY:
+ return (p2->cpu_delay_percent > p1->cpu_delay_percent ? 1 : -1);
+ case PERCENT_IO_DELAY:
+ return (p2->blkio_delay_percent > p1->blkio_delay_percent ? 1 : -1);
+ case PERCENT_SWAP_DELAY:
+ return (p2->swapin_delay_percent > p1->swapin_delay_percent ? 1 : -1);
+ #endif
case IO_PRIORITY:
return LinuxProcess_effectiveIOPriority(p1) - LinuxProcess_effectiveIOPriority(p2);
default:
diff --git a/linux/LinuxProcess.h b/linux/LinuxProcess.h
index f2d81aa..9400d7b 100644
--- a/linux/LinuxProcess.h
+++ b/linux/LinuxProcess.h
@@ -73,7 +73,12 @@ typedef enum LinuxProcessFields {
#endif
OOM = 114,
IO_PRIORITY = 115,
- LAST_PROCESSFIELD = 116,
+ #ifdef HAVE_DELAYACCT
+ PERCENT_CPU_DELAY = 116,
+ PERCENT_IO_DELAY = 117,
+ PERCENT_SWAP_DELAY = 118,
+ #endif
+ LAST_PROCESSFIELD = 119,
} LinuxProcessField;
#include "IOPriority.h"
@@ -116,6 +121,16 @@ typedef struct LinuxProcess_ {
char* cgroup;
#endif
unsigned int oom;
+ char* ttyDevice;
+ #ifdef HAVE_DELAYACCT
+ unsigned long long int delay_read_time;
+ unsigned long long cpu_delay_total;
+ unsigned long long blkio_delay_total;
+ unsigned long long swapin_delay_total;
+ float cpu_delay_percent;
+ float blkio_delay_percent;
+ float swapin_delay_percent;
+ #endif
} LinuxProcess;
#ifndef Process_isKernelThread
@@ -151,6 +166,10 @@ IOPriority LinuxProcess_updateIOPriority(LinuxProcess* this);
bool LinuxProcess_setIOPriority(LinuxProcess* this, IOPriority ioprio);
+#ifdef HAVE_DELAYACCT
+void LinuxProcess_printDelay(float delay_percent, char* buffer, int n);
+#endif
+
void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field);
long LinuxProcess_compare(const void* v1, const void* v2);
diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c
index 712baa5..6f2631a 100644
--- a/linux/LinuxProcessList.c
+++ b/linux/LinuxProcessList.c
@@ -27,6 +27,16 @@ in the source distribution for its full text.
#include <sys/types.h>
#include <fcntl.h>
+#ifdef HAVE_DELAYACCT
+#include <netlink/attr.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/socket.h>
+#include <netlink/msg.h>
+#include <linux/taskstats.h>
+#endif
+
/*{
#include "ProcessList.h"
@@ -59,11 +69,23 @@ typedef struct CPUData_ {
unsigned long long int guestPeriod;
} CPUData;
+typedef struct TtyDriver_ {
+ char* path;
+ unsigned int major;
+ unsigned int minorFrom;
+ unsigned int minorTo;
+} TtyDriver;
+
typedef struct LinuxProcessList_ {
ProcessList super;
-
+
CPUData* cpus;
-
+ TtyDriver* ttyDrivers;
+
+ #ifdef HAVE_DELAYACCT
+ struct nl_sock *netlink_socket;
+ int netlink_family;
+ #endif
} LinuxProcessList;
#ifndef PROCDIR
@@ -78,6 +100,10 @@ typedef struct LinuxProcessList_ {
#define PROCMEMINFOFILE PROCDIR "/meminfo"
#endif
+#ifndef PROCTTYDRIVERSFILE
+#define PROCTTYDRIVERSFILE PROCDIR "/tty/drivers"
+#endif
+
#ifndef PROC_LINE_LENGTH
#define PROC_LINE_LENGTH 512
#endif
@@ -87,11 +113,124 @@ typedef struct LinuxProcessList_ {
#ifndef CLAMP
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
-
+
+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;
+ }
+}
+
+static int sortTtyDrivers(const void* va, const void* vb) {
+ TtyDriver* a = (TtyDriver*) va;
+ TtyDriver* b = (TtyDriver*) vb;
+ return (a->major == b->major) ? (a->minorFrom - b->minorFrom) : (a->major - b->major);
+}
+
+static void LinuxProcessList_initTtyDrivers(LinuxProcessList* this) {
+ TtyDriver* ttyDrivers;
+ int fd = open(PROCTTYDRIVERSFILE, O_RDONLY);
+ if (fd == -1)
+ return;
+ char* buf = NULL;
+ int bufSize = MAX_READ;
+ int bufLen = 0;
+ for(;;) {
+ buf = realloc(buf, bufSize);
+ int size = xread(fd, buf + bufLen, MAX_READ);
+ if (size <= 0) {
+ buf[bufLen] = '\0';
+ close(fd);
+ break;
+ }
+ bufLen += size;
+ bufSize += MAX_READ;
+ }
+ if (bufLen == 0) {
+ free(buf);
+ return;
+ }
+ int numDrivers = 0;
+ int allocd = 10;
+ ttyDrivers = malloc(sizeof(TtyDriver) * allocd);
+ char* at = buf;
+ while (*at != '\0') {
+ at = strchr(at, ' '); // skip first token
+ while (*at == ' ') at++; // skip spaces
+ char* token = at; // mark beginning of path
+ at = strchr(at, ' '); // find end of path
+ *at = '\0'; at++; // clear and skip
+ ttyDrivers[numDrivers].path = strdup(token); // save
+ while (*at == ' ') at++; // skip spaces
+ token = at; // mark beginning of major
+ at = strchr(at, ' '); // find end of major
+ *at = '\0'; at++; // clear and skip
+ ttyDrivers[numDrivers].major = atoi(token); // save
+ while (*at == ' ') at++; // skip spaces
+ token = at; // mark beginning of minorFrom
+ while (*at >= '0' && *at <= '9') at++; //find end of minorFrom
+ if (*at == '-') { // if has range
+ *at = '\0'; at++; // clear and skip
+ ttyDrivers[numDrivers].minorFrom = atoi(token); // save
+ token = at; // mark beginning of minorTo
+ at = strchr(at, ' '); // find end of minorTo
+ *at = '\0'; at++; // clear and skip
+ ttyDrivers[numDrivers].minorTo = atoi(token); // save
+ } else { // no range
+ *at = '\0'; at++; // clear and skip
+ ttyDrivers[numDrivers].minorFrom = atoi(token); // save
+ ttyDrivers[numDrivers].minorTo = atoi(token); // save
+ }
+ at = strchr(at, '\n'); // go to end of line
+ at++; // skip
+ numDrivers++;
+ if (numDrivers == allocd) {
+ allocd += 10;
+ ttyDrivers = realloc(ttyDrivers, sizeof(TtyDriver) * allocd);
+ }
+ }
+ free(buf);
+ numDrivers++;
+ ttyDrivers = realloc(ttyDrivers, sizeof(TtyDriver) * numDrivers);
+ ttyDrivers[numDrivers - 1].path = NULL;
+ qsort(ttyDrivers, numDrivers - 1, sizeof(TtyDriver), sortTtyDrivers);
+ this->ttyDrivers = ttyDrivers;
+}
+
+#ifdef HAVE_DELAYACCT
+
+static void LinuxProcessList_initNetlinkSocket(LinuxProcessList* this) {
+ this->netlink_socket = nl_socket_alloc();
+ if (this->netlink_socket == NULL) {
+ return;
+ }
+ if (nl_connect(this->netlink_socket, NETLINK_GENERIC) < 0) {
+ return;
+ }
+ this->netlink_family = genl_ctrl_resolve(this->netlink_socket, TASKSTATS_GENL_NAME);
+}
+
+#endif
+
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
LinuxProcessList* this = xCalloc(1, sizeof(LinuxProcessList));
ProcessList* pl = &(this->super);
ProcessList_init(pl, Class(LinuxProcess), usersTable, pidWhiteList, userId);
+
+ LinuxProcessList_initTtyDrivers(this);
+
+ #ifdef HAVE_DELAYACCT
+ LinuxProcessList_initNetlinkSocket(this);
+ #endif
// Update CPU count:
FILE* file = fopen(PROCSTATFILE, "r");
@@ -122,25 +261,21 @@ void ProcessList_delete(ProcessList* pl) {
LinuxProcessList* this = (LinuxProcessList*) pl;
ProcessList_done(pl);
free(this->cpus);
+ if (this->ttyDrivers) {
+ for(int i = 0; this->ttyDrivers[i].path; i++) {
+ free(this->ttyDrivers[i].path);
+ }
+ free(this->ttyDrivers);
+ }
+ #ifdef HAVE_DELAYACCT
+ if (this->netlink_socket) {
+ nl_close(this->netlink_socket);
+ nl_socket_free(this->netlink_socket);
+ }
+ #endif
free(this);
}
-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;
- }
-}
-
static double jiffy = 0.0;
static inline unsigned long long LinuxProcess_adjustTime(unsigned long long t) {
@@ -152,7 +287,7 @@ static inline unsigned long long LinuxProcess_adjustTime(unsigned long long t) {
static bool LinuxProcessList_readStatFile(Process *process, const char* dirname, const char* name, char* command, int* commLen) {
LinuxProcess* lp = (LinuxProcess*) process;
char filename[MAX_NAME+1];
- snprintf(filename, MAX_NAME, "%s/%s/stat", dirname, name);
+ xSnprintf(filename, MAX_NAME, "%s/%s/stat", dirname, name);
int fd = open(filename, O_RDONLY);
if (fd == -1)
return false;
@@ -221,7 +356,7 @@ static bool LinuxProcessList_readStatFile(Process *process, const char* dirname,
process->processor = strtol(location, &location, 10);
process->time = lp->utime + lp->stime;
-
+
return true;
}
@@ -230,7 +365,7 @@ static bool LinuxProcessList_statProcessDir(Process* process, const char* dirnam
char filename[MAX_NAME+1];
filename[MAX_NAME] = '\0';
- snprintf(filename, MAX_NAME, "%s/%s", dirname, name);
+ xSnprintf(filename, MAX_NAME, "%s/%s", dirname, name);
struct stat sstat;
int statok = stat(filename, &sstat);
if (statok == -1)
@@ -252,11 +387,20 @@ static void LinuxProcessList_readIoFile(LinuxProcess* process, const char* dirna
char filename[MAX_NAME+1];
filename[MAX_NAME] = '\0';
- snprintf(filename, MAX_NAME, "%s/%s/io", dirname, name);
+ xSnprintf(filename, MAX_NAME, "%s/%s/io", dirname, name);
int fd = open(filename, O_RDONLY);
if (fd == -1) {
process->io_rate_read_bps = -1;
process->io_rate_write_bps = -1;
+ process->io_rchar = -1LL;
+ process->io_wchar = -1LL;
+ process->io_syscr = -1LL;
+ process->io_syscw = -1LL;
+ process->io_read_bytes = -1LL;
+ process->io_write_bytes = -1LL;
+ process->io_cancelled_write_bytes = -1LL;
+ process->io_rate_read_time = -1LL;
+ process->io_rate_write_time = -1LL;
return;
}
@@ -312,7 +456,7 @@ static void LinuxProcessList_readIoFile(LinuxProcess* process, const char* dirna
static bool LinuxProcessList_readStatmFile(LinuxProcess* process, const char* dirname, const char* name) {
char filename[MAX_NAME+1];
- snprintf(filename, MAX_NAME, "%s/%s/statm", dirname, name);
+ xSnprintf(filename, MAX_NAME, "%s/%s/statm", dirname, name);
int fd = open(filename, O_RDONLY);
if (fd == -1)
return false;
@@ -342,7 +486,7 @@ static void LinuxProcessList_readOpenVZData(LinuxProcess* process, const char* d
return;
}
char filename[MAX_NAME+1];
- snprintf(filename, MAX_NAME, "%s/%s/stat", dirname, name);
+ xSnprintf(filename, MAX_NAME, "%s/%s/stat", dirname, name);
FILE* file = fopen(filename, "r");
if (!file)
return;
@@ -365,7 +509,7 @@ static void LinuxProcessList_readOpenVZData(LinuxProcess* process, const char* d
static void LinuxProcessList_readCGroupFile(LinuxProcess* process, const char* dirname, const char* name) {
char filename[MAX_NAME+1];
- snprintf(filename, MAX_NAME, "%s/%s/cgroup", dirname, name);
+ xSnprintf(filename, MAX_NAME, "%s/%s/cgroup", dirname, name);
FILE* file = fopen(filename, "r");
if (!file) {
process->cgroup = xStrdup("");
@@ -400,7 +544,7 @@ static void LinuxProcessList_readCGroupFile(LinuxProcess* process, const char* d
static void LinuxProcessList_readVServerData(LinuxProcess* process, const char* dirname, const char* name) {
char filename[MAX_NAME+1];
- snprintf(filename, MAX_NAME, "%s/%s/status", dirname, name);
+ xSnprintf(filename, MAX_NAME, "%s/%s/status", dirname, name);
FILE* file = fopen(filename, "r");
if (!file)
return;
@@ -431,10 +575,11 @@ static void LinuxProcessList_readVServerData(LinuxProcess* process, const char*
static void LinuxProcessList_readOomData(LinuxProcess* process, const char* dirname, const char* name) {
char filename[MAX_NAME+1];
- snprintf(filename, MAX_NAME, "%s/%s/oom_score", dirname, name);
+ xSnprintf(filename, MAX_NAME, "%s/%s/oom_score", dirname, name);
FILE* file = fopen(filename, "r");
- if (!file)
+ if (!file) {
return;
+ }
char buffer[PROC_LINE_LENGTH + 1];
if (fgets(buffer, PROC_LINE_LENGTH, file)) {
unsigned int oom;
@@ -446,6 +591,75 @@ static void LinuxProcessList_readOomData(LinuxProcess* process, const char* dirn
fclose(file);
}
+#ifdef HAVE_DELAYACCT
+
+static int handleNetlinkMsg(struct nl_msg *nlmsg, void *linuxProcess) {
+ struct nlmsghdr *nlhdr;
+ struct nlattr *nlattrs[TASKSTATS_TYPE_MAX + 1];
+ struct nlattr *nlattr;
+ struct taskstats *stats;
+ int rem;
+ unsigned long long int timeDelta;
+ LinuxProcess* lp = (LinuxProcess*) linuxProcess;
+
+ nlhdr = nlmsg_hdr(nlmsg);
+
+ if (genlmsg_parse(nlhdr, 0, nlattrs, TASKSTATS_TYPE_MAX, NULL) < 0) {
+ return NL_SKIP;
+ }
+
+ if ((nlattr = nlattrs[TASKSTATS_TYPE_AGGR_PID]) || (nlattr = nlattrs[TASKSTATS_TYPE_NULL])) {
+ stats = nla_data(nla_next(nla_data(nlattr), &rem));
+ assert(lp->super.pid == stats->ac_pid);
+ timeDelta = (stats->ac_etime*1000 - lp->delay_read_time);
+ #define BOUNDS(x) isnan(x) ? 0.0 : (x > 100) ? 100.0 : x;
+ #define DELTAPERC(x,y) BOUNDS((float) (x - y) / timeDelta * 100);
+ lp->cpu_delay_percent = DELTAPERC(stats->cpu_delay_total, lp->cpu_delay_total);
+ lp->blkio_delay_percent = DELTAPERC(stats->blkio_delay_total, lp->blkio_delay_total);
+ lp->swapin_delay_percent = DELTAPERC(stats->swapin_delay_total, lp->swapin_delay_total);
+ #undef DELTAPERC
+ #undef BOUNDS
+ lp->swapin_delay_total = stats->swapin_delay_total;
+ lp->blkio_delay_total = stats->blkio_delay_total;
+ lp->cpu_delay_total = stats->cpu_delay_total;
+ lp->delay_read_time = stats->ac_etime*1000;
+ }
+ return NL_OK;
+}
+
+static void LinuxProcessList_readDelayAcctData(LinuxProcessList* this, LinuxProcess* process) {
+ struct nl_msg *msg;
+
+ if (nl_socket_modify_cb(this->netlink_socket, NL_CB_VALID, NL_CB_CUSTOM, handleNetlinkMsg, process) < 0) {
+ return;
+ }
+
+ if (! (msg = nlmsg_alloc())) {
+ return;
+ }
+
+ if (! genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, this->netlink_family, 0, NLM_F_REQUEST, TASKSTATS_CMD_GET, TASKSTATS_VERSION)) {
+ nlmsg_free(msg);
+ }
+
+ if (nla_put_u32(msg, TASKSTATS_CMD_ATTR_PID, process->super.pid) < 0) {
+ nlmsg_free(msg);
+ }
+
+ if (nl_send_sync(this->netlink_socket, msg) < 0) {
+ process->swapin_delay_percent = -1LL;
+ process->blkio_delay_percent = -1LL;
+ process->cpu_delay_percent = -1LL;
+ return;
+ }
+
+ if (nl_recvmsgs_default(this->netlink_socket) < 0) {
+ return;
+ }
+}
+
+#endif
+
static void setCommand(Process* process, const char* command, int len) {
if (process->comm && process->commLen >= len) {
strncpy(process->comm, command, len + 1);
@@ -461,7 +675,7 @@ static bool LinuxProcessList_readCmdlineFile(Process* process, const char* dirna
return true;
char filename[MAX_NAME+1];
- snprintf(filename, MAX_NAME, "%s/%s/cmdline", dirname, name);
+ xSnprintf(filename, MAX_NAME, "%s/%s/cmdline", dirname, name);
int fd = open(filename, O_RDONLY);
if (fd == -1)
return false;
@@ -471,27 +685,71 @@ static bool LinuxProcessList_readCmdlineFile(Process* process, const char* dirna
close(fd);
int tokenEnd = 0;
int lastChar = 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] = ' ';
- } else {
- lastChar = i;
+ if (amtRead <= 0) {
+ return false;
+ }
+ for (int i = 0; i < amtRead; i++) {
+ if (command[i] == '\0' || command[i] == '\n') {
+ if (tokenEnd == 0) {
+ tokenEnd = i;
}
+ command[i] = ' ';
+ } else {
+ lastChar = i;
+ }
}
if (tokenEnd == 0) {
tokenEnd = amtRead;
}
command[lastChar + 1] = '\0';
process->basenameOffset = tokenEnd;
- setCommand(process, command, lastChar + 1);
+ setCommand(process, command, lastChar);
return true;
}
+static char* LinuxProcessList_updateTtyDevice(TtyDriver* ttyDrivers, unsigned int tty_nr) {
+ unsigned int maj = major(tty_nr);
+ unsigned int min = minor(tty_nr);
+
+ int i = -1;
+ for (;;) {
+ i++;
+ if ((!ttyDrivers[i].path) || maj < ttyDrivers[i].major) {
+ break;
+ }
+ if (maj > ttyDrivers[i].major) {
+ continue;
+ }
+ if (min < ttyDrivers[i].minorFrom) {
+ break;
+ }
+ if (min > ttyDrivers[i].minorTo) {
+ continue;
+ }
+ unsigned int idx = min - ttyDrivers[i].minorFrom;
+ struct stat sstat;
+ char* fullPath;
+ for(;;) {
+ asprintf(&fullPath, "%s/%d", ttyDrivers[i].path, idx);
+ int err = stat(fullPath, &sstat);
+ if (err == 0 && major(sstat.st_rdev) == maj && minor(sstat.st_rdev) == min) return fullPath;
+ free(fullPath);
+ asprintf(&fullPath, "%s%d", ttyDrivers[i].path, idx);
+ err = stat(fullPath, &sstat);
+ if (err == 0 && major(sstat.st_rdev) == maj && minor(sstat.st_rdev) == min) return fullPath;
+ free(fullPath);
+ if (idx == min) break;
+ idx = min;
+ }
+ int err = stat(ttyDrivers[i].path, &sstat);
+ if (err == 0 && tty_nr == sstat.st_rdev) return strdup(ttyDrivers[i].path);
+ }
+ char* out;
+ asprintf(&out, "/dev/%u:%u", maj, min);
+ return out;
+}
+
static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char* dirname, Process* parent, double period, struct timeval tv) {
ProcessList* pl = (ProcessList*) this;
DIR* dir;
@@ -538,7 +796,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
LinuxProcess* lp = (LinuxProcess*) proc;
char subdirname[MAX_NAME+1];
- snprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name);
+ xSnprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name);
LinuxProcessList_recurseProcTree(this, subdirname, proc, period, tv);
#ifdef HAVE_TASKSTATS
@@ -554,8 +812,13 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
char command[MAX_NAME+1];
unsigned long long int lasttimes = (lp->utime + lp->stime);
int commLen = 0;
+ unsigned int tty_nr = proc->tty_nr;
if (! LinuxProcessList_readStatFile(proc, dirname, name, command, &commLen))
goto errorReadingProcess;
+ if (tty_nr != proc->tty_nr && this->ttyDrivers) {
+ free(lp->ttyDevice);
+ lp->ttyDevice = LinuxProcessList_updateTtyDevice(this->ttyDrivers, proc->tty_nr);
+ }
if (settings->flags & PROCESS_FLAG_LINUX_IOPRIO)
LinuxProcess_updateIOPriority(lp);
float percent_cpu = (lp->utime + lp->stime - lasttimes) / period * 100.0;
@@ -595,6 +858,10 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
}
}
+ #ifdef HAVE_DELAYACCT
+ LinuxProcessList_readDelayAcctData(this, lp);
+ #endif
+
#ifdef HAVE_CGROUP
if (settings->flags & PROCESS_FLAG_LINUX_CGROUP)
LinuxProcessList_readCGroupFile(lp, dirname, name);
diff --git a/linux/LinuxProcessList.h b/linux/LinuxProcessList.h
index 9772581..5005220 100644
--- a/linux/LinuxProcessList.h
+++ b/linux/LinuxProcessList.h
@@ -9,6 +9,9 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
+#ifdef HAVE_DELAYACCT
+#endif
+
#include "ProcessList.h"
@@ -40,11 +43,23 @@ typedef struct CPUData_ {
unsigned long long int guestPeriod;
} CPUData;
+typedef struct TtyDriver_ {
+ char* path;
+ unsigned int major;
+ unsigned int minorFrom;
+ unsigned int minorTo;
+} TtyDriver;
+
typedef struct LinuxProcessList_ {
ProcessList super;
-
+
CPUData* cpus;
-
+ TtyDriver* ttyDrivers;
+
+ #ifdef HAVE_DELAYACCT
+ struct nl_sock *netlink_socket;
+ int netlink_family;
+ #endif
} LinuxProcessList;
#ifndef PROCDIR
@@ -59,6 +74,10 @@ typedef struct LinuxProcessList_ {
#define PROCMEMINFOFILE PROCDIR "/meminfo"
#endif
+#ifndef PROCTTYDRIVERSFILE
+#define PROCTTYDRIVERSFILE PROCDIR "/tty/drivers"
+#endif
+
#ifndef PROC_LINE_LENGTH
#define PROC_LINE_LENGTH 512
#endif
@@ -67,7 +86,11 @@ typedef struct LinuxProcessList_ {
#ifndef CLAMP
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
-
+
+#ifdef HAVE_DELAYACCT
+
+#endif
+
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId);
void ProcessList_delete(ProcessList* pl);
@@ -89,6 +112,10 @@ void ProcessList_delete(ProcessList* pl);
#endif
+#ifdef HAVE_DELAYACCT
+
+#endif
+
void ProcessList_goThroughEntries(ProcessList* super);
#endif
diff --git a/linux/Platform.c b/linux/Platform.c
index 04360ca..025abff 100644
--- a/linux/Platform.c
+++ b/linux/Platform.c
@@ -47,7 +47,7 @@ ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_R
int Platform_numberOfFields = LAST_PROCESSFIELD;
-SignalItem Platform_signals[] = {
+const SignalItem Platform_signals[] = {
{ .name = " 0 Cancel", .number = 0 },
{ .name = " 1 SIGHUP", .number = 1 },
{ .name = " 2 SIGINT", .number = 2 },
@@ -84,7 +84,7 @@ SignalItem Platform_signals[] = {
{ .name = "31 SIGSYS", .number = 31 },
};
-unsigned int Platform_numberOfSignals = sizeof(Platform_signals)/sizeof(SignalItem);
+const unsigned int Platform_numberOfSignals = sizeof(Platform_signals)/sizeof(SignalItem);
static Htop_Reaction Platform_actionSetIOPriority(State* st) {
Panel* panel = st->panel;
@@ -215,7 +215,7 @@ void Platform_setSwapValues(Meter* this) {
char* Platform_getProcessEnv(pid_t pid) {
char procname[32+1];
- snprintf(procname, 32, "/proc/%d/environ", pid);
+ xSnprintf(procname, 32, "/proc/%d/environ", pid);
FILE* fd = fopen(procname, "r");
char *env = NULL;
if (fd) {
diff --git a/linux/Platform.h b/linux/Platform.h
index b0d69fb..b0456e5 100644
--- a/linux/Platform.h
+++ b/linux/Platform.h
@@ -23,9 +23,9 @@ extern ProcessField Platform_defaultFields[];
extern int Platform_numberOfFields;
-extern SignalItem Platform_signals[];
+extern const SignalItem Platform_signals[];
-extern unsigned int Platform_numberOfSignals;
+extern const unsigned int Platform_numberOfSignals;
void Platform_setBindings(Htop_Action* keys);

© 2014-2024 Faster IT GmbH | imprint | privacy policy