supgid/supgrp support, improved library interface
Library changes readproc . added support for supplementary groups . eliminated 2 potential mem leak sources . shortcut used for multi-threaded str vectors & ptrs was obsoleted . freeing of proc_t related dynamic memory now rests with the library . standardized/normalized many c comments sysinfo . corrected note regarding glibc & cpuinfo library.map . made the visible freeproc accessable Program changes pmap . initialized buffer for new readproc i/f . eliminated now obsolete free() call ps . added width aware supgrp support . initialized buffers for new readproc i/f . eliminated now obsolete free() calls top . added supgrp support as variable width . eliminated now obsolete free() calls . expoilted library freeproc function . corrected -h|v args text & spacing . updated some c comments Documentation changes ps.1 . added supgid and supgrp top.1 . added supgid and supgrp . addition of above required renumbering many fields in section 3a. DESCRIPTIONS
This commit is contained in:
parent
3f59ff5a16
commit
3ef4823f90
2
pmap.c
2
pmap.c
@ -358,11 +358,11 @@ int main(int argc, char *argv[]){
|
|||||||
|
|
||||||
discover_shm_minor();
|
discover_shm_minor();
|
||||||
|
|
||||||
|
memset(&p, '\0', sizeof(p));
|
||||||
pidlist[count] = 0; // old libproc interface is zero-terminated
|
pidlist[count] = 0; // old libproc interface is zero-terminated
|
||||||
PT = openproc(PROC_FILLSTAT|PROC_FILLARG|PROC_PID, pidlist);
|
PT = openproc(PROC_FILLSTAT|PROC_FILLARG|PROC_PID, pidlist);
|
||||||
while(readproc(PT, &p)){
|
while(readproc(PT, &p)){
|
||||||
ret |= one_proc(&p);
|
ret |= one_proc(&p);
|
||||||
if(p.cmdline) free((void*)*p.cmdline);
|
|
||||||
count--;
|
count--;
|
||||||
}
|
}
|
||||||
closeproc(PT);
|
closeproc(PT);
|
||||||
|
@ -7,7 +7,7 @@ global:
|
|||||||
|
|
||||||
readproc; readtask; readproctab; readproctab2; look_up_our_self; escape_command;
|
readproc; readtask; readproctab; readproctab2; look_up_our_self; escape_command;
|
||||||
escape_str; escape_strlist; escaped_copy; read_cmdline;
|
escape_str; escape_strlist; escaped_copy; read_cmdline;
|
||||||
openproc; closeproc;
|
openproc; closeproc; freeproc;
|
||||||
tty_to_dev; dev_to_tty; open_psdb_message; open_psdb; lookup_wchan;
|
tty_to_dev; dev_to_tty; open_psdb_message; open_psdb; lookup_wchan;
|
||||||
display_version; procps_version; linux_version_code;
|
display_version; procps_version; linux_version_code;
|
||||||
Hertz; smp_num_cpus; have_privs; getbtime;
|
Hertz; smp_num_cpus; have_privs; getbtime;
|
||||||
|
298
proc/readproc.c
298
proc/readproc.c
@ -38,6 +38,7 @@ extern void __cyg_profile_func_enter(void*,void*);
|
|||||||
#define LEAVE(x)
|
#define LEAVE(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef SIGNAL_STRING
|
||||||
// convert hex string to unsigned long long
|
// convert hex string to unsigned long long
|
||||||
static unsigned long long unhex(const char *restrict cp){
|
static unsigned long long unhex(const char *restrict cp){
|
||||||
unsigned long long ull = 0;
|
unsigned long long ull = 0;
|
||||||
@ -48,9 +49,21 @@ static unsigned long long unhex(const char *restrict cp){
|
|||||||
}
|
}
|
||||||
return ull;
|
return ull;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int task_dir_missing;
|
static int task_dir_missing;
|
||||||
|
|
||||||
|
// free any additional dynamically acquired storage associated with a proc_t
|
||||||
|
// ( and if it's to be reused, refresh it otherwise destroy it )
|
||||||
|
static inline void free_acquired (proc_t *p, int reuse) {
|
||||||
|
if (p->environ) free((void*)*p->environ);
|
||||||
|
if (p->cmdline) free((void*)*p->cmdline);
|
||||||
|
if (p->cgroup) free((void*)*p->cgroup);
|
||||||
|
if (p->supgid) free(p->supgid);
|
||||||
|
if (p->supgrp) free(p->supgrp);
|
||||||
|
memset(p, reuse ? '\0' : '\xff', sizeof(*p));
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
typedef struct status_table_struct {
|
typedef struct status_table_struct {
|
||||||
@ -71,12 +84,18 @@ typedef struct status_table_struct {
|
|||||||
#define NUL {"", 0, 0},
|
#define NUL {"", 0, 0},
|
||||||
|
|
||||||
// Derived from:
|
// Derived from:
|
||||||
// gperf -7 --language=ANSI-C --key-positions=1,3,4 -C -n -c sml.gperf
|
// gperf -7 --language=ANSI-C --key-positions=1,3,4 -C -n -c <if-not-piped>
|
||||||
//
|
//
|
||||||
// Suggested method:
|
// Suggested method:
|
||||||
// Grep this file for "case_", then strip those down to the name.
|
// Grep this file for "case_", then strip those down to the name.
|
||||||
// (leave the colon and newline) So "Pid:\n" and "Threads:\n"
|
// Eliminate duplicates (due to #ifs), the ' case_' prefix and
|
||||||
// would be lines in the file. (no quote, no escape, etc.)
|
// any c comments. Leave the colon and newline so that "Pid:\n",
|
||||||
|
// "Threads:\n", etc. would be lines, but no quote, no escape, etc.
|
||||||
|
//
|
||||||
|
// After a pipe through gperf, insert the resulting 'asso_values'
|
||||||
|
// into our 'assoc' array. Then convert the gperf 'wordlist' array
|
||||||
|
// into our 'table' array by wrapping the string literals within
|
||||||
|
// the F macro and replacing empty strings with the NUL define.
|
||||||
//
|
//
|
||||||
// In the status_table_struct watch out for name size (grrr, expanding)
|
// In the status_table_struct watch out for name size (grrr, expanding)
|
||||||
// and the number of entries (we mask with 63 for now). The table
|
// and the number of entries (we mask with 63 for now). The table
|
||||||
@ -169,17 +188,6 @@ static void status2proc(char *S, proc_t *restrict P, int is_proc){
|
|||||||
|
|
||||||
ENTER(0x220);
|
ENTER(0x220);
|
||||||
|
|
||||||
P->vm_size = 0;
|
|
||||||
P->vm_lock = 0;
|
|
||||||
P->vm_rss = 0;
|
|
||||||
P->vm_data = 0;
|
|
||||||
P->vm_stack= 0;
|
|
||||||
P->vm_exe = 0;
|
|
||||||
P->vm_lib = 0;
|
|
||||||
P->vm_swap = 0;
|
|
||||||
P->nlwp = 0;
|
|
||||||
P->signal[0] = '\0'; // so we can detect it as missing for very old kernels
|
|
||||||
|
|
||||||
goto base;
|
goto base;
|
||||||
|
|
||||||
for(;;){
|
for(;;){
|
||||||
@ -209,8 +217,8 @@ ENTER(0x220);
|
|||||||
goto *entry.addr;
|
goto *entry.addr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case_Name:{
|
case_Name:
|
||||||
unsigned u = 0;
|
{ unsigned u = 0;
|
||||||
while(u < sizeof P->cmd - 1u){
|
while(u < sizeof P->cmd - 1u){
|
||||||
int c = *S++;
|
int c = *S++;
|
||||||
if(unlikely(c=='\n')) break;
|
if(unlikely(c=='\n')) break;
|
||||||
@ -316,12 +324,25 @@ ENTER(0x220);
|
|||||||
case_VmSwap: // Linux 2.6.34
|
case_VmSwap: // Linux 2.6.34
|
||||||
P->vm_swap = strtol(S,&S,10);
|
P->vm_swap = strtol(S,&S,10);
|
||||||
continue;
|
continue;
|
||||||
|
case_Groups:
|
||||||
|
{ int j = strchr(S, '\n') - S; // currently lines end space + \n
|
||||||
|
if (j) {
|
||||||
|
P->supgid = xmalloc(j+1); // +1 in case space disappears
|
||||||
|
memcpy(P->supgid, S, j);
|
||||||
|
if (unlikely(' ' != P->supgid[--j])) ++j;
|
||||||
|
P->supgid[j] = '\0'; // whack the space or the newline
|
||||||
|
for ( ; j; j--)
|
||||||
|
if (' ' == P->supgid[j])
|
||||||
|
P->supgid[j] = ',';
|
||||||
|
} else
|
||||||
|
P->supgid = strdup("-");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
case_CapBnd:
|
case_CapBnd:
|
||||||
case_CapEff:
|
case_CapEff:
|
||||||
case_CapInh:
|
case_CapInh:
|
||||||
case_CapPrm:
|
case_CapPrm:
|
||||||
case_FDSize:
|
case_FDSize:
|
||||||
case_Groups:
|
|
||||||
case_SigQ:
|
case_SigQ:
|
||||||
case_VmHWM: // 2005, peak VmRSS unless VmRSS is bigger
|
case_VmHWM: // 2005, peak VmRSS unless VmRSS is bigger
|
||||||
case_VmPTE:
|
case_VmPTE:
|
||||||
@ -332,20 +353,20 @@ ENTER(0x220);
|
|||||||
#if 0
|
#if 0
|
||||||
// recent kernels supply per-tgid pending signals
|
// recent kernels supply per-tgid pending signals
|
||||||
if(is_proc && *ShdPnd){
|
if(is_proc && *ShdPnd){
|
||||||
memcpy(P->signal, ShdPnd, 16);
|
memcpy(P->signal, ShdPnd, 16);
|
||||||
P->signal[16] = '\0';
|
P->signal[16] = '\0';
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// recent kernels supply per-tgid pending signals
|
// recent kernels supply per-tgid pending signals
|
||||||
#ifdef SIGNAL_STRING
|
#ifdef SIGNAL_STRING
|
||||||
if(!is_proc || !P->signal[0]){
|
if(!is_proc || !P->signal[0]){
|
||||||
memcpy(P->signal, P->_sigpnd, 16);
|
memcpy(P->signal, P->_sigpnd, 16);
|
||||||
P->signal[16] = '\0';
|
P->signal[16] = '\0';
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if(!is_proc || !have_process_pending){
|
if(!is_proc){
|
||||||
P->signal = P->_sigpnd;
|
P->signal = P->_sigpnd;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -354,18 +375,36 @@ ENTER(0x220);
|
|||||||
// Only 2.6.0 and above have "Threads" (nlwp) info.
|
// Only 2.6.0 and above have "Threads" (nlwp) info.
|
||||||
|
|
||||||
if(Threads){
|
if(Threads){
|
||||||
P->nlwp = Threads;
|
P->nlwp = Threads;
|
||||||
P->tgid = Tgid; // the POSIX PID value
|
P->tgid = Tgid; // the POSIX PID value
|
||||||
P->tid = Pid; // the thread ID
|
P->tid = Pid; // the thread ID
|
||||||
}else{
|
}else{
|
||||||
P->nlwp = 1;
|
P->nlwp = 1;
|
||||||
P->tgid = Pid;
|
P->tgid = Pid;
|
||||||
P->tid = Pid;
|
P->tid = Pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
LEAVE(0x220);
|
LEAVE(0x220);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void supgrps_from_supgids (proc_t *p) {
|
||||||
|
char *g, *s;
|
||||||
|
int t;
|
||||||
|
|
||||||
|
if (!p->supgid || '-' == *p->supgid) {
|
||||||
|
p->supgrp = strdup("-");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s = p->supgid;
|
||||||
|
t = 0;
|
||||||
|
do {
|
||||||
|
if (',' == *s) ++s;
|
||||||
|
g = group_from_gid((uid_t)strtol(s, &s, 10));
|
||||||
|
p->supgrp = realloc(p->supgrp, P_G_SZ+t+2);
|
||||||
|
t += snprintf(p->supgrp+t, P_G_SZ+2, "%s%s", t ? "," : "", g);
|
||||||
|
} while (*s);
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
#ifdef OOMEM_ENABLE
|
#ifdef OOMEM_ENABLE
|
||||||
static void oomscore2proc(const char* S, proc_t *restrict P)
|
static void oomscore2proc(const char* S, proc_t *restrict P)
|
||||||
@ -521,7 +560,7 @@ static char** file2strvec(const char* directory, const char* what) {
|
|||||||
q = ret = (char**) (endbuf+align); /* ==> free(*ret) to dealloc */
|
q = ret = (char**) (endbuf+align); /* ==> free(*ret) to dealloc */
|
||||||
*q++ = p = rbuf; /* point ptrs to the strings */
|
*q++ = p = rbuf; /* point ptrs to the strings */
|
||||||
endbuf--; /* do not traverse final NUL */
|
endbuf--; /* do not traverse final NUL */
|
||||||
while (++p < endbuf)
|
while (++p < endbuf)
|
||||||
if (!*p) /* NUL char implies that */
|
if (!*p) /* NUL char implies that */
|
||||||
*q++ = p+1; /* next string -> next char */
|
*q++ = p+1; /* next string -> next char */
|
||||||
|
|
||||||
@ -652,35 +691,37 @@ int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid) {
|
|||||||
// The pid (tgid? tid?) is already in p, and a path to it in path, with some
|
// The pid (tgid? tid?) is already in p, and a path to it in path, with some
|
||||||
// room to spare.
|
// room to spare.
|
||||||
static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict const p) {
|
static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict const p) {
|
||||||
static struct stat sb; // stat() buffer
|
static struct stat sb; // stat() buffer
|
||||||
static char sbuf[1024]; // buffer for stat,statm
|
static char sbuf[1024]; // buffer for stat,statm,status
|
||||||
char *restrict const path = PT->path;
|
char *restrict const path = PT->path;
|
||||||
unsigned flags = PT->flags;
|
unsigned flags = PT->flags;
|
||||||
|
|
||||||
if (unlikely(stat(path, &sb) == -1)) /* no such dirent (anymore) */
|
if (unlikely(stat(path, &sb) == -1)) /* no such dirent (anymore) */
|
||||||
goto next_proc;
|
goto next_proc;
|
||||||
|
|
||||||
if ((flags & PROC_UID) && !XinLN(uid_t, sb.st_uid, PT->uids, PT->nuid))
|
if ((flags & PROC_UID) && !XinLN(uid_t, sb.st_uid, PT->uids, PT->nuid))
|
||||||
goto next_proc; /* not one of the requested uids */
|
goto next_proc; /* not one of the requested uids */
|
||||||
|
|
||||||
p->euid = sb.st_uid; /* need a way to get real uid */
|
p->euid = sb.st_uid; /* need a way to get real uid */
|
||||||
p->egid = sb.st_gid; /* need a way to get real gid */
|
p->egid = sb.st_gid; /* need a way to get real gid */
|
||||||
|
|
||||||
if (flags & PROC_FILLSTAT) { /* read, parse /proc/#/stat */
|
if (flags & PROC_FILLSTAT) { // read /proc/#/stat
|
||||||
if (unlikely( file2str(path, "stat", sbuf, sizeof sbuf) == -1 ))
|
if (unlikely( file2str(path, "stat", sbuf, sizeof sbuf) == -1 ))
|
||||||
goto next_proc; /* error reading /proc/#/stat */
|
goto next_proc;
|
||||||
stat2proc(sbuf, p); /* parse /proc/#/stat */
|
stat2proc(sbuf, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(flags & PROC_FILLMEM)) { /* read, parse /proc/#/statm */
|
if (flags & PROC_FILLMEM) { // read /proc/#/statm
|
||||||
if (likely( file2str(path, "statm", sbuf, sizeof sbuf) != -1 ))
|
if (likely(file2str(path, "statm", sbuf, sizeof sbuf) != -1 ))
|
||||||
statm2proc(sbuf, p); /* ignore statm errors here */
|
statm2proc(sbuf, p);
|
||||||
} /* statm fields just zero */
|
}
|
||||||
|
|
||||||
if (flags & PROC_FILLSTATUS) { /* read, parse /proc/#/status */
|
if (flags & PROC_FILLSTATUS) { // read /proc/#/status
|
||||||
if (likely( file2str(path, "status", sbuf, sizeof sbuf) != -1 )){
|
if (likely( file2str(path, "status", sbuf, sizeof sbuf) != -1 )){
|
||||||
status2proc(sbuf, p, 1);
|
status2proc(sbuf, p, 1);
|
||||||
}
|
if (flags & PROC_FILLSUPGRP)
|
||||||
|
supgrps_from_supgids(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if multithreaded, some values are crap
|
// if multithreaded, some values are crap
|
||||||
@ -688,17 +729,17 @@ static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict cons
|
|||||||
p->wchan = (KLONG)~0ull;
|
p->wchan = (KLONG)~0ull;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* some number->text resolving which is time consuming and kind of insane */
|
/* some number->text resolving which is time consuming */
|
||||||
if (flags & PROC_FILLUSR){
|
if (flags & PROC_FILLUSR){
|
||||||
memcpy(p->euser, user_from_uid(p->euid), sizeof p->euser);
|
memcpy(p->euser, user_from_uid(p->euid), sizeof p->euser);
|
||||||
if(flags & PROC_FILLSTATUS) {
|
if(flags & PROC_FILLSTATUS) {
|
||||||
memcpy(p->ruser, user_from_uid(p->ruid), sizeof p->ruser);
|
memcpy(p->ruser, user_from_uid(p->ruid), sizeof p->ruser);
|
||||||
memcpy(p->suser, user_from_uid(p->suid), sizeof p->suser);
|
memcpy(p->suser, user_from_uid(p->suid), sizeof p->suser);
|
||||||
memcpy(p->fuser, user_from_uid(p->fuid), sizeof p->fuser);
|
memcpy(p->fuser, user_from_uid(p->fuid), sizeof p->fuser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* some number->text resolving which is time consuming and kind of insane */
|
/* some number->text resolving which is time consuming */
|
||||||
if (flags & PROC_FILLGRP){
|
if (flags & PROC_FILLGRP){
|
||||||
memcpy(p->egroup, group_from_gid(p->egid), sizeof p->egroup);
|
memcpy(p->egroup, group_from_gid(p->egid), sizeof p->egroup);
|
||||||
if(flags & PROC_FILLSTATUS) {
|
if(flags & PROC_FILLSTATUS) {
|
||||||
@ -708,12 +749,12 @@ static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict cons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(flags & PROC_FILLENV)) /* read /proc/#/environ */
|
if (unlikely(flags & PROC_FILLENV)) // read /proc/#/environ
|
||||||
p->environ = file2strvec(path, "environ");
|
p->environ = file2strvec(path, "environ");
|
||||||
else
|
else
|
||||||
p->environ = NULL;
|
p->environ = NULL;
|
||||||
|
|
||||||
if (flags & (PROC_FILLCOM|PROC_FILLARG)) { /* read /proc/#/cmdline */
|
if (flags & (PROC_FILLCOM|PROC_FILLARG)) { // read /proc/#/cmdline
|
||||||
if (flags & PROC_EDITCMDLCVT)
|
if (flags & PROC_EDITCMDLCVT)
|
||||||
fill_cmdline_cvt(p);
|
fill_cmdline_cvt(p);
|
||||||
else
|
else
|
||||||
@ -721,7 +762,7 @@ static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict cons
|
|||||||
} else
|
} else
|
||||||
p->cmdline = NULL;
|
p->cmdline = NULL;
|
||||||
|
|
||||||
if ((flags & PROC_FILLCGROUP) /* read /proc/#/cgroup, if possible */
|
if ((flags & PROC_FILLCGROUP) // read /proc/#/cgroup
|
||||||
&& linux_version_code >= LINUX_VERSION(2,6,24)) {
|
&& linux_version_code >= LINUX_VERSION(2,6,24)) {
|
||||||
if (flags & PROC_EDITCGRPCVT)
|
if (flags & PROC_EDITCGRPCVT)
|
||||||
fill_cgroup_cvt(p);
|
fill_cgroup_cvt(p);
|
||||||
@ -750,55 +791,55 @@ next_proc:
|
|||||||
// t is the POSIX thread (task group member, generally not the leader)
|
// t is the POSIX thread (task group member, generally not the leader)
|
||||||
// path is a path to the task, with some room to spare.
|
// path is a path to the task, with some room to spare.
|
||||||
static proc_t* simple_readtask(PROCTAB *restrict const PT, const proc_t *restrict const p, proc_t *restrict const t, char *restrict const path) {
|
static proc_t* simple_readtask(PROCTAB *restrict const PT, const proc_t *restrict const p, proc_t *restrict const t, char *restrict const path) {
|
||||||
static struct stat sb; // stat() buffer
|
static struct stat sb; // stat() buffer
|
||||||
static char sbuf[1024]; // buffer for stat,statm
|
static char sbuf[1024]; // buffer for stat,statm,status
|
||||||
unsigned flags = PT->flags;
|
unsigned flags = PT->flags;
|
||||||
|
|
||||||
//printf("hhh\n");
|
if (unlikely(stat(path, &sb) == -1)) /* no such dirent (anymore) */
|
||||||
if (unlikely(stat(path, &sb) == -1)) /* no such dirent (anymore) */
|
goto next_task;
|
||||||
goto next_task;
|
|
||||||
|
|
||||||
// if ((flags & PROC_UID) && !XinLN(uid_t, sb.st_uid, PT->uids, PT->nuid))
|
// if ((flags & PROC_UID) && !XinLN(uid_t, sb.st_uid, PT->uids, PT->nuid))
|
||||||
// goto next_task; /* not one of the requested uids */
|
// goto next_task; /* not one of the requested uids */
|
||||||
|
|
||||||
t->euid = sb.st_uid; /* need a way to get real uid */
|
t->euid = sb.st_uid; /* need a way to get real uid */
|
||||||
t->egid = sb.st_gid; /* need a way to get real gid */
|
t->egid = sb.st_gid; /* need a way to get real gid */
|
||||||
|
|
||||||
//printf("iii\n");
|
if (flags & PROC_FILLSTAT) { // read /proc/#/task/#/stat
|
||||||
if (flags & PROC_FILLSTAT) { /* read, parse /proc/#/stat */
|
if (unlikely( file2str(path, "stat", sbuf, sizeof sbuf) == -1 ))
|
||||||
if (unlikely( file2str(path, "stat", sbuf, sizeof sbuf) == -1 ))
|
goto next_task;
|
||||||
goto next_task; /* error reading /proc/#/stat */
|
stat2proc(sbuf, t);
|
||||||
stat2proc(sbuf, t); /* parse /proc/#/stat */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(flags & PROC_FILLMEM)) { /* read, parse /proc/#/statm */
|
if (flags & PROC_FILLMEM) { // read /proc/#/task/#statm
|
||||||
#if 0
|
#if 1
|
||||||
if (likely( file2str(path, "statm", sbuf, sizeof sbuf) != -1 ))
|
if (likely(file2str(path, "statm", sbuf, sizeof sbuf) != -1 ))
|
||||||
statm2proc(sbuf, t); /* ignore statm errors here */
|
statm2proc(sbuf, t);
|
||||||
#else
|
#else
|
||||||
t->size = p->size;
|
t->size = p->size;
|
||||||
t->resident = p->resident;
|
t->resident = p->resident;
|
||||||
t->share = p->share;
|
t->share = p->share;
|
||||||
t->trs = p->trs;
|
t->trs = p->trs;
|
||||||
t->lrs = p->lrs;
|
t->lrs = p->lrs;
|
||||||
t->drs = p->drs;
|
t->drs = p->drs;
|
||||||
t->dt = p->dt;
|
t->dt = p->dt;
|
||||||
#endif
|
#endif
|
||||||
} /* statm fields just zero */
|
}
|
||||||
|
|
||||||
if (flags & PROC_FILLSTATUS) { /* read, parse /proc/#/status */
|
if (flags & PROC_FILLSTATUS) { // read /proc/#/task/#/status
|
||||||
if (likely( file2str(path, "status", sbuf, sizeof sbuf) != -1 )){
|
if (likely( file2str(path, "status", sbuf, sizeof sbuf) != -1 )){
|
||||||
status2proc(sbuf, t, 0);
|
status2proc(sbuf, t, 0);
|
||||||
|
if (flags & PROC_FILLSUPGRP)
|
||||||
|
supgrps_from_supgids(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* some number->text resolving which is time consuming */
|
/* some number->text resolving which is time consuming */
|
||||||
if (flags & PROC_FILLUSR){
|
if (flags & PROC_FILLUSR){
|
||||||
memcpy(t->euser, user_from_uid(t->euid), sizeof t->euser);
|
memcpy(t->euser, user_from_uid(t->euid), sizeof t->euser);
|
||||||
if(flags & PROC_FILLSTATUS) {
|
if(flags & PROC_FILLSTATUS) {
|
||||||
memcpy(t->ruser, user_from_uid(t->ruid), sizeof t->ruser);
|
memcpy(t->ruser, user_from_uid(t->ruid), sizeof t->ruser);
|
||||||
memcpy(t->suser, user_from_uid(t->suid), sizeof t->suser);
|
memcpy(t->suser, user_from_uid(t->suid), sizeof t->suser);
|
||||||
memcpy(t->fuser, user_from_uid(t->fuid), sizeof t->fuser);
|
memcpy(t->fuser, user_from_uid(t->fuid), sizeof t->fuser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -812,21 +853,42 @@ static proc_t* simple_readtask(PROCTAB *restrict const PT, const proc_t *restric
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 1 // begin active ------------------------
|
||||||
if ((flags & PROC_FILLCOM) || (flags & PROC_FILLARG)) /* read+parse /proc/#/cmdline */
|
if (unlikely(flags & PROC_FILLENV)) // read /proc/#/task/#/environ
|
||||||
t->cmdline = file2strvec(path, "cmdline");
|
t->environ = file2strvec(path, "environ");
|
||||||
else
|
|
||||||
t->cmdline = NULL;
|
|
||||||
|
|
||||||
if (unlikely(flags & PROC_FILLENV)) /* read+parse /proc/#/environ */
|
|
||||||
t->environ = file2strvec(path, "environ");
|
|
||||||
else
|
else
|
||||||
t->environ = NULL;
|
t->environ = NULL;
|
||||||
#else
|
|
||||||
|
if (flags & (PROC_FILLCOM|PROC_FILLARG)) { // read /proc/#/task/#/cmdline
|
||||||
|
if (flags & PROC_EDITCMDLCVT)
|
||||||
|
fill_cmdline_cvt(t);
|
||||||
|
else
|
||||||
|
t->cmdline = file2strvec(path, "cmdline");
|
||||||
|
} else
|
||||||
|
t->cmdline = NULL;
|
||||||
|
|
||||||
|
if ((flags & PROC_FILLCGROUP) // read /proc/#/task/#/cgroup
|
||||||
|
&& linux_version_code >= LINUX_VERSION(2,6,24)) {
|
||||||
|
if (flags & PROC_EDITCGRPCVT)
|
||||||
|
fill_cgroup_cvt(t);
|
||||||
|
else
|
||||||
|
t->cgroup = file2strvec(path, "cgroup");
|
||||||
|
} else
|
||||||
|
t->cgroup = NULL;
|
||||||
|
#else // end active --------------------------
|
||||||
t->cmdline = p->cmdline; // better not free these until done with all threads!
|
t->cmdline = p->cmdline; // better not free these until done with all threads!
|
||||||
t->environ = p->environ;
|
t->environ = p->environ;
|
||||||
|
t->cgroup = p->cgroup;
|
||||||
|
t->supgid = p->supgid;
|
||||||
|
t->supgrp = p->supgrp;
|
||||||
|
#error we DO NOT BURDEN library users with the above insanity ANYMORE !
|
||||||
|
#endif // end inactive ------------------------
|
||||||
|
|
||||||
|
#ifdef OOMEM_ENABLE
|
||||||
|
t->oom_score = p->oom_score;
|
||||||
|
t->oom_adj = p->oom_adj;
|
||||||
#endif
|
#endif
|
||||||
t->cgroup = p->cgroup;
|
|
||||||
t->ppid = p->ppid; // ought to put the per-task ppid somewhere
|
t->ppid = p->ppid; // ought to put the per-task ppid somewhere
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
@ -916,7 +978,8 @@ proc_t* readproc(PROCTAB *restrict const PT, proc_t *restrict p) {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
saved_p = p;
|
saved_p = p;
|
||||||
if(!p) p = xcalloc(p, sizeof *p); /* passed buf or alloced mem */
|
if(!p) p = xcalloc(NULL, sizeof *p);
|
||||||
|
else free_acquired(p, 1);
|
||||||
|
|
||||||
for(;;){
|
for(;;){
|
||||||
// fills in the path, plus p->tid and p->tgid
|
// fills in the path, plus p->tid and p->tgid
|
||||||
@ -944,20 +1007,25 @@ proc_t* readtask(PROCTAB *restrict const PT, const proc_t *restrict const p, pro
|
|||||||
proc_t *saved_t;
|
proc_t *saved_t;
|
||||||
|
|
||||||
saved_t = t;
|
saved_t = t;
|
||||||
if(!t) t = xcalloc(t, sizeof *t); /* passed buf or alloced mem */
|
if(!t) t = xcalloc(NULL, sizeof *t);
|
||||||
|
else free_acquired(t, 1);
|
||||||
|
|
||||||
// 1. got to fake a thread for old kernels
|
// 1. got to fake a thread for old kernels
|
||||||
// 2. for single-threaded processes, this is faster (but must patch up stuff that differs!)
|
if(task_dir_missing) {
|
||||||
if(task_dir_missing || p->nlwp < 2){
|
|
||||||
if(PT->did_fake) goto out;
|
if(PT->did_fake) goto out;
|
||||||
PT->did_fake=1;
|
PT->did_fake=1;
|
||||||
memcpy(t,p,sizeof(proc_t));
|
memcpy(t,p,sizeof(proc_t));
|
||||||
// use the per-task pending, not per-tgid pending
|
// use the per-task pending, not per-tgid pending
|
||||||
#ifdef SIGNAL_STRING
|
#ifdef SIGNAL_STRING
|
||||||
memcpy(&t->signal, &t->_sigpnd, sizeof t->signal);
|
memcpy(&t->signal, &t->_sigpnd, sizeof t->signal);
|
||||||
#else
|
#else
|
||||||
t->signal = t->_sigpnd;
|
t->signal = t->_sigpnd;
|
||||||
#endif
|
#endif
|
||||||
|
t->environ = NULL;
|
||||||
|
t->cmdline = vectorize_this_str("n/a");
|
||||||
|
t->cgroup = NULL;
|
||||||
|
t->supgid = NULL;
|
||||||
|
t->supgrp = NULL;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1026,19 +1094,12 @@ void closeproc(PROCTAB* PT) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// deallocate the space allocated by readproc if the passed rbuf was NULL
|
// deallocate space allocated by readproc
|
||||||
void freeproc(proc_t* p) {
|
void freeproc(proc_t* p) {
|
||||||
if (!p) /* in case p is NULL */
|
if (p) {
|
||||||
return;
|
free_acquired(p, 0);
|
||||||
/* ptrs are after strings to avoid copying memory when building them. */
|
free(p);
|
||||||
/* so free is called on the address of the address of strvec[0]. */
|
}
|
||||||
if (p->cmdline)
|
|
||||||
free((void*)*p->cmdline);
|
|
||||||
if (p->environ)
|
|
||||||
free((void*)*p->environ);
|
|
||||||
if (p->cgroup)
|
|
||||||
free((void*)*p->cgroup);
|
|
||||||
free(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1115,6 +1176,7 @@ proc_data_t *readproctab2(int(*want_proc)(proc_t *buf), int(*want_task)(proc_t *
|
|||||||
n_alloc = n_alloc*5/4+30; // grow by over 25%
|
n_alloc = n_alloc*5/4+30; // grow by over 25%
|
||||||
data = realloc(data,sizeof(proc_t)*n_alloc);
|
data = realloc(data,sizeof(proc_t)*n_alloc);
|
||||||
//if(!data) return NULL;
|
//if(!data) return NULL;
|
||||||
|
memset(data+n_used, 0, sizeof(proc_t)*(n_alloc-n_used));
|
||||||
}
|
}
|
||||||
if(n_proc_alloc == n_proc){
|
if(n_proc_alloc == n_proc){
|
||||||
//proc_t **old = ptab;
|
//proc_t **old = ptab;
|
||||||
@ -1133,8 +1195,8 @@ proc_data_t *readproctab2(int(*want_proc)(proc_t *buf), int(*want_task)(proc_t *
|
|||||||
proc_t *old = data;
|
proc_t *old = data;
|
||||||
n_alloc = n_alloc*5/4+30; // grow by over 25%
|
n_alloc = n_alloc*5/4+30; // grow by over 25%
|
||||||
data = realloc(data,sizeof(proc_t)*n_alloc);
|
data = realloc(data,sizeof(proc_t)*n_alloc);
|
||||||
// have to move tmp too
|
// have to move tmp too
|
||||||
tmp = data+(tmp-old);
|
tmp = data+(tmp-old);
|
||||||
//if(!data) return NULL;
|
//if(!data) return NULL;
|
||||||
}
|
}
|
||||||
if(n_task_alloc == n_task){
|
if(n_task_alloc == n_task){
|
||||||
|
@ -113,7 +113,9 @@ typedef struct proc_t {
|
|||||||
char
|
char
|
||||||
**environ, // (special) environment string vector (/proc/#/environ)
|
**environ, // (special) environment string vector (/proc/#/environ)
|
||||||
**cmdline, // (special) command line string vector (/proc/#/cmdline)
|
**cmdline, // (special) command line string vector (/proc/#/cmdline)
|
||||||
**cgroup; // (special) cgroup string vector (/proc/#/cgroup)
|
**cgroup, // (special) cgroup string vector (/proc/#/cgroup)
|
||||||
|
*supgid, // status supplementary gids as comma delimited str
|
||||||
|
*supgrp; // supp grp names as comma delimited str, derived from supgid
|
||||||
char
|
char
|
||||||
// Be compatible: Digital allows 16 and NT allows 14 ???
|
// Be compatible: Digital allows 16 and NT allows 14 ???
|
||||||
euser[P_G_SZ], // stat(),status effective user name
|
euser[P_G_SZ], // stat(),status effective user name
|
||||||
@ -180,7 +182,7 @@ typedef struct PROCTAB {
|
|||||||
unsigned pathlen; // length of string in the above (w/o '\0')
|
unsigned pathlen; // length of string in the above (w/o '\0')
|
||||||
} PROCTAB;
|
} PROCTAB;
|
||||||
|
|
||||||
// initialize a PROCTAB structure holding needed call-to-call persistent data
|
// Initialize a PROCTAB structure holding needed call-to-call persistent data
|
||||||
extern PROCTAB* openproc(int flags, ... /* pid_t*|uid_t*|dev_t*|char* [, int n] */ );
|
extern PROCTAB* openproc(int flags, ... /* pid_t*|uid_t*|dev_t*|char* [, int n] */ );
|
||||||
|
|
||||||
typedef struct proc_data_t {
|
typedef struct proc_data_t {
|
||||||
@ -198,13 +200,21 @@ extern proc_data_t *readproctab2(int(*want_proc)(proc_t *buf), int(*want_task)(p
|
|||||||
// table subset satisfying the constraints of flags and the optional PID list.
|
// table subset satisfying the constraints of flags and the optional PID list.
|
||||||
// Free allocated memory with exit(). Access via tab[N]->member. The pointer
|
// Free allocated memory with exit(). Access via tab[N]->member. The pointer
|
||||||
// list is NULL terminated.
|
// list is NULL terminated.
|
||||||
|
|
||||||
extern proc_t** readproctab(int flags, ... /* same as openproc */ );
|
extern proc_t** readproctab(int flags, ... /* same as openproc */ );
|
||||||
|
|
||||||
// clean-up open files, etc from the openproc()
|
// Clean-up open files, etc from the openproc()
|
||||||
extern void closeproc(PROCTAB* PT);
|
extern void closeproc(PROCTAB* PT);
|
||||||
|
|
||||||
// retrieve the next process matching the criteria set by the openproc()
|
// Retrieve the next process or task matching the criteria set by the openproc().
|
||||||
|
//
|
||||||
|
// Note: When NULL is used as the readproc 'p' or readtask 't' parameter,
|
||||||
|
// the library will allocate the necessary proc_t storage.
|
||||||
|
//
|
||||||
|
// Alternately, you may provide your own reuseable buffer address
|
||||||
|
// in which case that buffer *MUST* be initialized to zero one time
|
||||||
|
// only before first use. Thereafter, the library will manage such
|
||||||
|
// a passed proc_t, freeing any additional acquired memory associated
|
||||||
|
// with the previous process or thread.
|
||||||
extern proc_t* readproc(PROCTAB *restrict const PT, proc_t *restrict p);
|
extern proc_t* readproc(PROCTAB *restrict const PT, proc_t *restrict p);
|
||||||
extern proc_t* readtask(PROCTAB *restrict const PT, const proc_t *restrict const p, proc_t *restrict t);
|
extern proc_t* readtask(PROCTAB *restrict const PT, const proc_t *restrict const p, proc_t *restrict t);
|
||||||
|
|
||||||
@ -213,11 +223,10 @@ extern int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid);
|
|||||||
|
|
||||||
extern void look_up_our_self(proc_t *p);
|
extern void look_up_our_self(proc_t *p);
|
||||||
|
|
||||||
// deallocate space allocated by readproc
|
// Deallocate space allocated by readproc
|
||||||
|
|
||||||
extern void freeproc(proc_t* p);
|
extern void freeproc(proc_t* p);
|
||||||
|
|
||||||
//fill out a proc_t for a single task
|
// Fill out a proc_t for a single task
|
||||||
extern proc_t * get_proc_stats(pid_t pid, proc_t *p);
|
extern proc_t * get_proc_stats(pid_t pid, proc_t *p);
|
||||||
|
|
||||||
// openproc/readproctab:
|
// openproc/readproctab:
|
||||||
@ -244,7 +253,8 @@ extern proc_t * get_proc_stats(pid_t pid, proc_t *p);
|
|||||||
#define PROC_FILLWCHAN 0x0080 // look up WCHAN name
|
#define PROC_FILLWCHAN 0x0080 // look up WCHAN name
|
||||||
#define PROC_FILLARG 0x0100 // alloc and fill in `cmdline'
|
#define PROC_FILLARG 0x0100 // alloc and fill in `cmdline'
|
||||||
#define PROC_FILLCGROUP 0x0200 // alloc and fill in `cgroup`
|
#define PROC_FILLCGROUP 0x0200 // alloc and fill in `cgroup`
|
||||||
#define PROC_FILLOOM 0x0400 // alloc and fill in oom_score, oom_adj
|
#define PROC_FILLSUPGRP 0x0400 // resolve supplementary group id -> group name
|
||||||
|
#define PROC_FILLOOM 0x0800 // alloc and fill in oom_score, oom_adj
|
||||||
|
|
||||||
#define PROC_LOOSE_TASKS 0x2000 // threat threads as if they were processes
|
#define PROC_LOOSE_TASKS 0x2000 // threat threads as if they were processes
|
||||||
|
|
||||||
|
@ -947,6 +947,9 @@ out:
|
|||||||
void cpuinfo (void) {
|
void cpuinfo (void) {
|
||||||
// ought to count CPUs in /proc/stat instead of relying
|
// ought to count CPUs in /proc/stat instead of relying
|
||||||
// on glibc, which foolishly tries to parse /proc/cpuinfo
|
// on glibc, which foolishly tries to parse /proc/cpuinfo
|
||||||
|
// note: that may have been the case but now /proc/stat
|
||||||
|
// is the default source. parsing of /proc/cpuinfo
|
||||||
|
// only occurs if the open on /proc/stat fails
|
||||||
//
|
//
|
||||||
// SourceForge has an old Alpha running Linux 2.2.20 that
|
// SourceForge has an old Alpha running Linux 2.2.20 that
|
||||||
// appears to have a non-SMP kernel on a 2-way SMP box.
|
// appears to have a non-SMP kernel on a 2-way SMP box.
|
||||||
|
30
ps/display.c
30
ps/display.c
@ -327,61 +327,46 @@ static int want_this_proc_pcpu(proc_t *buf){
|
|||||||
|
|
||||||
/***** just display */
|
/***** just display */
|
||||||
static void simple_spew(void){
|
static void simple_spew(void){
|
||||||
proc_t buf;
|
static proc_t buf, buf2; // static avoids memset
|
||||||
PROCTAB* ptp;
|
PROCTAB* ptp;
|
||||||
|
|
||||||
ptp = openproc(needs_for_format | needs_for_sort | needs_for_select | needs_for_threads);
|
ptp = openproc(needs_for_format | needs_for_sort | needs_for_select | needs_for_threads);
|
||||||
if(!ptp) {
|
if(!ptp) {
|
||||||
fprintf(stderr, "Error: can not access /proc.\n");
|
fprintf(stderr, "Error: can not access /proc.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
memset(&buf, '#', sizeof(proc_t));
|
|
||||||
switch(thread_flags & (TF_show_proc|TF_loose_tasks|TF_show_task)){
|
switch(thread_flags & (TF_show_proc|TF_loose_tasks|TF_show_task)){
|
||||||
case TF_show_proc: // normal non-thread output
|
case TF_show_proc: // normal non-thread output
|
||||||
while(readproc(ptp,&buf)){
|
while(readproc(ptp,&buf)){
|
||||||
if(want_this_proc(&buf)){
|
if(want_this_proc(&buf)){
|
||||||
show_one_proc(&buf, proc_format_list);
|
show_one_proc(&buf, proc_format_list);
|
||||||
}
|
}
|
||||||
if(buf.cmdline) free((void*)*buf.cmdline); // ought to reuse
|
|
||||||
if(buf.environ) free((void*)*buf.environ); // ought to reuse
|
|
||||||
if(buf.cgroup) free((void*)*buf.cgroup);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TF_show_proc|TF_loose_tasks: // H option
|
case TF_show_proc|TF_loose_tasks: // H option
|
||||||
while(readproc(ptp,&buf)){
|
while(readproc(ptp,&buf)){
|
||||||
proc_t buf2;
|
|
||||||
// must still have the process allocated
|
// must still have the process allocated
|
||||||
while(readtask(ptp,&buf,&buf2)){
|
while(readtask(ptp,&buf,&buf2)){
|
||||||
if(!want_this_proc(&buf)) continue;
|
if(!want_this_proc(&buf)) continue;
|
||||||
show_one_proc(&buf2, task_format_list);
|
show_one_proc(&buf2, task_format_list);
|
||||||
}
|
}
|
||||||
if(buf.cmdline) free((void*)*buf.cmdline); // ought to reuse
|
|
||||||
if(buf.environ) free((void*)*buf.environ); // ought to reuse
|
|
||||||
if(buf.cgroup) free((void*)*buf.cgroup);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TF_show_proc|TF_show_task: // m and -m options
|
case TF_show_proc|TF_show_task: // m and -m options
|
||||||
while(readproc(ptp,&buf)){
|
while(readproc(ptp,&buf)){
|
||||||
if(want_this_proc(&buf)){
|
if(want_this_proc(&buf)){
|
||||||
proc_t buf2;
|
|
||||||
show_one_proc(&buf, proc_format_list);
|
show_one_proc(&buf, proc_format_list);
|
||||||
// must still have the process allocated
|
// must still have the process allocated
|
||||||
while(readtask(ptp,&buf,&buf2)) show_one_proc(&buf2, task_format_list);
|
while(readtask(ptp,&buf,&buf2)) show_one_proc(&buf2, task_format_list);
|
||||||
}
|
}
|
||||||
if(buf.cmdline) free((void*)*buf.cmdline); // ought to reuse
|
|
||||||
if(buf.environ) free((void*)*buf.environ); // ought to reuse
|
|
||||||
if(buf.cgroup) free((void*)*buf.cgroup);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TF_show_task: // -L and -T options
|
case TF_show_task: // -L and -T options
|
||||||
while(readproc(ptp,&buf)){
|
while(readproc(ptp,&buf)){
|
||||||
if(want_this_proc(&buf)){
|
if(want_this_proc(&buf)){
|
||||||
proc_t buf2;
|
|
||||||
// must still have the process allocated
|
// must still have the process allocated
|
||||||
while(readtask(ptp,&buf,&buf2)) show_one_proc(&buf2, task_format_list);
|
while(readtask(ptp,&buf,&buf2)) show_one_proc(&buf2, task_format_list);
|
||||||
}
|
}
|
||||||
if(buf.cmdline) free((void*)*buf.cmdline); // ought to reuse
|
|
||||||
if(buf.environ) free((void*)*buf.environ); // ought to reuse
|
|
||||||
if(buf.cgroup) free((void*)*buf.cgroup);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -438,16 +423,10 @@ static void show_proc_array(PROCTAB *restrict ptp, int n){
|
|||||||
while(n--){
|
while(n--){
|
||||||
if(thread_flags & TF_show_proc) show_one_proc(*p, proc_format_list);
|
if(thread_flags & TF_show_proc) show_one_proc(*p, proc_format_list);
|
||||||
if(thread_flags & TF_show_task){
|
if(thread_flags & TF_show_task){
|
||||||
proc_t buf2;
|
static proc_t buf2; // static avoids memset
|
||||||
// must still have the process allocated
|
// must still have the process allocated
|
||||||
while(readtask(ptp,*p,&buf2)) show_one_proc(&buf2, task_format_list);
|
while(readtask(ptp,*p,&buf2)) show_one_proc(&buf2, task_format_list);
|
||||||
// must not attempt to free cmdline and environ
|
|
||||||
}
|
}
|
||||||
/* no point freeing any of this -- won't need more mem */
|
|
||||||
// if((*p)->cmdline) free((void*)*(*p)->cmdline);
|
|
||||||
// if((*p)->environ) free((void*)*(*p)->environ);
|
|
||||||
// memset(*p, '%', sizeof(proc_t)); /* debug */
|
|
||||||
// free(*p);
|
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -464,9 +443,6 @@ static void show_tree(const int self, const int n, const int level, const int ha
|
|||||||
forest_prefix[level] = '\0';
|
forest_prefix[level] = '\0';
|
||||||
}
|
}
|
||||||
show_one_proc(processes[self],format_list); /* first show self */
|
show_one_proc(processes[self],format_list); /* first show self */
|
||||||
/* no point freeing any of this -- won't need more mem */
|
|
||||||
// if(processes[self]->cmdline) free((void*)*processes[self]->cmdline);
|
|
||||||
// if(processes[self]->environ) free((void*)*processes[self]->environ);
|
|
||||||
for(;;){ /* look for children */
|
for(;;){ /* look for children */
|
||||||
if(i >= n) return; /* no children */
|
if(i >= n) return; /* no children */
|
||||||
if(processes[i]->ppid == processes[self]->XXXID) break;
|
if(processes[i]->ppid == processes[self]->XXXID) break;
|
||||||
|
38
ps/output.c
38
ps/output.c
@ -38,7 +38,7 @@
|
|||||||
*
|
*
|
||||||
* Table 5 could go in a file with the output functions.
|
* Table 5 could go in a file with the output functions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
@ -360,7 +360,7 @@ static int pr_argcom(char *restrict const outbuf, const proc_t *restrict const p
|
|||||||
|
|
||||||
static int pr_cgroup(char *restrict const outbuf,const proc_t *restrict const pp) {
|
static int pr_cgroup(char *restrict const outbuf,const proc_t *restrict const pp) {
|
||||||
int rightward = max_rightward;
|
int rightward = max_rightward;
|
||||||
|
|
||||||
if(pp->cgroup) {
|
if(pp->cgroup) {
|
||||||
escaped_copy(outbuf, *pp->cgroup, OUTBUF_SIZE, &rightward);
|
escaped_copy(outbuf, *pp->cgroup, OUTBUF_SIZE, &rightward);
|
||||||
return max_rightward-rightward;
|
return max_rightward-rightward;
|
||||||
@ -373,7 +373,7 @@ static int pr_cgroup(char *restrict const outbuf,const proc_t *restrict const pp
|
|||||||
static int pr_fname(char *restrict const outbuf, const proc_t *restrict const pp){
|
static int pr_fname(char *restrict const outbuf, const proc_t *restrict const pp){
|
||||||
char *endp = outbuf;
|
char *endp = outbuf;
|
||||||
int rightward = max_rightward;
|
int rightward = max_rightward;
|
||||||
|
|
||||||
if(forest_prefix){
|
if(forest_prefix){
|
||||||
int fh = forest_helper(outbuf);
|
int fh = forest_helper(outbuf);
|
||||||
endp += fh;
|
endp += fh;
|
||||||
@ -381,7 +381,7 @@ static int pr_fname(char *restrict const outbuf, const proc_t *restrict const pp
|
|||||||
}
|
}
|
||||||
if (rightward>8) /* 8=default, but forest maybe feeds more */
|
if (rightward>8) /* 8=default, but forest maybe feeds more */
|
||||||
rightward = 8;
|
rightward = 8;
|
||||||
|
|
||||||
endp += escape_str(endp, pp->cmd, OUTBUF_SIZE, &rightward);
|
endp += escape_str(endp, pp->cmd, OUTBUF_SIZE, &rightward);
|
||||||
//return endp - outbuf;
|
//return endp - outbuf;
|
||||||
return max_rightward-rightward;
|
return max_rightward-rightward;
|
||||||
@ -1022,10 +1022,10 @@ static int do_pr_name(char *restrict const outbuf, const char *restrict const na
|
|||||||
if(!user_is_number){
|
if(!user_is_number){
|
||||||
int rightward = OUTBUF_SIZE; /* max cells */
|
int rightward = OUTBUF_SIZE; /* max cells */
|
||||||
int len; /* real cells */
|
int len; /* real cells */
|
||||||
|
|
||||||
escape_str(outbuf, name, OUTBUF_SIZE, &rightward);
|
escape_str(outbuf, name, OUTBUF_SIZE, &rightward);
|
||||||
len = OUTBUF_SIZE-rightward;
|
len = OUTBUF_SIZE-rightward;
|
||||||
|
|
||||||
if(len <= (int)max_rightward)
|
if(len <= (int)max_rightward)
|
||||||
return len; /* returns number of cells */
|
return len; /* returns number of cells */
|
||||||
}
|
}
|
||||||
@ -1072,11 +1072,23 @@ static int pr_nlwp(char *restrict const outbuf, const proc_t *restrict const pp)
|
|||||||
static int pr_sess(char *restrict const outbuf, const proc_t *restrict const pp){
|
static int pr_sess(char *restrict const outbuf, const proc_t *restrict const pp){
|
||||||
return snprintf(outbuf, COLWID, "%u", pp->session);
|
return snprintf(outbuf, COLWID, "%u", pp->session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int pr_supgid(char *restrict const outbuf, const proc_t *restrict const pp){
|
||||||
|
int rightward = max_rightward;
|
||||||
|
escaped_copy(outbuf, pp->supgid ? pp->supgid : "n/a", OUTBUF_SIZE, &rightward);
|
||||||
|
return max_rightward-rightward;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pr_supgrp(char *restrict const outbuf, const proc_t *restrict const pp){
|
||||||
|
int rightward = max_rightward;
|
||||||
|
escaped_copy(outbuf, pp->supgrp ? pp->supgrp : "n/a", OUTBUF_SIZE, &rightward);
|
||||||
|
return max_rightward-rightward;
|
||||||
|
}
|
||||||
|
|
||||||
static int pr_tpgid(char *restrict const outbuf, const proc_t *restrict const pp){
|
static int pr_tpgid(char *restrict const outbuf, const proc_t *restrict const pp){
|
||||||
return snprintf(outbuf, COLWID, "%d", pp->tpgid);
|
return snprintf(outbuf, COLWID, "%d", pp->tpgid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* SGI uses "cpu" to print the processor ID with header "P" */
|
/* SGI uses "cpu" to print the processor ID with header "P" */
|
||||||
static int pr_sgi_p(char *restrict const outbuf, const proc_t *restrict const pp){ /* FIXME */
|
static int pr_sgi_p(char *restrict const outbuf, const proc_t *restrict const pp){ /* FIXME */
|
||||||
if(pp->state == 'R') return snprintf(outbuf, COLWID, "%d", pp->processor);
|
if(pp->state == 'R') return snprintf(outbuf, COLWID, "%d", pp->processor);
|
||||||
@ -1241,7 +1253,9 @@ static int pr_t_left2(char *restrict const outbuf, const proc_t *restrict const
|
|||||||
#define GRP PROC_FILLGRP /* gid_t -> group names */
|
#define GRP PROC_FILLGRP /* gid_t -> group names */
|
||||||
#define WCH PROC_FILLWCHAN /* do WCHAN lookup */
|
#define WCH PROC_FILLWCHAN /* do WCHAN lookup */
|
||||||
|
|
||||||
|
#define SGRP PROC_FILLSTATUS | PROC_FILLSUPGRP /* supgid -> supgrp (names) */
|
||||||
#define CGRP PROC_FILLCGROUP | PROC_EDITCGRPCVT /* read cgroup */
|
#define CGRP PROC_FILLCGROUP | PROC_EDITCGRPCVT /* read cgroup */
|
||||||
|
|
||||||
/* TODO
|
/* TODO
|
||||||
* pull out annoying BSD aliases into another table (to macro table?)
|
* pull out annoying BSD aliases into another table (to macro table?)
|
||||||
* add sorting functions here (to unify names)
|
* add sorting functions here (to unify names)
|
||||||
@ -1437,6 +1451,8 @@ static const format_struct format_array[] = {
|
|||||||
{"status", "STATUS", pr_nop, sr_nop, 6, 0, DEC, AN|RIGHT},
|
{"status", "STATUS", pr_nop, sr_nop, 6, 0, DEC, AN|RIGHT},
|
||||||
{"stime", "STIME", pr_stime, sr_stime, 5, 0, XXX, ET|RIGHT}, /* was 6 wide */
|
{"stime", "STIME", pr_stime, sr_stime, 5, 0, XXX, ET|RIGHT}, /* was 6 wide */
|
||||||
{"suid", "SUID", pr_suid, sr_suid, 5, 0, LNx, ET|RIGHT},
|
{"suid", "SUID", pr_suid, sr_suid, 5, 0, LNx, ET|RIGHT},
|
||||||
|
{"supgid", "SUPGID", pr_supgid, sr_nop, 20, 0, LNX, PO|UNLIMITED},
|
||||||
|
{"supgrp", "SUPGRP", pr_supgrp, sr_nop, 40,SGRP, LNX, PO|UNLIMITED},
|
||||||
{"suser", "SUSER", pr_suser, sr_suser, 8, USR, LNx, ET|USER},
|
{"suser", "SUSER", pr_suser, sr_suser, 8, USR, LNx, ET|USER},
|
||||||
{"svgid", "SVGID", pr_sgid, sr_sgid, 5, 0, XXX, ET|RIGHT},
|
{"svgid", "SVGID", pr_sgid, sr_sgid, 5, 0, XXX, ET|RIGHT},
|
||||||
{"svgroup", "SVGROUP", pr_sgroup, sr_sgroup, 8, GRP, LNX, ET|USER},
|
{"svgroup", "SVGROUP", pr_sgroup, sr_sgroup, 8, GRP, LNX, ET|USER},
|
||||||
@ -1797,14 +1813,14 @@ void show_one_proc(const proc_t *restrict const p, const format_node *restrict f
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
max_leftward = fmt->width + actual - correct; /* TODO check this */
|
max_leftward = fmt->width + actual - correct; /* TODO check this */
|
||||||
|
|
||||||
// fprintf(stderr, "cols: %d, max_rightward: %d, max_leftward: %d, actual: %d, correct: %d\n",
|
// fprintf(stderr, "cols: %d, max_rightward: %d, max_leftward: %d, actual: %d, correct: %d\n",
|
||||||
// active_cols, max_rightward, max_leftward, actual, correct);
|
// active_cols, max_rightward, max_leftward, actual, correct);
|
||||||
|
|
||||||
/* prepare data and calculate leftpad */
|
/* prepare data and calculate leftpad */
|
||||||
if(likely(p) && likely(fmt->pr)) amount = (*fmt->pr)(outbuf,p);
|
if(likely(p) && likely(fmt->pr)) amount = (*fmt->pr)(outbuf,p);
|
||||||
else amount = strlen(strcpy(outbuf, fmt->name)); /* AIX or headers */
|
else amount = strlen(strcpy(outbuf, fmt->name)); /* AIX or headers */
|
||||||
|
|
||||||
switch((fmt->flags) & CF_JUST_MASK){
|
switch((fmt->flags) & CF_JUST_MASK){
|
||||||
case 0: /* for AIX, assigned outside this file */
|
case 0: /* for AIX, assigned outside this file */
|
||||||
leftpad = 0;
|
leftpad = 0;
|
||||||
@ -1869,7 +1885,7 @@ void show_one_proc(const proc_t *restrict const p, const format_node *restrict f
|
|||||||
|
|
||||||
/* real size -- don't forget in 'amount' is number of cells */
|
/* real size -- don't forget in 'amount' is number of cells */
|
||||||
sz = strlen(outbuf);
|
sz = strlen(outbuf);
|
||||||
|
|
||||||
/* print data, set x position stuff */
|
/* print data, set x position stuff */
|
||||||
if(unlikely(!fmt->next)){
|
if(unlikely(!fmt->next)){
|
||||||
/* Last column. Write padding + data + newline all together. */
|
/* Last column. Write padding + data + newline all together. */
|
||||||
|
12
ps/ps.1
12
ps/ps.1
@ -1321,6 +1321,18 @@ suid SUID T{
|
|||||||
saved user\ ID. (alias\ \fBsvuid\fR).
|
saved user\ ID. (alias\ \fBsvuid\fR).
|
||||||
T}
|
T}
|
||||||
|
|
||||||
|
supgid SUPGID T{
|
||||||
|
group ids of supplementary groups, if any.
|
||||||
|
See
|
||||||
|
.BR getgroups (2).
|
||||||
|
T}
|
||||||
|
|
||||||
|
supgrp SUPGRP T{
|
||||||
|
group names of supplementary groups, if any.
|
||||||
|
See
|
||||||
|
.BR getgroups (2).
|
||||||
|
T}
|
||||||
|
|
||||||
suser SUSER T{
|
suser SUSER T{
|
||||||
saved user name. This will be the textual user\ ID,
|
saved user name. This will be the textual user\ ID,
|
||||||
if\ it can be obtained and the field width permits,
|
if\ it can be obtained and the field width permits,
|
||||||
|
46
top.1
46
top.1
@ -435,7 +435,7 @@ Many different hierarchies of cgroups can exist simultaneously on a system
|
|||||||
and each hierarchy is attached to one or more subsystems.
|
and each hierarchy is attached to one or more subsystems.
|
||||||
A subsystem represents a single resource.
|
A subsystem represents a single resource.
|
||||||
|
|
||||||
\*(NT The 'CGROUPS' field/column, unlike most columns, is not fixed-width.
|
\*(NT The 'CGROUPS' field, unlike most columns, is not fixed-width.
|
||||||
When displayed, it plus any other variable width columns will be allocated
|
When displayed, it plus any other variable width columns will be allocated
|
||||||
all remaining screen width (up to the maximum \*(WX characters).
|
all remaining screen width (up to the maximum \*(WX characters).
|
||||||
|
|
||||||
@ -461,7 +461,7 @@ fit in this field's current width.
|
|||||||
That width depends upon other fields selected, their order and the current
|
That width depends upon other fields selected, their order and the current
|
||||||
screen width.
|
screen width.
|
||||||
|
|
||||||
\*(NT The 'COMMAND' field/column, unlike most columns, is not fixed-width.
|
\*(NT The 'COMMAND' field, unlike most columns, is not fixed-width.
|
||||||
When displayed, it plus any other variable width columns will be allocated
|
When displayed, it plus any other variable width columns will be allocated
|
||||||
all remaining screen width (up to the maximum \*(WX characters).
|
all remaining screen width (up to the maximum \*(WX characters).
|
||||||
|
|
||||||
@ -621,15 +621,35 @@ login shell.
|
|||||||
The\fI saved\fR user ID.
|
The\fI saved\fR user ID.
|
||||||
|
|
||||||
.TP 4
|
.TP 4
|
||||||
27.\fB SUSER \*(Em Saved User Name \fR
|
27.\fB SUPGIDS \*(Em Supplementary Group IDs \fR
|
||||||
|
The IDs of any supplementary group(s) established at login or
|
||||||
|
inherited from a task's parent.
|
||||||
|
They are displayed in a comma delimited list.
|
||||||
|
|
||||||
|
\*(NT The 'SUPGIDS' field, unlike most columns, is not fixed-width.
|
||||||
|
When displayed, it plus any other variable width columns will be allocated
|
||||||
|
all remaining screen width (up to the maximum \*(WX characters).
|
||||||
|
|
||||||
|
.TP 4
|
||||||
|
28.\fB SUPGRPS \*(Em Supplementary Group Names \fR
|
||||||
|
The names of any supplementary group(s) established at login or
|
||||||
|
inherited from a task's parent.
|
||||||
|
They are displayed in a comma delimited list.
|
||||||
|
|
||||||
|
\*(NT The 'SUPGRPS' field, unlike most columns, is not fixed-width.
|
||||||
|
When displayed, it plus any other variable width columns will be allocated
|
||||||
|
all remaining screen width (up to the maximum \*(WX characters).
|
||||||
|
|
||||||
|
.TP 4
|
||||||
|
29.\fB SUSER \*(Em Saved User Name \fR
|
||||||
The\fI saved\fR user name.
|
The\fI saved\fR user name.
|
||||||
|
|
||||||
.TP 4
|
.TP 4
|
||||||
28.\fB SWAP \*(Em Swapped Size (kb) \fR
|
30.\fB SWAP \*(Em Swapped Size (kb) \fR
|
||||||
The non-resident portion of a task's address space.
|
The non-resident portion of a task's address space.
|
||||||
|
|
||||||
.TP 4
|
.TP 4
|
||||||
29.\fB TIME \*(Em \*(PU Time \fR
|
31.\fB TIME \*(Em \*(PU Time \fR
|
||||||
Total \*(PU time the task has used since it started.
|
Total \*(PU time the task has used since it started.
|
||||||
When 'Cumulative mode' is \*O, each process is listed with the \*(Pu
|
When 'Cumulative mode' is \*O, each process is listed with the \*(Pu
|
||||||
time that it and its dead children have used.
|
time that it and its dead children have used.
|
||||||
@ -637,19 +657,19 @@ You toggle 'Cumulative mode' with 'S', which is both a \*(CO and an \*(CI.
|
|||||||
\*(XC 'S' \*(CI for additional information regarding this mode.
|
\*(XC 'S' \*(CI for additional information regarding this mode.
|
||||||
|
|
||||||
.TP 4
|
.TP 4
|
||||||
30.\fB TIME+ \*(Em \*(PU Time, hundredths \fR
|
32.\fB TIME+ \*(Em \*(PU Time, hundredths \fR
|
||||||
The same as 'TIME', but reflecting more granularity through hundredths
|
The same as 'TIME', but reflecting more granularity through hundredths
|
||||||
of a second.
|
of a second.
|
||||||
|
|
||||||
.TP 4
|
.TP 4
|
||||||
31.\fB TPGID \*(Em Tty Process Group Id \fR
|
33.\fB TPGID \*(Em Tty Process Group Id \fR
|
||||||
The process group ID of the foreground process for the connected tty,
|
The process group ID of the foreground process for the connected tty,
|
||||||
or -1 if a process is not connected to a terminal.
|
or -1 if a process is not connected to a terminal.
|
||||||
By convention, this value equals the process ID (\*(Xa PID) of the
|
By convention, this value equals the process ID (\*(Xa PID) of the
|
||||||
the process group leader (\*(Xa PGRP).
|
the process group leader (\*(Xa PGRP).
|
||||||
|
|
||||||
.TP 4
|
.TP 4
|
||||||
32.\fB TTY \*(Em Controlling Tty \fR
|
34.\fB TTY \*(Em Controlling Tty \fR
|
||||||
The name of the controlling terminal.
|
The name of the controlling terminal.
|
||||||
This is usually the device (serial port, pty, etc.) from which the
|
This is usually the device (serial port, pty, etc.) from which the
|
||||||
process was started, and which it uses for input or output.
|
process was started, and which it uses for input or output.
|
||||||
@ -657,21 +677,21 @@ However, a task need not be associated with a terminal, in which case
|
|||||||
you'll see '?' displayed.
|
you'll see '?' displayed.
|
||||||
|
|
||||||
.TP 4
|
.TP 4
|
||||||
33.\fB UID \*(Em User Id \fR
|
35.\fB UID \*(Em User Id \fR
|
||||||
The\fI effective\fR user ID of the task's owner.
|
The\fI effective\fR user ID of the task's owner.
|
||||||
|
|
||||||
.TP 4
|
.TP 4
|
||||||
34.\fB USER \*(Em User Name \fR
|
36.\fB USER \*(Em User Name \fR
|
||||||
The\fI effective\fR user name of the task's owner.
|
The\fI effective\fR user name of the task's owner.
|
||||||
|
|
||||||
.TP 4
|
.TP 4
|
||||||
35.\fB VIRT \*(Em Virtual Memory Size (kb) \fR
|
37.\fB VIRT \*(Em Virtual Memory Size (kb) \fR
|
||||||
The total amount of \*(MV used by the task.
|
The total amount of \*(MV used by the task.
|
||||||
It includes all code, data and shared libraries plus pages that have been
|
It includes all code, data and shared libraries plus pages that have been
|
||||||
swapped out and pages that have been mapped but not used.
|
swapped out and pages that have been mapped but not used.
|
||||||
|
|
||||||
.TP 4
|
.TP 4
|
||||||
36.\fB WCHAN \*(Em Sleeping in Function \fR
|
38.\fB WCHAN \*(Em Sleeping in Function \fR
|
||||||
Depending on the availability of the kernel link map ('System.map'), this
|
Depending on the availability of the kernel link map ('System.map'), this
|
||||||
field will show the name or the address of the kernel function in which the
|
field will show the name or the address of the kernel function in which the
|
||||||
task is currently sleeping.
|
task is currently sleeping.
|
||||||
@ -682,7 +702,7 @@ By displaying this field, \*(We's own working set could be increased by over
|
|||||||
Should that occur, your only means of reducing that overhead will be to stop
|
Should that occur, your only means of reducing that overhead will be to stop
|
||||||
and restart \*(We.
|
and restart \*(We.
|
||||||
|
|
||||||
\*(NT The 'WCHAN' field/column, unlike most columns, is not fixed-width.
|
\*(NT The 'WCHAN' field, unlike most columns, is not fixed-width.
|
||||||
When displayed, it plus any other variable width columns will be allocated
|
When displayed, it plus any other variable width columns will be allocated
|
||||||
all remaining screen width (up to the maximum \*(WX characters).
|
all remaining screen width (up to the maximum \*(WX characters).
|
||||||
|
|
||||||
|
59
top.c
59
top.c
@ -216,6 +216,8 @@ SCB_NUMx(PID, tid)
|
|||||||
SCB_NUMx(PPD, ppid)
|
SCB_NUMx(PPD, ppid)
|
||||||
SCB_NUMx(PRI, priority)
|
SCB_NUMx(PRI, priority)
|
||||||
SCB_NUM1(RES, resident) // also serves MEM !
|
SCB_NUM1(RES, resident) // also serves MEM !
|
||||||
|
SCB_STRX(SGD, supgid)
|
||||||
|
SCB_STRS(SGN, supgrp)
|
||||||
SCB_NUM1(SHR, share)
|
SCB_NUM1(SHR, share)
|
||||||
SCB_NUM1(SID, session)
|
SCB_NUM1(SID, session)
|
||||||
SCB_NUMx(STA, state)
|
SCB_NUMx(STA, state)
|
||||||
@ -1164,6 +1166,7 @@ static inline int user_matched (WIN_t *q, const proc_t *p) {
|
|||||||
#define L_EUSER PROC_FILLUSR
|
#define L_EUSER PROC_FILLUSR
|
||||||
#define L_OUSER PROC_FILLSTATUS | PROC_FILLUSR
|
#define L_OUSER PROC_FILLSTATUS | PROC_FILLUSR
|
||||||
#define L_EGROUP PROC_FILLSTATUS | PROC_FILLGRP
|
#define L_EGROUP PROC_FILLSTATUS | PROC_FILLGRP
|
||||||
|
#define L_SUPGRP PROC_FILLSTATUS | PROC_FILLSUPGRP
|
||||||
// make 'none' non-zero (used to be important to Frames_libflags)
|
// make 'none' non-zero (used to be important to Frames_libflags)
|
||||||
#define L_NONE PROC_SPARE_1
|
#define L_NONE PROC_SPARE_1
|
||||||
// from either 'stat' or 'status' (preferred), via bits not otherwise used
|
// from either 'stat' or 'status' (preferred), via bits not otherwise used
|
||||||
@ -1231,8 +1234,10 @@ static FLD_t Fieldstab[] = {
|
|||||||
#else
|
#else
|
||||||
{ "Flags ", "%08lx ", -1, -1, SF(FLG), L_stat, "Task Flags <sched.h>" },
|
{ "Flags ", "%08lx ", -1, -1, SF(FLG), L_stat, "Task Flags <sched.h>" },
|
||||||
#endif
|
#endif
|
||||||
// next entry's like P_CMD/P_WCH, and '.head' must be same length -- they share varcolsz
|
// next 3 entries as P_CMD/P_WCH: '.head' must be same length -- they share varcolsz
|
||||||
{ "CGROUPS ", NULL, -1, -1, SF(CGR), L_CGROUP, "Control Groups" }
|
{ "CGROUPS ", NULL, -1, -1, SF(CGR), L_CGROUP, "Control Groups" },
|
||||||
|
{ "SUPGIDS ", NULL, -1, -1, SF(SGD), L_status, "Supp Groups IDs" },
|
||||||
|
{ "SUPGRPS ", NULL, -1, -1, SF(SGN), L_SUPGRP, "Supp Groups Names" }
|
||||||
#ifdef OOMEM_ENABLE
|
#ifdef OOMEM_ENABLE
|
||||||
#define L_oom PROC_FILLOOM
|
#define L_oom PROC_FILLOOM
|
||||||
,{ "Adj ", "%3d ", -1, -1, SF(OOA), L_oom, "oom_adjustment (2^X)" }
|
,{ "Adj ", "%3d ", -1, -1, SF(OOA), L_oom, "oom_adjustment (2^X)" }
|
||||||
@ -1506,15 +1511,15 @@ static void calibrate_fields (void) {
|
|||||||
* ( xPRFX has pos 2 & 10 for 'extending' when at minimums )
|
* ( xPRFX has pos 2 & 10 for 'extending' when at minimums )
|
||||||
*
|
*
|
||||||
* The first 4 screen rows are reserved for explanatory text.
|
* The first 4 screen rows are reserved for explanatory text.
|
||||||
* Thus, with our current 36 fields, a maximum of 6 columns and
|
* Thus, with our current 38 fields, a maximum of 6 columns and
|
||||||
* 1 space between columns, a tty will still remain useable under
|
* 1 space between columns, a tty will still remain useable under
|
||||||
* these extremes:
|
* these extremes:
|
||||||
* rows cols displayed
|
* rows cols displayed
|
||||||
* ---- ---- ------------------
|
* ---- ---- ------------------
|
||||||
* 10 66 xPRFX only
|
* 11 66 xPRFX only (w/ room for +4)
|
||||||
* 10 198 full xPRFX + xSUFX
|
* 11 198 full xPRFX + xSUFX (w/ room for +4)
|
||||||
* 22 22 xPRFX only
|
* 23 22 xPRFX only
|
||||||
* 22 66 full xPRFX + xSUFX
|
* 23 66 full xPRFX + xSUFX
|
||||||
* ( if not, the user deserves our most cryptic messages )
|
* ( if not, the user deserves our most cryptic messages )
|
||||||
*/
|
*/
|
||||||
static void display_fields (int focus, int extend) {
|
static void display_fields (int focus, int extend) {
|
||||||
@ -1904,13 +1909,11 @@ static void prochlp (proc_t *this) {
|
|||||||
static proc_t **procs_refresh (proc_t **ppt) {
|
static proc_t **procs_refresh (proc_t **ppt) {
|
||||||
#define PTRsz sizeof(proc_t *)
|
#define PTRsz sizeof(proc_t *)
|
||||||
#define ENTsz sizeof(proc_t)
|
#define ENTsz sizeof(proc_t)
|
||||||
static int threadshown = 0; // thread hack optimization
|
|
||||||
static unsigned savmax = 0; // first time, Bypass: (i)
|
static unsigned savmax = 0; // first time, Bypass: (i)
|
||||||
proc_t *ptask = (proc_t *)-1; // first time, Force: (ii)
|
proc_t *ptask = (proc_t *)-1; // first time, Force: (ii)
|
||||||
unsigned curmax = 0; // every time (jeeze)
|
unsigned curmax = 0; // every time (jeeze)
|
||||||
PROCTAB* PT;
|
PROCTAB* PT;
|
||||||
proc_t *pthrd; // for thread hack
|
proc_t *pthrd; // for thread hack
|
||||||
unsigned i; // ditto
|
|
||||||
|
|
||||||
prochlp(NULL); // prep for a new frame
|
prochlp(NULL); // prep for a new frame
|
||||||
if (NULL == (PT = openproc(Frames_libflags, Monpids)))
|
if (NULL == (PT = openproc(Frames_libflags, Monpids)))
|
||||||
@ -1919,17 +1922,6 @@ static proc_t **procs_refresh (proc_t **ppt) {
|
|||||||
// i) Allocated Chunks: *Existing* table; refresh + reuse
|
// i) Allocated Chunks: *Existing* table; refresh + reuse
|
||||||
if (!Thread_mode) {
|
if (!Thread_mode) {
|
||||||
while (curmax < savmax) {
|
while (curmax < savmax) {
|
||||||
if (ppt[curmax]->cmdline || ppt[curmax]->cgroup) {
|
|
||||||
if (threadshown) { // skip if never used (see note below)
|
|
||||||
for (i = curmax + 1; i < savmax; i++) {
|
|
||||||
if (ppt[i]->cmdline == ppt[curmax]->cmdline) ppt[i]->cmdline = NULL;
|
|
||||||
if (ppt[i]->cgroup == ppt[curmax]->cgroup) ppt[i]->cgroup = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ppt[curmax]->cmdline) free(*ppt[curmax]->cmdline);
|
|
||||||
if (ppt[curmax]->cgroup) free(*ppt[curmax]->cgroup);
|
|
||||||
ppt[curmax]->cmdline = ppt[curmax]->cgroup = NULL;
|
|
||||||
}
|
|
||||||
if (!(ptask = readproc(PT, ppt[curmax]))) break;
|
if (!(ptask = readproc(PT, ppt[curmax]))) break;
|
||||||
prochlp(ptask); // tally & complete this proc_t
|
prochlp(ptask); // tally & complete this proc_t
|
||||||
++curmax;
|
++curmax;
|
||||||
@ -1939,23 +1931,11 @@ static proc_t **procs_refresh (proc_t **ppt) {
|
|||||||
while (curmax < savmax) {
|
while (curmax < savmax) {
|
||||||
if (!(ptask = readproc(PT, NULL))) break;
|
if (!(ptask = readproc(PT, NULL))) break;
|
||||||
while (curmax < savmax) {
|
while (curmax < savmax) {
|
||||||
if (ppt[curmax]->cmdline || ppt[curmax]->cgroup) {
|
|
||||||
/* note: threads share some of the same storage, so we must look
|
|
||||||
through the rest of our table for duplicate ref's... */
|
|
||||||
for (i = curmax + 1; i < savmax; i++) {
|
|
||||||
if (ppt[i]->cmdline == ppt[curmax]->cmdline) ppt[i]->cmdline = NULL;
|
|
||||||
if (ppt[i]->cgroup == ppt[curmax]->cgroup) ppt[i]->cgroup = NULL;
|
|
||||||
} /* ...but free only once ! */
|
|
||||||
if (ppt[curmax]->cmdline) free(*ppt[curmax]->cmdline);
|
|
||||||
if (ppt[curmax]->cgroup) free(*ppt[curmax]->cgroup);
|
|
||||||
ppt[curmax]->cmdline = ppt[curmax]->cgroup = NULL;
|
|
||||||
}
|
|
||||||
if (!(pthrd = readtask(PT, ptask, ppt[curmax]))) break;
|
if (!(pthrd = readtask(PT, ptask, ppt[curmax]))) break;
|
||||||
threadshown = 1;
|
|
||||||
prochlp(pthrd); // tally & complete this thread
|
prochlp(pthrd); // tally & complete this thread
|
||||||
++curmax;
|
++curmax;
|
||||||
}
|
}
|
||||||
free(ptask); // readproc's proc_t not needed
|
freeproc(ptask); // readproc's proc_t not needed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1977,11 +1957,10 @@ static proc_t **procs_refresh (proc_t **ppt) {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
ppt = alloc_r(ppt, (curmax + 1) * PTRsz);
|
ppt = alloc_r(ppt, (curmax + 1) * PTRsz);
|
||||||
if (!(pthrd = readtask(PT, ptask, NULL))) break;
|
if (!(pthrd = readtask(PT, ptask, NULL))) break;
|
||||||
threadshown = 1;
|
|
||||||
prochlp(pthrd); // tally & complete this thread
|
prochlp(pthrd); // tally & complete this thread
|
||||||
ppt[curmax++] = pthrd;
|
ppt[curmax++] = pthrd;
|
||||||
}
|
}
|
||||||
free(ptask); // readproc's proc_t not needed
|
freeproc(ptask); // readproc's proc_t not needed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2191,7 +2170,7 @@ static void parse_args (char **args) {
|
|||||||
. bunched args are actually handled properly and none are ignored
|
. bunched args are actually handled properly and none are ignored
|
||||||
. we tolerate NO whitespace and NO switches -- maybe too tolerant? */
|
. we tolerate NO whitespace and NO switches -- maybe too tolerant? */
|
||||||
static const char usage_str[] =
|
static const char usage_str[] =
|
||||||
" -hv | -bcHiSs -d delay -n iters -u|U user | -p pid[,pid] -w [cols]";
|
" -hv | -bcHiSs -d delay -n limit -u|U user | -p pid[,pid] -w [cols]";
|
||||||
static const char sel_error[] = "conflicting process selections (U/p/u)";
|
static const char sel_error[] = "conflicting process selections (U/p/u)";
|
||||||
static const char numbs_str[] = "+,-.0123456789";
|
static const char numbs_str[] = "+,-.0123456789";
|
||||||
float tmp_delay = MAXFLOAT;
|
float tmp_delay = MAXFLOAT;
|
||||||
@ -2230,7 +2209,7 @@ static void parse_args (char **args) {
|
|||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
case 'v': case 'V':
|
case 'v': case 'V':
|
||||||
fprintf(stdout, "\t%s\nusage:\t%s%s\n", procps_version, Myname, usage_str);
|
fprintf(stdout, "\t%s\nusage:\t%s%s", procps_version, Myname, usage_str);
|
||||||
bye_bye(NULL);
|
bye_bye(NULL);
|
||||||
case 'i':
|
case 'i':
|
||||||
TOGw(Curwin, Show_IDLEPS);
|
TOGw(Curwin, Show_IDLEPS);
|
||||||
@ -3319,6 +3298,12 @@ static void task_show (const WIN_t *q, const proc_t *p) {
|
|||||||
case P_RES:
|
case P_RES:
|
||||||
makeCOL(scale_num(pages2K(p->resident), w, s));
|
makeCOL(scale_num(pages2K(p->resident), w, s));
|
||||||
break;
|
break;
|
||||||
|
case P_SGD:
|
||||||
|
makeVAR(p->supgid ? p->supgid : "n/a");
|
||||||
|
break;
|
||||||
|
case P_SGN:
|
||||||
|
makeVAR(p->supgrp ? p->supgrp : "n/a");
|
||||||
|
break;
|
||||||
case P_SHR:
|
case P_SHR:
|
||||||
makeCOL(scale_num(pages2K(p->share), w, s));
|
makeCOL(scale_num(pages2K(p->share), w, s));
|
||||||
break;
|
break;
|
||||||
|
5
top.h
5
top.h
@ -129,6 +129,7 @@ enum pflag {
|
|||||||
P_MEM, P_VRT, P_SWP, P_RES, P_COD, P_DAT, P_SHR,
|
P_MEM, P_VRT, P_SWP, P_RES, P_COD, P_DAT, P_SHR,
|
||||||
P_FL1, P_FL2, P_DRT,
|
P_FL1, P_FL2, P_DRT,
|
||||||
P_STA, P_CMD, P_WCH, P_FLG, P_CGR,
|
P_STA, P_CMD, P_WCH, P_FLG, P_CGR,
|
||||||
|
P_SGD, P_SGN,
|
||||||
#ifdef OOMEM_ENABLE
|
#ifdef OOMEM_ENABLE
|
||||||
P_OOA, P_OOM,
|
P_OOA, P_OOM,
|
||||||
#endif
|
#endif
|
||||||
@ -367,6 +368,10 @@ typedef struct WIN_t {
|
|||||||
if (!(*P)->v || !(*Q)->v) return SORT_eq; \
|
if (!(*P)->v || !(*Q)->v) return SORT_eq; \
|
||||||
return Frame_srtflg * STRSORTCMP((*Q)->v[0], (*P)->v[0]); } \
|
return Frame_srtflg * STRSORTCMP((*Q)->v[0], (*P)->v[0]); } \
|
||||||
return Frame_srtflg * STRSORTCMP((*Q)->s, (*P)->s); }
|
return Frame_srtflg * STRSORTCMP((*Q)->s, (*P)->s); }
|
||||||
|
#define SCB_STRX(f,s) \
|
||||||
|
int strverscmp(const char *s1, const char *s2); \
|
||||||
|
static int SCB_NAME(f) (const proc_t **P, const proc_t **Q) { \
|
||||||
|
return Frame_srtflg * strverscmp((*Q)->s, (*P)->s); }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following two macros are used to 'inline' those portions of the
|
* The following two macros are used to 'inline' those portions of the
|
||||||
|
Loading…
x
Reference in New Issue
Block a user