mirror of
https://github.com/xzeldon/htop.git
synced 2025-07-14 04:54:37 +03:00
Resolve merge conflicts, merge #298 "Macro cleanup" from @BenBE
This commit is contained in:
@ -37,7 +37,7 @@ Linux battery readings written by Ian P. Hands (iphands@gmail.com, ihands@redhat
|
||||
// but I think this is on the way out so I did not rewrite it.
|
||||
// The /sys implementation below does things the right way.
|
||||
|
||||
static unsigned long int parseBatInfo(const char *fileName, const unsigned short int lineNum, const unsigned short int wordNum) {
|
||||
static unsigned long int parseBatInfo(const char* fileName, const unsigned short int lineNum, const unsigned short int wordNum) {
|
||||
const char batteryPath[] = PROCDIR "/acpi/battery/";
|
||||
DIR* batteryDir = opendir(batteryPath);
|
||||
if (!batteryDir)
|
||||
@ -52,9 +52,11 @@ static unsigned long int parseBatInfo(const char *fileName, const unsigned short
|
||||
struct dirent* dirEntry = readdir(batteryDir);
|
||||
if (!dirEntry)
|
||||
break;
|
||||
|
||||
char* entryName = dirEntry->d_name;
|
||||
if (!String_startsWith(entryName, "BAT"))
|
||||
continue;
|
||||
|
||||
batteries[nBatteries] = xStrdup(entryName);
|
||||
nBatteries++;
|
||||
}
|
||||
@ -74,14 +76,16 @@ static unsigned long int parseBatInfo(const char *fileName, const unsigned short
|
||||
for (unsigned short int j = 0; j < lineNum; j++) {
|
||||
free(line);
|
||||
line = String_readLine(file);
|
||||
if (!line) break;
|
||||
if (!line)
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
if (!line) break;
|
||||
if (!line)
|
||||
break;
|
||||
|
||||
char *foundNumStr = String_getToken(line, wordNum);
|
||||
char* foundNumStr = String_getToken(line, wordNum);
|
||||
const unsigned long int foundNum = atoi(foundNumStr);
|
||||
free(foundNumStr);
|
||||
free(line);
|
||||
@ -98,8 +102,8 @@ static unsigned long int parseBatInfo(const char *fileName, const unsigned short
|
||||
|
||||
static ACPresence procAcpiCheck(void) {
|
||||
ACPresence isOn = AC_ERROR;
|
||||
const char *power_supplyPath = PROCDIR "/acpi/ac_adapter";
|
||||
DIR *dir = opendir(power_supplyPath);
|
||||
const char* power_supplyPath = PROCDIR "/acpi/ac_adapter";
|
||||
DIR* dir = opendir(power_supplyPath);
|
||||
if (!dir) {
|
||||
return AC_ERROR;
|
||||
}
|
||||
@ -115,17 +119,20 @@ static ACPresence procAcpiCheck(void) {
|
||||
continue;
|
||||
|
||||
char statePath[256];
|
||||
xSnprintf((char *) statePath, sizeof statePath, "%s/%s/state", power_supplyPath, entryName);
|
||||
xSnprintf(statePath, sizeof(statePath), "%s/%s/state", power_supplyPath, entryName);
|
||||
FILE* file = fopen(statePath, "r");
|
||||
if (!file) {
|
||||
isOn = AC_ERROR;
|
||||
continue;
|
||||
}
|
||||
char* line = String_readLine(file);
|
||||
fclose(file);
|
||||
if (!line) continue;
|
||||
|
||||
char *isOnline = String_getToken(line, 2);
|
||||
fclose(file);
|
||||
|
||||
if (!line)
|
||||
continue;
|
||||
|
||||
char* isOnline = String_getToken(line, 2);
|
||||
free(line);
|
||||
|
||||
if (String_eq(isOnline, "on-line")) {
|
||||
@ -139,8 +146,10 @@ static ACPresence procAcpiCheck(void) {
|
||||
}
|
||||
}
|
||||
|
||||
if (dir)
|
||||
if (dir) {
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
return isOn;
|
||||
}
|
||||
|
||||
@ -165,20 +174,27 @@ static void Battery_getProcData(double* level, ACPresence* isOnAC) {
|
||||
// READ FROM /sys
|
||||
// ----------------------------------------
|
||||
|
||||
static inline 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 inline 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) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (res > 0) {
|
||||
buf = ((char*)buf) + res;
|
||||
count -= res;
|
||||
alreadyRead += res;
|
||||
}
|
||||
|
||||
if (count == 0 || res == 0) {
|
||||
return alreadyRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Battery_getSysData(double* level, ACPresence* isOnAC) {
|
||||
@ -186,7 +202,7 @@ static void Battery_getSysData(double* level, ACPresence* isOnAC) {
|
||||
*level = NAN;
|
||||
*isOnAC = AC_ERROR;
|
||||
|
||||
DIR *dir = opendir(SYS_POWERSUPPLY_DIR);
|
||||
DIR* dir = opendir(SYS_POWERSUPPLY_DIR);
|
||||
if (!dir)
|
||||
return;
|
||||
|
||||
@ -197,6 +213,7 @@ static void Battery_getSysData(double* level, ACPresence* isOnAC) {
|
||||
struct dirent* dirEntry = readdir(dir);
|
||||
if (!dirEntry)
|
||||
break;
|
||||
|
||||
const char* entryName = dirEntry->d_name;
|
||||
char filePath[256];
|
||||
|
||||
@ -226,15 +243,17 @@ static void Battery_getSysData(double* level, ACPresence* isOnAC) {
|
||||
return;
|
||||
}
|
||||
buffer[buflen] = '\0';
|
||||
char *buf = buffer;
|
||||
char *line = NULL;
|
||||
char* buf = buffer;
|
||||
char* line = NULL;
|
||||
bool full = false;
|
||||
bool now = false;
|
||||
int fullSize = 0;
|
||||
double capacityLevel = NAN;
|
||||
|
||||
#define match(str,prefix) \
|
||||
(String_startsWith(str,prefix) ? (str) + strlen(prefix) : NULL)
|
||||
|
||||
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;
|
||||
@ -255,18 +274,24 @@ static void Battery_getSysData(double* level, ACPresence* isOnAC) {
|
||||
fullSize = atoi(value);
|
||||
totalFull += fullSize;
|
||||
full = true;
|
||||
if (now) break;
|
||||
if (now) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
value = (!now) ? match(energy, "NOW=") : NULL;
|
||||
if (value) {
|
||||
totalRemain += atoi(value);
|
||||
now = true;
|
||||
if (full) break;
|
||||
if (full) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#undef match
|
||||
|
||||
#undef match
|
||||
|
||||
if (!now && full && !isnan(capacityLevel)) {
|
||||
totalRemain += (capacityLevel * fullSize);
|
||||
}
|
||||
@ -282,9 +307,11 @@ static void Battery_getSysData(double* level, ACPresence* isOnAC) {
|
||||
return;
|
||||
}
|
||||
char buffer[2] = "";
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
ssize_t res = read(fd3, buffer, 1);
|
||||
if (res == -1 && errno == EINTR) continue;
|
||||
if (res == -1 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
close(fd3);
|
||||
|
@ -21,8 +21,13 @@ 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);
|
||||
static const struct { int klass; const char* name; } classes[] = {
|
||||
if (currPrio == IOPriority_None) {
|
||||
Panel_setSelected(this, 0);
|
||||
}
|
||||
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 }
|
||||
@ -30,14 +35,18 @@ Panel* IOPriorityPanel_new(IOPriority currPrio) {
|
||||
for (int c = 0; classes[c].name; c++) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
char name[50];
|
||||
xSnprintf(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);
|
||||
if (currPrio == ioprio) {
|
||||
Panel_setSelected(this, Panel_size(this) - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Panel_add(this, (Object*) ListItem_new("Idle", IOPriority_Idle));
|
||||
if (currPrio == IOPriority_Idle) Panel_setSelected(this, Panel_size(this) - 1);
|
||||
if (currPrio == IOPriority_Idle) {
|
||||
Panel_setSelected(this, Panel_size(this) - 1);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -168,8 +168,9 @@ dynamically derived from the cpu nice level of the process:
|
||||
io_priority = (cpu_nice + 20) / 5. -- From ionice(1) man page
|
||||
*/
|
||||
static int LinuxProcess_effectiveIOPriority(const LinuxProcess* this) {
|
||||
if (IOPriority_class(this->ioPriority) == IOPRIO_CLASS_NONE)
|
||||
if (IOPriority_class(this->ioPriority) == IOPRIO_CLASS_NONE) {
|
||||
return IOPriority_tuple(IOPRIO_CLASS_BE, (this->super.nice + 20) / 5);
|
||||
}
|
||||
|
||||
return this->ioPriority;
|
||||
}
|
||||
@ -194,11 +195,11 @@ bool LinuxProcess_setIOPriority(Process* this, Arg ioprio) {
|
||||
|
||||
#ifdef HAVE_DELAYACCT
|
||||
void LinuxProcess_printDelay(float delay_percent, char* buffer, int n) {
|
||||
if (isnan(delay_percent)) {
|
||||
xSnprintf(buffer, n, " N/A ");
|
||||
} else {
|
||||
xSnprintf(buffer, n, "%4.1f ", delay_percent);
|
||||
}
|
||||
if (isnan(delay_percent)) {
|
||||
xSnprintf(buffer, n, " N/A ");
|
||||
} else {
|
||||
xSnprintf(buffer, n, "%4.1f ", delay_percent);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -244,11 +245,11 @@ void LinuxProcess_writeField(const Process* this, RichString* str, ProcessField
|
||||
case IO_WRITE_RATE: Process_outputRate(str, buffer, n, lp->io_rate_write_bps, coloring); return;
|
||||
case IO_RATE: {
|
||||
double totalRate = NAN;
|
||||
if(!isnan(lp->io_rate_read_bps) && !isnan(lp->io_rate_write_bps))
|
||||
if (!isnan(lp->io_rate_read_bps) && !isnan(lp->io_rate_write_bps))
|
||||
totalRate = lp->io_rate_read_bps + lp->io_rate_write_bps;
|
||||
else if(!isnan(lp->io_rate_read_bps))
|
||||
else if (!isnan(lp->io_rate_read_bps))
|
||||
totalRate = lp->io_rate_read_bps;
|
||||
else if(!isnan(lp->io_rate_write_bps))
|
||||
else if (!isnan(lp->io_rate_write_bps))
|
||||
totalRate = lp->io_rate_write_bps;
|
||||
else
|
||||
totalRate = NAN;
|
||||
@ -290,8 +291,9 @@ void LinuxProcess_writeField(const Process* this, RichString* str, ProcessField
|
||||
case PERCENT_SWAP_DELAY: LinuxProcess_printDelay(lp->swapin_delay_percent, buffer, n); break;
|
||||
#endif
|
||||
case CTXT:
|
||||
if (lp->ctxt_diff > 1000)
|
||||
if (lp->ctxt_diff > 1000) {
|
||||
attr |= A_BOLD;
|
||||
}
|
||||
xSnprintf(buffer, n, "%5lu ", lp->ctxt_diff);
|
||||
break;
|
||||
case SECATTR: snprintf(buffer, n, "%-30s ", lp->secattr ? lp->secattr : "?"); break;
|
||||
@ -379,7 +381,8 @@ long LinuxProcess_compare(const void* v1, const void* v2) {
|
||||
default:
|
||||
return Process_compare(v1, v2);
|
||||
}
|
||||
test_diff:
|
||||
|
||||
test_diff:
|
||||
return (diff > 0) ? 1 : (diff < 0 ? -1 : 0);
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ typedef struct LinuxProcess_ {
|
||||
#endif
|
||||
unsigned long ctxt_total;
|
||||
unsigned long ctxt_diff;
|
||||
char *secattr;
|
||||
char* secattr;
|
||||
} LinuxProcess;
|
||||
|
||||
#define Process_isKernelThread(_process) (((const LinuxProcess*)(_process))->isKernelThread)
|
||||
|
@ -51,20 +51,27 @@ in the source distribution for its full text.
|
||||
#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 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) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (res > 0) {
|
||||
buf = ((char*)buf) + res;
|
||||
count -= res;
|
||||
alreadyRead += res;
|
||||
}
|
||||
|
||||
if (count == 0 || res == 0) {
|
||||
return alreadyRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int sortTtyDrivers(const void* va, const void* vb) {
|
||||
@ -78,10 +85,11 @@ static void LinuxProcessList_initTtyDrivers(LinuxProcessList* this) {
|
||||
int fd = open(PROCTTYDRIVERSFILE, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return;
|
||||
|
||||
char* buf = NULL;
|
||||
int bufSize = MAX_READ;
|
||||
int bufLen = 0;
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
buf = xRealloc(buf, bufSize);
|
||||
int size = xread(fd, buf + bufLen, MAX_READ);
|
||||
if (size <= 0) {
|
||||
@ -160,21 +168,24 @@ static void LinuxProcessList_initNetlinkSocket(LinuxProcessList* this) {
|
||||
|
||||
static int LinuxProcessList_computeCPUcount(void) {
|
||||
FILE* file = fopen(PROCSTATFILE, "r");
|
||||
if (file == NULL)
|
||||
if (file == NULL) {
|
||||
CRT_fatalError("Cannot open " PROCSTATFILE);
|
||||
}
|
||||
|
||||
int cpus = 0;
|
||||
char buffer[PROC_LINE_LENGTH + 1];
|
||||
while(fgets(buffer, sizeof(buffer), file)) {
|
||||
if (String_startsWith(buffer, "cpu"))
|
||||
while (fgets(buffer, sizeof(buffer), file)) {
|
||||
if (String_startsWith(buffer, "cpu")) {
|
||||
cpus++;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
/* subtract raw cpu entry */
|
||||
if (cpus > 0)
|
||||
if (cpus > 0) {
|
||||
cpus--;
|
||||
}
|
||||
|
||||
return cpus;
|
||||
}
|
||||
@ -208,7 +219,7 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
|
||||
|
||||
// Check for /proc/*/smaps_rollup availability (improves smaps parsing speed, Linux 4.14+)
|
||||
FILE* file = fopen(PROCDIR "/self/smaps_rollup", "r");
|
||||
if(file != NULL) {
|
||||
if (file != NULL) {
|
||||
this->haveSmapsRollup = true;
|
||||
fclose(file);
|
||||
} else {
|
||||
@ -218,16 +229,18 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
|
||||
// Read btime
|
||||
{
|
||||
FILE* statfile = fopen(PROCSTATFILE, "r");
|
||||
if (statfile == NULL)
|
||||
if (statfile == NULL) {
|
||||
CRT_fatalError("Cannot open " PROCSTATFILE);
|
||||
}
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
char buffer[PROC_LINE_LENGTH + 1];
|
||||
if (fgets(buffer, sizeof(buffer), statfile) == NULL) {
|
||||
CRT_fatalError("No btime in " PROCSTATFILE);
|
||||
} else if (String_startsWith(buffer, "btime ")) {
|
||||
if (sscanf(buffer, "btime %lld\n", &btime) != 1)
|
||||
if (sscanf(buffer, "btime %lld\n", &btime) != 1) {
|
||||
CRT_fatalError("Failed to parse btime from " PROCSTATFILE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -255,7 +268,7 @@ void ProcessList_delete(ProcessList* pl) {
|
||||
ProcessList_done(pl);
|
||||
free(this->cpus);
|
||||
if (this->ttyDrivers) {
|
||||
for(int i = 0; this->ttyDrivers[i].path; i++) {
|
||||
for (int i = 0; this->ttyDrivers[i].path; i++) {
|
||||
free(this->ttyDrivers[i].path);
|
||||
}
|
||||
free(this->ttyDrivers);
|
||||
@ -271,10 +284,10 @@ void ProcessList_delete(ProcessList* pl) {
|
||||
|
||||
static inline unsigned long long LinuxProcess_adjustTime(unsigned long long t) {
|
||||
static double jiffy = NAN;
|
||||
if(isnan(jiffy)) {
|
||||
if (isnan(jiffy)) {
|
||||
errno = 0;
|
||||
long sc_jiffy = sysconf(_SC_CLK_TCK);
|
||||
if(errno || -1 == sc_jiffy) {
|
||||
if (errno || -1 == sc_jiffy) {
|
||||
jiffy = NAN;
|
||||
return t; // Assume 100Hz clock
|
||||
}
|
||||
@ -284,30 +297,33 @@ static inline unsigned long long LinuxProcess_adjustTime(unsigned long long t) {
|
||||
return t * jiffytime * 100;
|
||||
}
|
||||
|
||||
static bool LinuxProcessList_readStatFile(Process *process, const char* dirname, const char* name, char* command, int* commLen) {
|
||||
static bool LinuxProcessList_readStatFile(Process* process, const char* dirname, const char* name, char* command, int* commLen) {
|
||||
LinuxProcess* lp = (LinuxProcess*) process;
|
||||
const int commLenIn = *commLen;
|
||||
*commLen = 0;
|
||||
char filename[MAX_NAME+1];
|
||||
char filename[MAX_NAME + 1];
|
||||
xSnprintf(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];
|
||||
static char buf[MAX_READ + 1];
|
||||
|
||||
int size = xread(fd, buf, MAX_READ);
|
||||
close(fd);
|
||||
if (size <= 0) return false;
|
||||
if (size <= 0)
|
||||
return false;
|
||||
buf[size] = '\0';
|
||||
|
||||
assert(process->pid == atoi(buf));
|
||||
char *location = strchr(buf, ' ');
|
||||
if (!location) return false;
|
||||
char* location = strchr(buf, ' ');
|
||||
if (!location)
|
||||
return false;
|
||||
|
||||
location += 2;
|
||||
char *end = strrchr(location, ')');
|
||||
if (!end) return false;
|
||||
char* end = strrchr(location, ')');
|
||||
if (!end)
|
||||
return false;
|
||||
|
||||
int commsize = MINIMUM(end - location, commLenIn - 1);
|
||||
// deepcode ignore BufferOverflow: commsize is bounded by the allocated length passed in by commLen, saved into commLenIn
|
||||
@ -352,14 +368,16 @@ static bool LinuxProcessList_readStatFile(Process *process, const char* dirname,
|
||||
location += 1;
|
||||
process->nlwp = strtol(location, &location, 10);
|
||||
location += 1;
|
||||
location = strchr(location, ' ')+1;
|
||||
location = strchr(location, ' ') + 1;
|
||||
if (process->starttime_ctime == 0) {
|
||||
process->starttime_ctime = btime + LinuxProcess_adjustTime(strtoll(location, &location, 10)) / 100;
|
||||
} else {
|
||||
location = strchr(location, ' ')+1;
|
||||
location = strchr(location, ' ') + 1;
|
||||
}
|
||||
location += 1;
|
||||
for (int i=0; i<15; i++) location = strchr(location, ' ')+1;
|
||||
for (int i = 0; i < 15; i++) {
|
||||
location = strchr(location, ' ') + 1;
|
||||
}
|
||||
process->exit_signal = strtol(location, &location, 10);
|
||||
location += 1;
|
||||
assert(location != NULL);
|
||||
@ -372,7 +390,7 @@ static bool LinuxProcessList_readStatFile(Process *process, const char* dirname,
|
||||
|
||||
|
||||
static bool LinuxProcessList_statProcessDir(Process* process, const char* dirname, char* name) {
|
||||
char filename[MAX_NAME+1];
|
||||
char filename[MAX_NAME + 1];
|
||||
filename[MAX_NAME] = '\0';
|
||||
|
||||
xSnprintf(filename, MAX_NAME, "%s/%s", dirname, name);
|
||||
@ -387,7 +405,7 @@ static bool LinuxProcessList_statProcessDir(Process* process, const char* dirnam
|
||||
#ifdef HAVE_TASKSTATS
|
||||
|
||||
static void LinuxProcessList_readIoFile(LinuxProcess* process, const char* dirname, char* name, unsigned long long now) {
|
||||
char filename[MAX_NAME+1];
|
||||
char filename[MAX_NAME + 1];
|
||||
filename[MAX_NAME] = '\0';
|
||||
|
||||
xSnprintf(filename, MAX_NAME, "%s/%s/io", dirname, name);
|
||||
@ -410,45 +428,47 @@ static void LinuxProcessList_readIoFile(LinuxProcess* process, const char* dirna
|
||||
char buffer[1024];
|
||||
ssize_t buflen = xread(fd, buffer, 1023);
|
||||
close(fd);
|
||||
if (buflen < 1) return;
|
||||
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;
|
||||
char* buf = buffer;
|
||||
char* line = NULL;
|
||||
while ((line = strsep(&buf, "\n")) != NULL) {
|
||||
switch (line[0]) {
|
||||
case 'r':
|
||||
if (line[1] == 'c' && String_startsWith(line+2, "har: "))
|
||||
process->io_rchar = strtoull(line+7, NULL, 10);
|
||||
else if (String_startsWith(line+1, "ead_bytes: ")) {
|
||||
process->io_read_bytes = strtoull(line+12, NULL, 10);
|
||||
if (line[1] == 'c' && String_startsWith(line + 2, "har: ")) {
|
||||
process->io_rchar = strtoull(line + 7, NULL, 10);
|
||||
} else if (String_startsWith(line + 1, "ead_bytes: ")) {
|
||||
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);
|
||||
((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' && String_startsWith(line+2, "har: "))
|
||||
process->io_wchar = strtoull(line+7, NULL, 10);
|
||||
else if (String_startsWith(line+1, "rite_bytes: ")) {
|
||||
process->io_write_bytes = strtoull(line+13, NULL, 10);
|
||||
if (line[1] == 'c' && String_startsWith(line + 2, "har: ")) {
|
||||
process->io_wchar = strtoull(line + 7, NULL, 10);
|
||||
} else if (String_startsWith(line + 1, "rite_bytes: ")) {
|
||||
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);
|
||||
((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[4] == 'r' && String_startsWith(line+1, "yscr: ")) {
|
||||
process->io_syscr = strtoull(line+7, NULL, 10);
|
||||
} else if (String_startsWith(line+1, "yscw: ")) {
|
||||
process->io_syscw = strtoull(line+7, NULL, 10);
|
||||
if (line[4] == 'r' && String_startsWith(line + 1, "yscr: ")) {
|
||||
process->io_syscr = strtoull(line + 7, NULL, 10);
|
||||
} else if (String_startsWith(line + 1, "yscw: ")) {
|
||||
process->io_syscw = strtoull(line + 7, NULL, 10);
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
if (String_startsWith(line+1, "ancelled_write_bytes: ")) {
|
||||
process->io_cancelled_write_bytes = strtoull(line+23, NULL, 10);
|
||||
}
|
||||
if (String_startsWith(line + 1, "ancelled_write_bytes: ")) {
|
||||
process->io_cancelled_write_bytes = strtoull(line + 23, NULL, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -458,11 +478,12 @@ 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];
|
||||
char filename[MAX_NAME + 1];
|
||||
xSnprintf(filename, sizeof(filename), "%s/%s/statm", dirname, name);
|
||||
FILE* statmfile = fopen(filename, "r");
|
||||
if (!statmfile)
|
||||
return false;
|
||||
|
||||
int r = fscanf(statmfile, "%ld %ld %ld %ld %ld %ld %ld",
|
||||
&process->super.m_size,
|
||||
&process->super.m_resident,
|
||||
@ -481,7 +502,7 @@ static bool LinuxProcessList_readSmapsFile(LinuxProcess* process, const char* di
|
||||
|
||||
char buffer[256];
|
||||
|
||||
if(haveSmapsRollup) {// only available in Linux 4.14+
|
||||
if (haveSmapsRollup) {// only available in Linux 4.14+
|
||||
xSnprintf(buffer, sizeof(buffer), "%s/%s/smaps_rollup", dirname, name);
|
||||
} else {
|
||||
xSnprintf(buffer, sizeof(buffer), "%s/%s/smaps", dirname, name);
|
||||
@ -496,10 +517,10 @@ static bool LinuxProcessList_readSmapsFile(LinuxProcess* process, const char* di
|
||||
process->m_psswp = 0;
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), f)) {
|
||||
if(!strchr(buffer, '\n')) {
|
||||
if (!strchr(buffer, '\n')) {
|
||||
// Partial line, skip to end of this line
|
||||
while(fgets(buffer, sizeof(buffer), f)) {
|
||||
if(strchr(buffer, '\n')) {
|
||||
while (fgets(buffer, sizeof(buffer), f)) {
|
||||
if (strchr(buffer, '\n')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -529,7 +550,7 @@ static void LinuxProcessList_readOpenVZData(LinuxProcess* process, const char* d
|
||||
return;
|
||||
}
|
||||
|
||||
char filename[MAX_NAME+1];
|
||||
char filename[MAX_NAME + 1];
|
||||
xSnprintf(filename, sizeof(filename), "%s/%s/status", dirname, name);
|
||||
FILE* file = fopen(filename, "r");
|
||||
if (!file) {
|
||||
@ -542,11 +563,11 @@ static void LinuxProcessList_readOpenVZData(LinuxProcess* process, const char* d
|
||||
bool foundEnvID = false;
|
||||
bool foundVPid = false;
|
||||
char linebuf[256];
|
||||
while(fgets(linebuf, sizeof(linebuf), file) != NULL) {
|
||||
if(strchr(linebuf, '\n') == NULL) {
|
||||
while (fgets(linebuf, sizeof(linebuf), file) != NULL) {
|
||||
if (strchr(linebuf, '\n') == NULL) {
|
||||
// Partial line, skip to end of this line
|
||||
while(fgets(linebuf, sizeof(linebuf), file) != NULL) {
|
||||
if(strchr(linebuf, '\n') != NULL) {
|
||||
while (fgets(linebuf, sizeof(linebuf), file) != NULL) {
|
||||
if (strchr(linebuf, '\n') != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -554,14 +575,14 @@ static void LinuxProcessList_readOpenVZData(LinuxProcess* process, const char* d
|
||||
}
|
||||
|
||||
char* name_value_sep = strchr(linebuf, ':');
|
||||
if(name_value_sep == NULL) {
|
||||
if (name_value_sep == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int field;
|
||||
if(0 == strncasecmp(linebuf, "envID", name_value_sep - linebuf)) {
|
||||
if (0 == strncasecmp(linebuf, "envID", name_value_sep - linebuf)) {
|
||||
field = 1;
|
||||
} else if(0 == strncasecmp(linebuf, "VPid", name_value_sep - linebuf)) {
|
||||
} else if (0 == strncasecmp(linebuf, "VPid", name_value_sep - linebuf)) {
|
||||
field = 2;
|
||||
} else {
|
||||
continue;
|
||||
@ -569,7 +590,7 @@ static void LinuxProcessList_readOpenVZData(LinuxProcess* process, const char* d
|
||||
|
||||
do {
|
||||
name_value_sep++;
|
||||
} while(*name_value_sep != '\0' && *name_value_sep <= 32);
|
||||
} while (*name_value_sep != '\0' && *name_value_sep <= 32);
|
||||
|
||||
char* value_end = name_value_sep;
|
||||
|
||||
@ -577,7 +598,7 @@ static void LinuxProcessList_readOpenVZData(LinuxProcess* process, const char* d
|
||||
value_end++;
|
||||
}
|
||||
|
||||
if(name_value_sep == value_end) {
|
||||
if (name_value_sep == value_end) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -586,7 +607,7 @@ static void LinuxProcessList_readOpenVZData(LinuxProcess* process, const char* d
|
||||
switch(field) {
|
||||
case 1:
|
||||
foundEnvID = true;
|
||||
if(!String_eq(name_value_sep, process->ctid ? process->ctid : "")) {
|
||||
if (!String_eq(name_value_sep, process->ctid ? process->ctid : "")) {
|
||||
free(process->ctid);
|
||||
process->ctid = xStrdup(name_value_sep);
|
||||
}
|
||||
@ -603,12 +624,12 @@ static void LinuxProcessList_readOpenVZData(LinuxProcess* process, const char* d
|
||||
|
||||
fclose(file);
|
||||
|
||||
if(!foundEnvID) {
|
||||
if (!foundEnvID) {
|
||||
free(process->ctid);
|
||||
process->ctid = NULL;
|
||||
}
|
||||
|
||||
if(!foundVPid) {
|
||||
if (!foundVPid) {
|
||||
process->vpid = process->super.pid;
|
||||
}
|
||||
}
|
||||
@ -618,7 +639,7 @@ static void LinuxProcessList_readOpenVZData(LinuxProcess* process, const char* d
|
||||
#ifdef HAVE_CGROUP
|
||||
|
||||
static void LinuxProcessList_readCGroupFile(LinuxProcess* process, const char* dirname, const char* name) {
|
||||
char filename[MAX_NAME+1];
|
||||
char filename[MAX_NAME + 1];
|
||||
xSnprintf(filename, MAX_NAME, "%s/%s/cgroup", dirname, name);
|
||||
FILE* file = fopen(filename, "r");
|
||||
if (!file) {
|
||||
@ -634,10 +655,14 @@ static void LinuxProcessList_readCGroupFile(LinuxProcess* process, const char* d
|
||||
int left = PROC_LINE_LENGTH;
|
||||
while (!feof(file) && left > 0) {
|
||||
char buffer[PROC_LINE_LENGTH + 1];
|
||||
char *ok = fgets(buffer, PROC_LINE_LENGTH, file);
|
||||
if (!ok) break;
|
||||
char* ok = fgets(buffer, PROC_LINE_LENGTH, file);
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
char* group = strchr(buffer, ':');
|
||||
if (!group) break;
|
||||
if (!group)
|
||||
break;
|
||||
|
||||
if (at != output) {
|
||||
*at = ';';
|
||||
at++;
|
||||
@ -656,11 +681,12 @@ static void LinuxProcessList_readCGroupFile(LinuxProcess* process, const char* d
|
||||
#ifdef HAVE_VSERVER
|
||||
|
||||
static void LinuxProcessList_readVServerData(LinuxProcess* process, const char* dirname, const char* name) {
|
||||
char filename[MAX_NAME+1];
|
||||
char filename[MAX_NAME + 1];
|
||||
xSnprintf(filename, MAX_NAME, "%s/%s/status", dirname, name);
|
||||
FILE* file = fopen(filename, "r");
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
char buffer[PROC_LINE_LENGTH + 1];
|
||||
process->vxid = 0;
|
||||
while (fgets(buffer, PROC_LINE_LENGTH, file)) {
|
||||
@ -687,7 +713,7 @@ static void LinuxProcessList_readVServerData(LinuxProcess* process, const char*
|
||||
#endif
|
||||
|
||||
static void LinuxProcessList_readOomData(LinuxProcess* process, const char* dirname, const char* name) {
|
||||
char filename[MAX_NAME+1];
|
||||
char filename[MAX_NAME + 1];
|
||||
xSnprintf(filename, MAX_NAME, "%s/%s/oom_score", dirname, name);
|
||||
FILE* file = fopen(filename, "r");
|
||||
if (!file) {
|
||||
@ -705,24 +731,27 @@ static void LinuxProcessList_readOomData(LinuxProcess* process, const char* dirn
|
||||
}
|
||||
|
||||
static void LinuxProcessList_readCtxtData(LinuxProcess* process, const char* dirname, const char* name) {
|
||||
char filename[MAX_NAME+1];
|
||||
char filename[MAX_NAME + 1];
|
||||
xSnprintf(filename, MAX_NAME, "%s/%s/status", dirname, name);
|
||||
FILE* file = fopen(filename, "r");
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
char buffer[PROC_LINE_LENGTH + 1];
|
||||
unsigned long ctxt = 0;
|
||||
while (fgets(buffer, PROC_LINE_LENGTH, file)) {
|
||||
if (String_startsWith(buffer, "voluntary_ctxt_switches:")) {
|
||||
unsigned long vctxt;
|
||||
int ok = sscanf(buffer, "voluntary_ctxt_switches:\t%lu", &vctxt);
|
||||
if (ok >= 1)
|
||||
if (ok >= 1) {
|
||||
ctxt += vctxt;
|
||||
}
|
||||
} else if (String_startsWith(buffer, "nonvoluntary_ctxt_switches:")) {
|
||||
unsigned long nvctxt;
|
||||
int ok = sscanf(buffer, "nonvoluntary_ctxt_switches:\t%lu", &nvctxt);
|
||||
if (ok >= 1)
|
||||
if (ok >= 1) {
|
||||
ctxt += nvctxt;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
@ -731,7 +760,7 @@ static void LinuxProcessList_readCtxtData(LinuxProcess* process, const char* dir
|
||||
}
|
||||
|
||||
static void LinuxProcessList_readSecattrData(LinuxProcess* process, const char* dirname, const char* name) {
|
||||
char filename[MAX_NAME+1];
|
||||
char filename[MAX_NAME + 1];
|
||||
xSnprintf(filename, sizeof(filename), "%s/%s/attr/current", dirname, name);
|
||||
FILE* file = fopen(filename, "r");
|
||||
if (!file) {
|
||||
@ -740,28 +769,30 @@ static void LinuxProcessList_readSecattrData(LinuxProcess* process, const char*
|
||||
return;
|
||||
}
|
||||
char buffer[PROC_LINE_LENGTH + 1];
|
||||
char *res = fgets(buffer, sizeof(buffer), file);
|
||||
char* res = fgets(buffer, sizeof(buffer), file);
|
||||
fclose(file);
|
||||
if (!res) {
|
||||
free(process->secattr);
|
||||
process->secattr = NULL;
|
||||
return;
|
||||
}
|
||||
char *newline = strchr(buffer, '\n');
|
||||
if (newline)
|
||||
char* newline = strchr(buffer, '\n');
|
||||
if (newline) {
|
||||
*newline = '\0';
|
||||
if (process->secattr && String_eq(process->secattr, buffer))
|
||||
}
|
||||
if (process->secattr && String_eq(process->secattr, buffer)) {
|
||||
return;
|
||||
}
|
||||
free(process->secattr);
|
||||
process->secattr = xStrdup(buffer);
|
||||
}
|
||||
|
||||
#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;
|
||||
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;
|
||||
@ -777,24 +808,25 @@ static int handleNetlinkMsg(struct nl_msg *nlmsg, void *linuxProcess) {
|
||||
memcpy(&stats, nla_data(nla_next(nla_data(nlattr), &rem)), sizeof(stats));
|
||||
assert(lp->super.pid == (pid_t)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);
|
||||
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;
|
||||
lp->delay_read_time = stats.ac_etime * 1000;
|
||||
}
|
||||
return NL_OK;
|
||||
}
|
||||
|
||||
static void LinuxProcessList_readDelayAcctData(LinuxProcessList* this, LinuxProcess* process) {
|
||||
struct nl_msg *msg;
|
||||
struct nl_msg* msg;
|
||||
|
||||
if (nl_socket_modify_cb(this->netlink_socket, NL_CB_VALID, NL_CB_CUSTOM, handleNetlinkMsg, process) < 0) {
|
||||
return;
|
||||
@ -837,13 +869,13 @@ static void setCommand(Process* process, const char* command, int len) {
|
||||
}
|
||||
|
||||
static bool LinuxProcessList_readCmdlineFile(Process* process, const char* dirname, const char* name) {
|
||||
char filename[MAX_NAME+1];
|
||||
char filename[MAX_NAME + 1];
|
||||
xSnprintf(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
|
||||
char command[4096 + 1]; // max cmdline length on Linux
|
||||
int amtRead = xread(fd, command, sizeof(command) - 1);
|
||||
close(fd);
|
||||
int tokenEnd = 0;
|
||||
@ -900,20 +932,31 @@ static char* LinuxProcessList_updateTtyDevice(TtyDriver* ttyDrivers, unsigned in
|
||||
unsigned int idx = min - ttyDrivers[i].minorFrom;
|
||||
struct stat sstat;
|
||||
char* fullPath;
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
xAsprintf(&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;
|
||||
if (err == 0 && major(sstat.st_rdev) == maj && minor(sstat.st_rdev) == min) {
|
||||
return fullPath;
|
||||
}
|
||||
free(fullPath);
|
||||
|
||||
xAsprintf(&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;
|
||||
if (err == 0 && major(sstat.st_rdev) == maj && minor(sstat.st_rdev) == min) {
|
||||
return fullPath;
|
||||
}
|
||||
free(fullPath);
|
||||
if (idx == min) break;
|
||||
|
||||
if (idx == min) {
|
||||
break;
|
||||
}
|
||||
|
||||
idx = min;
|
||||
}
|
||||
int err = stat(ttyDrivers[i].path, &sstat);
|
||||
if (err == 0 && tty_nr == sstat.st_rdev) return xStrdup(ttyDrivers[i].path);
|
||||
if (err == 0 && tty_nr == sstat.st_rdev) {
|
||||
return xStrdup(ttyDrivers[i].path);
|
||||
}
|
||||
}
|
||||
char* out;
|
||||
xAsprintf(&out, "/dev/%u:%u", maj, min);
|
||||
@ -927,11 +970,13 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
|
||||
const Settings* settings = pl->settings;
|
||||
|
||||
#ifdef HAVE_TASKSTATS
|
||||
unsigned long long now = tv.tv_sec*1000LL+tv.tv_usec/1000LL;
|
||||
unsigned long long now = tv.tv_sec * 1000LL + tv.tv_usec / 1000LL;
|
||||
#endif
|
||||
|
||||
dir = opendir(dirname);
|
||||
if (!dir) return false;
|
||||
if (!dir)
|
||||
return false;
|
||||
|
||||
int cpus = pl->cpuCount;
|
||||
bool hideKernelThreads = settings->hideKernelThreads;
|
||||
bool hideUserlandThreads = settings->hideUserlandThreads;
|
||||
@ -964,7 +1009,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
|
||||
|
||||
LinuxProcess* lp = (LinuxProcess*) proc;
|
||||
|
||||
char subdirname[MAX_NAME+1];
|
||||
char subdirname[MAX_NAME + 1];
|
||||
xSnprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name);
|
||||
LinuxProcessList_recurseProcTree(this, subdirname, proc, period, tv);
|
||||
|
||||
@ -976,41 +1021,44 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
|
||||
if (! LinuxProcessList_readStatmFile(lp, dirname, name))
|
||||
goto errorReadingProcess;
|
||||
|
||||
if ((settings->flags & PROCESS_FLAG_LINUX_SMAPS) && !Process_isKernelThread(proc)){
|
||||
if (!parent){
|
||||
if ((settings->flags & PROCESS_FLAG_LINUX_SMAPS) && !Process_isKernelThread(proc)) {
|
||||
if (!parent) {
|
||||
// Read smaps file of each process only every second pass to improve performance
|
||||
static int smaps_flag = 0;
|
||||
if ((pid & 1) == smaps_flag){
|
||||
LinuxProcessList_readSmapsFile(lp, dirname, name, this->haveSmapsRollup);
|
||||
if ((pid & 1) == smaps_flag) {
|
||||
LinuxProcessList_readSmapsFile(lp, dirname, name, this->haveSmapsRollup);
|
||||
}
|
||||
if (pid == 1) {
|
||||
smaps_flag = !smaps_flag;
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
lp->m_pss = ((LinuxProcess*)parent)->m_pss;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
|
||||
|
||||
char command[MAX_NAME+1];
|
||||
char command[MAX_NAME + 1];
|
||||
unsigned long long int lasttimes = (lp->utime + lp->stime);
|
||||
int commLen = sizeof(command);
|
||||
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)
|
||||
|
||||
if (settings->flags & PROCESS_FLAG_LINUX_IOPRIO) {
|
||||
LinuxProcess_updateIOPriority(lp);
|
||||
}
|
||||
|
||||
float percent_cpu = (lp->utime + lp->stime - lasttimes) / period * 100.0;
|
||||
proc->percent_cpu = CLAMP(percent_cpu, 0.0, cpus * 100.0);
|
||||
if (isnan(proc->percent_cpu)) proc->percent_cpu = 0.0;
|
||||
proc->percent_cpu = isnan(percent_cpu) ? 0.0 : CLAMP(percent_cpu, 0.0, cpus * 100.0);
|
||||
proc->percent_mem = (proc->m_resident * CRT_pageSizeKB) / (double)(pl->totalMem) * 100.0;
|
||||
|
||||
if(!preExisting) {
|
||||
if (!preExisting) {
|
||||
|
||||
if (! LinuxProcessList_statProcessDir(proc, dirname, name))
|
||||
goto errorReadingProcess;
|
||||
@ -1049,18 +1097,22 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CGROUP
|
||||
if (settings->flags & PROCESS_FLAG_LINUX_CGROUP)
|
||||
if (settings->flags & PROCESS_FLAG_LINUX_CGROUP) {
|
||||
LinuxProcessList_readCGroupFile(lp, dirname, name);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (settings->flags & PROCESS_FLAG_LINUX_OOM)
|
||||
if (settings->flags & PROCESS_FLAG_LINUX_OOM) {
|
||||
LinuxProcessList_readOomData(lp, dirname, name);
|
||||
}
|
||||
|
||||
if (settings->flags & PROCESS_FLAG_LINUX_CTXT)
|
||||
if (settings->flags & PROCESS_FLAG_LINUX_CTXT) {
|
||||
LinuxProcessList_readCtxtData(lp, dirname, name);
|
||||
}
|
||||
|
||||
if (settings->flags & PROCESS_FLAG_LINUX_SECATTR)
|
||||
if (settings->flags & PROCESS_FLAG_LINUX_SECATTR) {
|
||||
LinuxProcessList_readSecattrData(lp, dirname, name);
|
||||
}
|
||||
|
||||
if (proc->state == 'Z' && (proc->basenameOffset == 0)) {
|
||||
proc->basenameOffset = -1;
|
||||
@ -1070,8 +1122,9 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
|
||||
proc->basenameOffset = -1;
|
||||
setCommand(proc, command, commLen);
|
||||
} else if (settings->showThreadNames) {
|
||||
if (! LinuxProcessList_readCmdlineFile(proc, dirname, name))
|
||||
if (! LinuxProcessList_readCmdlineFile(proc, dirname, name)) {
|
||||
goto errorReadingProcess;
|
||||
}
|
||||
}
|
||||
if (Process_isKernelThread(proc)) {
|
||||
pl->kernelThreads++;
|
||||
@ -1087,7 +1140,9 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
|
||||
continue;
|
||||
|
||||
// Exception handler.
|
||||
errorReadingProcess: {
|
||||
|
||||
errorReadingProcess:
|
||||
{
|
||||
if (preExisting) {
|
||||
ProcessList_remove(pl, proc);
|
||||
} else {
|
||||
@ -1111,7 +1166,12 @@ static inline void LinuxProcessList_scanMemoryInfo(ProcessList* this) {
|
||||
char buffer[128];
|
||||
while (fgets(buffer, 128, file)) {
|
||||
|
||||
#define tryRead(label, variable) do { if (String_startsWith(buffer, label) && sscanf(buffer + strlen(label), " %32llu kB", variable)) { break; } } while(0)
|
||||
#define tryRead(label, variable) \
|
||||
if (String_startsWith(buffer, label)) { \
|
||||
sscanf(buffer + strlen(label), " %32llu kB", variable); \
|
||||
break; \
|
||||
}
|
||||
|
||||
switch (buffer[0]) {
|
||||
case 'M':
|
||||
tryRead("MemTotal:", &this->totalMem);
|
||||
@ -1157,7 +1217,7 @@ static inline void LinuxProcessList_scanZramInfo(LinuxProcessList* this) {
|
||||
char disksize[34];
|
||||
|
||||
unsigned int i = 0;
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
xSnprintf(mm_stat, sizeof(mm_stat), "/sys/block/zram%u/mm_stat", i);
|
||||
xSnprintf(disksize, sizeof(disksize), "/sys/block/zram%u/disksize", i);
|
||||
i++;
|
||||
@ -1208,8 +1268,17 @@ static inline void LinuxProcessList_scanZfsArcstats(LinuxProcessList* lpl) {
|
||||
}
|
||||
char buffer[128];
|
||||
while (fgets(buffer, 128, file)) {
|
||||
#define tryRead(label, variable) do { if (String_startsWith(buffer, label) && sscanf(buffer + strlen(label), " %*2u %32llu", variable)) { break; } } while(0)
|
||||
#define tryReadFlag(label, variable, flag) do { if (String_startsWith(buffer, label) && sscanf(buffer + strlen(label), " %*2u %32llu", variable)) { (flag) = 1; break; } else { (flag) = 0; } } while(0)
|
||||
#define tryRead(label, variable) \
|
||||
if (String_startsWith(buffer, label)) { \
|
||||
sscanf(buffer + strlen(label), " %*2u %32llu", variable); \
|
||||
break; \
|
||||
}
|
||||
#define tryReadFlag(label, variable, flag) \
|
||||
if (String_startsWith(buffer, label)) { \
|
||||
(flag) = sscanf(buffer + strlen(label), " %*2u %32llu", variable); \
|
||||
break; \
|
||||
}
|
||||
|
||||
switch (buffer[0]) {
|
||||
case 'c':
|
||||
tryRead("c_max", &lpl->zfs.max);
|
||||
@ -1275,10 +1344,13 @@ static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this) {
|
||||
// 5, 7, 8 or 9 of these fields will be set.
|
||||
// The rest will remain at zero.
|
||||
char* ok = fgets(buffer, PROC_LINE_LENGTH, file);
|
||||
if (!ok) buffer[0] = '\0';
|
||||
if (i == 0)
|
||||
if (!ok) {
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
(void) sscanf(buffer, "cpu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice);
|
||||
else {
|
||||
} else {
|
||||
int cpuid;
|
||||
(void) sscanf(buffer, "cpu%4d %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", &cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice);
|
||||
assert(cpuid == i - 1);
|
||||
@ -1322,8 +1394,8 @@ static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this) {
|
||||
cpuData->stealTime = steal;
|
||||
cpuData->guestTime = virtalltime;
|
||||
cpuData->totalTime = totaltime;
|
||||
|
||||
}
|
||||
|
||||
double period = (double)this->cpus[0].totalPeriod / cpus;
|
||||
fclose(file);
|
||||
return period;
|
||||
@ -1386,13 +1458,15 @@ static void scanCPUFreqencyFromCPUinfo(LinuxProcessList* this) {
|
||||
(sscanf(buffer, "cpu MHz : %lf", &frequency) == 1) ||
|
||||
(sscanf(buffer, "cpu MHz: %lf", &frequency) == 1)
|
||||
) {
|
||||
if (cpuid < 0 || cpuid > (cpus - 1))
|
||||
if (cpuid < 0 || cpuid > (cpus - 1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CPUData* cpuData = &(this->cpus[cpuid + 1]);
|
||||
/* do not override sysfs data */
|
||||
if (isnan(cpuData->frequency))
|
||||
if (isnan(cpuData->frequency)) {
|
||||
cpuData->frequency = frequency;
|
||||
}
|
||||
numCPUsWithFrequency++;
|
||||
totalFrequency += frequency;
|
||||
} else if (buffer[0] == '\n') {
|
||||
@ -1401,19 +1475,22 @@ static void scanCPUFreqencyFromCPUinfo(LinuxProcessList* this) {
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
if (numCPUsWithFrequency > 0)
|
||||
if (numCPUsWithFrequency > 0) {
|
||||
this->cpus[0].frequency = totalFrequency / numCPUsWithFrequency;
|
||||
}
|
||||
}
|
||||
|
||||
static void LinuxProcessList_scanCPUFrequency(LinuxProcessList* this) {
|
||||
int cpus = this->super.cpuCount;
|
||||
assert(cpus > 0);
|
||||
|
||||
for (int i = 0; i <= cpus; i++)
|
||||
for (int i = 0; i <= cpus; i++) {
|
||||
this->cpus[i].frequency = NAN;
|
||||
}
|
||||
|
||||
if (scanCPUFreqencyFromSysCPUFreq(this) == 0)
|
||||
if (scanCPUFreqencyFromSysCPUFreq(this) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
scanCPUFreqencyFromCPUinfo(this);
|
||||
}
|
||||
@ -1429,12 +1506,14 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||
|
||||
double period = LinuxProcessList_scanCPUTime(this);
|
||||
|
||||
if (settings->showCPUFrequency)
|
||||
if (settings->showCPUFrequency) {
|
||||
LinuxProcessList_scanCPUFrequency(this);
|
||||
}
|
||||
|
||||
// in pause mode only gather global data for meters (CPU/memory/...)
|
||||
if (pauseProcessUpdate)
|
||||
if (pauseProcessUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
|
@ -64,7 +64,7 @@ typedef struct LinuxProcessList_ {
|
||||
bool haveSmapsRollup;
|
||||
|
||||
#ifdef HAVE_DELAYACCT
|
||||
struct nl_sock *netlink_socket;
|
||||
struct nl_sock* netlink_socket;
|
||||
int netlink_family;
|
||||
#endif
|
||||
|
||||
|
@ -103,15 +103,18 @@ static Htop_Reaction Platform_actionSetIOPriority(State* st) {
|
||||
Panel* panel = st->panel;
|
||||
|
||||
LinuxProcess* p = (LinuxProcess*) Panel_getSelected(panel);
|
||||
if (!p) return HTOP_OK;
|
||||
if (!p)
|
||||
return HTOP_OK;
|
||||
|
||||
IOPriority ioprio1 = p->ioPriority;
|
||||
Panel* ioprioPanel = IOPriorityPanel_new(ioprio1);
|
||||
void* set = Action_pickFromVector(st, ioprioPanel, 21, true);
|
||||
if (set) {
|
||||
IOPriority ioprio2 = IOPriorityPanel_getIOPriority(ioprioPanel);
|
||||
bool ok = MainPanel_foreachProcess((MainPanel*)panel, LinuxProcess_setIOPriority, (Arg){ .i = ioprio2 }, NULL);
|
||||
if (!ok)
|
||||
bool ok = MainPanel_foreachProcess((MainPanel*)panel, LinuxProcess_setIOPriority, (Arg) { .i = ioprio2 }, NULL);
|
||||
if (!ok) {
|
||||
beep();
|
||||
}
|
||||
}
|
||||
Panel_delete((Object*)ioprioPanel);
|
||||
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
|
||||
@ -167,15 +170,20 @@ int Platform_getUptime() {
|
||||
if (fd) {
|
||||
int n = fscanf(fd, "%64lf", &uptime);
|
||||
fclose(fd);
|
||||
if (n <= 0) return 0;
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return floor(uptime);
|
||||
}
|
||||
|
||||
void Platform_getLoadAverage(double* one, double* five, double* fifteen) {
|
||||
int activeProcs, totalProcs, lastProc;
|
||||
*one = 0; *five = 0; *fifteen = 0;
|
||||
FILE *fd = fopen(PROCDIR "/loadavg", "r");
|
||||
*one = 0;
|
||||
*five = 0;
|
||||
*fifteen = 0;
|
||||
|
||||
FILE* fd = fopen(PROCDIR "/loadavg", "r");
|
||||
if (fd) {
|
||||
int total = fscanf(fd, "%32lf %32lf %32lf %32d/%32d %32d", one, five, fifteen,
|
||||
&activeProcs, &totalProcs, &lastProc);
|
||||
@ -187,7 +195,9 @@ void Platform_getLoadAverage(double* one, double* five, double* fifteen) {
|
||||
|
||||
int Platform_getMaxPid() {
|
||||
FILE* file = fopen(PROCDIR "/sys/kernel/pid_max", "r");
|
||||
if (!file) return -1;
|
||||
if (!file)
|
||||
return -1;
|
||||
|
||||
int maxPid = 4194303;
|
||||
int match = fscanf(file, "%32d", &maxPid);
|
||||
(void) match;
|
||||
@ -212,18 +222,20 @@ double Platform_setCPUValues(Meter* this, int cpu) {
|
||||
v[CPU_METER_IOWAIT] = cpuData->ioWaitPeriod / total * 100.0;
|
||||
this->curItems = 8;
|
||||
if (this->pl->settings->accountGuestInCPUMeter) {
|
||||
percent = v[0]+v[1]+v[2]+v[3]+v[4]+v[5]+v[6];
|
||||
percent = v[0] + v[1] + v[2] + v[3] + v[4] + v[5] + v[6];
|
||||
} else {
|
||||
percent = v[0]+v[1]+v[2]+v[3]+v[4];
|
||||
percent = v[0] + v[1] + v[2] + v[3] + v[4];
|
||||
}
|
||||
} else {
|
||||
v[2] = cpuData->systemAllPeriod / total * 100.0;
|
||||
v[3] = (cpuData->stealPeriod + cpuData->guestPeriod) / total * 100.0;
|
||||
this->curItems = 4;
|
||||
percent = v[0]+v[1]+v[2]+v[3];
|
||||
percent = v[0] + v[1] + v[2] + v[3];
|
||||
}
|
||||
percent = CLAMP(percent, 0.0, 100.0);
|
||||
if (isnan(percent)) percent = 0.0;
|
||||
if (isnan(percent)) {
|
||||
percent = 0.0;
|
||||
}
|
||||
|
||||
v[CPU_METER_FREQUENCY] = cpuData->frequency;
|
||||
|
||||
@ -277,10 +289,10 @@ char* Platform_getProcessEnv(pid_t pid) {
|
||||
char procname[128];
|
||||
xSnprintf(procname, sizeof(procname), PROCDIR "/%d/environ", pid);
|
||||
FILE* fd = fopen(procname, "r");
|
||||
if(!fd)
|
||||
if (!fd)
|
||||
return NULL;
|
||||
|
||||
char *env = NULL;
|
||||
char* env = NULL;
|
||||
|
||||
size_t capacity = 0;
|
||||
size_t size = 0;
|
||||
@ -304,7 +316,7 @@ char* Platform_getProcessEnv(pid_t pid) {
|
||||
env = xRealloc(env, size + 2);
|
||||
|
||||
env[size] = '\0';
|
||||
env[size+1] = '\0';
|
||||
env[size + 1] = '\0';
|
||||
|
||||
return env;
|
||||
}
|
||||
@ -423,11 +435,11 @@ FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) {
|
||||
return pdata;
|
||||
}
|
||||
|
||||
void Platform_getPressureStall(const char *file, bool some, double* ten, double* sixty, double* threehundred) {
|
||||
void Platform_getPressureStall(const char* file, bool some, double* ten, double* sixty, double* threehundred) {
|
||||
*ten = *sixty = *threehundred = 0;
|
||||
char procname[128+1];
|
||||
char procname[128 + 1];
|
||||
xSnprintf(procname, 128, PROCDIR "/pressure/%s", file);
|
||||
FILE *fd = fopen(procname, "r");
|
||||
FILE* fd = fopen(procname, "r");
|
||||
if (!fd) {
|
||||
*ten = *sixty = *threehundred = NAN;
|
||||
return;
|
||||
@ -442,7 +454,7 @@ void Platform_getPressureStall(const char *file, bool some, double* ten, double*
|
||||
}
|
||||
|
||||
bool Platform_getDiskIO(DiskIOData* data) {
|
||||
FILE *fd = fopen(PROCDIR "/diskstats", "r");
|
||||
FILE* fd = fopen(PROCDIR "/diskstats", "r");
|
||||
if (!fd)
|
||||
return false;
|
||||
|
||||
@ -486,11 +498,11 @@ bool Platform_getDiskIO(DiskIOData* data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Platform_getNetworkIO(unsigned long int *bytesReceived,
|
||||
unsigned long int *packetsReceived,
|
||||
unsigned long int *bytesTransmitted,
|
||||
unsigned long int *packetsTransmitted) {
|
||||
FILE *fd = fopen(PROCDIR "/net/dev", "r");
|
||||
bool Platform_getNetworkIO(unsigned long int* bytesReceived,
|
||||
unsigned long int* packetsReceived,
|
||||
unsigned long int* bytesTransmitted,
|
||||
unsigned long int* packetsTransmitted) {
|
||||
FILE* fd = fopen(PROCDIR "/net/dev", "r");
|
||||
if (!fd)
|
||||
return false;
|
||||
|
||||
|
@ -57,9 +57,9 @@ void Platform_getPressureStall(const char *file, bool some, double* ten, double*
|
||||
|
||||
bool Platform_getDiskIO(DiskIOData* data);
|
||||
|
||||
bool Platform_getNetworkIO(unsigned long int *bytesReceived,
|
||||
unsigned long int *packetsReceived,
|
||||
unsigned long int *bytesTransmitted,
|
||||
unsigned long int *packetsTransmitted);
|
||||
bool Platform_getNetworkIO(unsigned long int* bytesReceived,
|
||||
unsigned long int* packetsReceived,
|
||||
unsigned long int* bytesTransmitted,
|
||||
unsigned long int* packetsTransmitted);
|
||||
|
||||
#endif
|
||||
|
@ -24,24 +24,24 @@ static const int PressureStallMeter_attributes[] = {
|
||||
};
|
||||
|
||||
static void PressureStallMeter_updateValues(Meter* this, char* buffer, int len) {
|
||||
const char *file;
|
||||
if (strstr(Meter_name(this), "CPU")) {
|
||||
file = "cpu";
|
||||
} else if (strstr(Meter_name(this), "IO")) {
|
||||
file = "io";
|
||||
} else {
|
||||
file = "memory";
|
||||
}
|
||||
const char* file;
|
||||
if (strstr(Meter_name(this), "CPU")) {
|
||||
file = "cpu";
|
||||
} else if (strstr(Meter_name(this), "IO")) {
|
||||
file = "io";
|
||||
} else {
|
||||
file = "memory";
|
||||
}
|
||||
|
||||
bool some;
|
||||
if (strstr(Meter_name(this), "Some")) {
|
||||
some = true;
|
||||
} else {
|
||||
some = false;
|
||||
}
|
||||
bool some;
|
||||
if (strstr(Meter_name(this), "Some")) {
|
||||
some = true;
|
||||
} else {
|
||||
some = false;
|
||||
}
|
||||
|
||||
Platform_getPressureStall(file, some, &this->values[0], &this->values[1], &this->values[2]);
|
||||
xSnprintf(buffer, len, "xxxx %.2lf%% %.2lf%% %.2lf%%", this->values[0], this->values[1], this->values[2]);
|
||||
Platform_getPressureStall(file, some, &this->values[0], &this->values[1], &this->values[2]);
|
||||
xSnprintf(buffer, len, "xxxx %.2lf%% %.2lf%% %.2lf%%", this->values[0], this->values[1], this->values[2]);
|
||||
}
|
||||
|
||||
static void PressureStallMeter_display(const Object* cast, RichString* out) {
|
||||
|
@ -32,16 +32,19 @@ static bool enforcing = false;
|
||||
static bool hasSELinuxMount(void) {
|
||||
struct statfs sfbuf;
|
||||
int r = statfs("/sys/fs/selinux", &sfbuf);
|
||||
if (r != 0)
|
||||
if (r != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sfbuf.f_type != SELINUX_MAGIC)
|
||||
if (sfbuf.f_type != SELINUX_MAGIC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct statvfs vfsbuf;
|
||||
r = statvfs("/sys/fs/selinux", &vfsbuf);
|
||||
if (r != 0 || (vfsbuf.f_flag & ST_RDONLY))
|
||||
if (r != 0 || (vfsbuf.f_flag & ST_RDONLY)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -51,22 +54,26 @@ static bool isSelinuxEnabled(void) {
|
||||
}
|
||||
|
||||
static bool isSelinuxEnforcing(void) {
|
||||
if (!enabled)
|
||||
if (!enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int fd = open("/sys/fs/selinux/enforce", O_RDONLY);
|
||||
if (fd < 0)
|
||||
if (fd < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char buf[20] = {0};
|
||||
int r = read(fd, buf, sizeof(buf) - 1);
|
||||
close(fd);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int enforce = 0;
|
||||
if (sscanf(buf, "%d", &enforce) != 1)
|
||||
if (sscanf(buf, "%d", &enforce) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !!enforce;
|
||||
}
|
||||
|
@ -19,18 +19,18 @@ static void ZramMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
written = Meter_humanUnit(buffer, this->values[0], size);
|
||||
buffer += written;
|
||||
size -= written;
|
||||
if(size <= 0) {
|
||||
if (size <= 0) {
|
||||
return;
|
||||
}
|
||||
*buffer++ = '(';
|
||||
size--;
|
||||
if(size <= 0) {
|
||||
if (size <= 0) {
|
||||
return;
|
||||
}
|
||||
written = Meter_humanUnit(buffer, this->values[1], size);
|
||||
buffer += written;
|
||||
size -= written;
|
||||
if(size <= 0) {
|
||||
if (size <= 0) {
|
||||
return;
|
||||
}
|
||||
*buffer++ = ')';
|
||||
|
Reference in New Issue
Block a user