refined library i/f and improved performance
Library changes readproc . added readeither to more efficiently fill both process and thread proc_t . added readproctab3, uses readeither . included task path support in: fill_cgroup_cvt, fill_cmdline_cvt, read_unvectored . QUICK_THREADS #define allows copying process info vs. repeatedly reading . simple_nexttid no longer values ppid . path var made non-static in readtask . documented 'proc_data_t' in .h file . tweaked some c comments & formatting library.map . added new readeither, readproctab3 Program changes ps . exploits readproctab3 where possible . improved args/comm compliance top . exploits readeither
This commit is contained in:
parent
3ef4823f90
commit
bb4f08ba29
@ -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; freeproc;
|
openproc; closeproc; freeproc; readeither; readproctab3;
|
||||||
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;
|
||||||
|
247
proc/readproc.c
247
proc/readproc.c
@ -38,6 +38,12 @@ extern void __cyg_profile_func_enter(void*,void*);
|
|||||||
#define LEAVE(x)
|
#define LEAVE(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef QUICK_THREADS
|
||||||
|
// used when multi-threaded and some memory must not be freed
|
||||||
|
#define MK_THREAD(q) q->pad_1 = '\xee'
|
||||||
|
#define IS_THREAD(q) ( q->pad_1 == '\xee' )
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef SIGNAL_STRING
|
#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){
|
||||||
@ -56,11 +62,17 @@ static int task_dir_missing;
|
|||||||
// free any additional dynamically acquired storage associated with a proc_t
|
// free any additional dynamically acquired storage associated with a proc_t
|
||||||
// ( and if it's to be reused, refresh it otherwise destroy it )
|
// ( and if it's to be reused, refresh it otherwise destroy it )
|
||||||
static inline void free_acquired (proc_t *p, int reuse) {
|
static inline void free_acquired (proc_t *p, int reuse) {
|
||||||
|
#ifdef QUICK_THREADS
|
||||||
|
if (!IS_THREAD(p)) {
|
||||||
|
#endif
|
||||||
if (p->environ) free((void*)*p->environ);
|
if (p->environ) free((void*)*p->environ);
|
||||||
if (p->cmdline) free((void*)*p->cmdline);
|
if (p->cmdline) free((void*)*p->cmdline);
|
||||||
if (p->cgroup) free((void*)*p->cgroup);
|
if (p->cgroup) free((void*)*p->cgroup);
|
||||||
if (p->supgid) free(p->supgid);
|
if (p->supgid) free(p->supgid);
|
||||||
if (p->supgrp) free(p->supgrp);
|
if (p->supgrp) free(p->supgrp);
|
||||||
|
#ifdef QUICK_THREADS
|
||||||
|
}
|
||||||
|
#endif
|
||||||
memset(p, reuse ? '\0' : '\xff', sizeof(*p));
|
memset(p, reuse ? '\0' : '\xff', sizeof(*p));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -571,14 +583,15 @@ static char** file2strvec(const char* directory, const char* what) {
|
|||||||
// this is the former under utilized 'read_cmdline', which has been
|
// this is the former under utilized 'read_cmdline', which has been
|
||||||
// generalized in support of these new libproc flags:
|
// generalized in support of these new libproc flags:
|
||||||
// PROC_EDITCGRPCVT, PROC_EDITCMDLCVT
|
// PROC_EDITCGRPCVT, PROC_EDITCMDLCVT
|
||||||
static int read_unvectored(char *restrict const dst, unsigned sz, unsigned pid, const char *what, char sep) {
|
static int read_unvectored(char *restrict const dst, unsigned sz, const char* whom, const char *what, char sep) {
|
||||||
char name[32];
|
char path[PROCPATHLEN];
|
||||||
int fd;
|
int fd;
|
||||||
unsigned n = 0;
|
unsigned n = 0;
|
||||||
|
|
||||||
snprintf(name, sizeof name, "/proc/%u/%s", pid, what);
|
snprintf(path, sizeof(path), "%s/%s", whom, what);
|
||||||
fd = open(name, O_RDONLY);
|
fd = open(path, O_RDONLY);
|
||||||
if(fd==-1) return 0;
|
if(fd==-1) return 0;
|
||||||
|
|
||||||
for(;;){
|
for(;;){
|
||||||
ssize_t r = read(fd,dst+n,sz-n);
|
ssize_t r = read(fd,dst+n,sz-n);
|
||||||
if(r==-1){
|
if(r==-1){
|
||||||
@ -618,17 +631,17 @@ static char** vectorize_this_str (const char* src) {
|
|||||||
#undef pSZ
|
#undef pSZ
|
||||||
}
|
}
|
||||||
|
|
||||||
// This routine reads /proc/#/cgroup for a single task.
|
// This routine reads a 'cgroup' for the designated proc_t.
|
||||||
// It is similar to file2strvec except we filter and concatenate
|
// It is similar to file2strvec except we filter and concatenate
|
||||||
// the data into a single string represented as a single vector.
|
// the data into a single string represented as a single vector.
|
||||||
static void fill_cgroup_cvt (proc_t *restrict p) {
|
static void fill_cgroup_cvt (const char* directory, proc_t *restrict p) {
|
||||||
#define vMAX ( sizeof(dbuf) - (int)(dst - dbuf) )
|
#define vMAX ( sizeof(dbuf) - (int)(dst - dbuf) )
|
||||||
char sbuf[1024], dbuf[1024];
|
char sbuf[1024], dbuf[1024];
|
||||||
char *src, *dst, *grp, *eob;
|
char *src, *dst, *grp, *eob;
|
||||||
int tot, x, whackable_int = sizeof(dbuf);
|
int tot, x, whackable_int = sizeof(dbuf);
|
||||||
|
|
||||||
*(dst = dbuf) = '\0'; // empty destination
|
*(dst = dbuf) = '\0'; // empty destination
|
||||||
tot = read_unvectored(sbuf, sizeof(sbuf), p->tid, "cgroup", '\0');
|
tot = read_unvectored(sbuf, sizeof(sbuf), directory, "cgroup", '\0');
|
||||||
for (src = sbuf, eob = sbuf + tot; src < eob; src += x) {
|
for (src = sbuf, eob = sbuf + tot; src < eob; src += x) {
|
||||||
x = 1; // loop assist
|
x = 1; // loop assist
|
||||||
if (!*src) continue;
|
if (!*src) continue;
|
||||||
@ -644,15 +657,15 @@ static void fill_cgroup_cvt (proc_t *restrict p) {
|
|||||||
#undef vMAX
|
#undef vMAX
|
||||||
}
|
}
|
||||||
|
|
||||||
// This routine reads /proc/#/cmdline for the designated task, "escapes"
|
// This routine reads a 'cmdline' for the designated proc_t, "escapes"
|
||||||
// the result into a single string represented as a single vector and
|
// the result into a single string represented as a single vector
|
||||||
// guarantees the caller a valid proc_t.cmdline pointer.
|
// and guarantees the caller a valid proc_t.cmdline pointer.
|
||||||
static void fill_cmdline_cvt (proc_t *restrict p) {
|
static void fill_cmdline_cvt (const char* directory, proc_t *restrict p) {
|
||||||
#define uFLG ( ESC_BRACKETS | ESC_DEFUNCT )
|
#define uFLG ( ESC_BRACKETS | ESC_DEFUNCT )
|
||||||
char sbuf[2048], dbuf[2048];
|
char sbuf[2048], dbuf[2048];
|
||||||
int whackable_int = sizeof(dbuf);
|
int whackable_int = sizeof(dbuf);
|
||||||
|
|
||||||
if (read_unvectored(sbuf, sizeof(sbuf), p->tid, "cmdline", ' '))
|
if (read_unvectored(sbuf, sizeof(sbuf), directory, "cmdline", ' '))
|
||||||
escape_str(dbuf, sbuf, sizeof(dbuf), &whackable_int);
|
escape_str(dbuf, sbuf, sizeof(dbuf), &whackable_int);
|
||||||
else
|
else
|
||||||
escape_command(dbuf, p, sizeof(dbuf), &whackable_int, uFLG);
|
escape_command(dbuf, p, sizeof(dbuf), &whackable_int, uFLG);
|
||||||
@ -662,7 +675,9 @@ static void fill_cmdline_cvt (proc_t *restrict p) {
|
|||||||
|
|
||||||
// warning: interface may change
|
// warning: interface may change
|
||||||
int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid) {
|
int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid) {
|
||||||
return read_unvectored(dst, sz, pid, "cmdline", ' ');
|
char path[PROCPATHLEN];
|
||||||
|
snprintf(path, sizeof(path), "/proc/%u", pid);
|
||||||
|
return read_unvectored(dst, sz, path, "cmdline", ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -706,18 +721,18 @@ static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict cons
|
|||||||
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 /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;
|
goto next_proc;
|
||||||
stat2proc(sbuf, p);
|
stat2proc(sbuf, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & PROC_FILLMEM) { // read /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);
|
statm2proc(sbuf, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & PROC_FILLSTATUS) { // read /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)
|
if (flags & PROC_FILLSUPGRP)
|
||||||
supgrps_from_supgids(p);
|
supgrps_from_supgids(p);
|
||||||
@ -756,7 +771,7 @@ static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict cons
|
|||||||
|
|
||||||
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(path, p);
|
||||||
else
|
else
|
||||||
p->cmdline = file2strvec(path, "cmdline");
|
p->cmdline = file2strvec(path, "cmdline");
|
||||||
} else
|
} else
|
||||||
@ -765,7 +780,7 @@ static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict cons
|
|||||||
if ((flags & PROC_FILLCGROUP) // read /proc/#/cgroup
|
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(path, p);
|
||||||
else
|
else
|
||||||
p->cgroup = file2strvec(path, "cgroup");
|
p->cgroup = file2strvec(path, "cgroup");
|
||||||
} else
|
} else
|
||||||
@ -773,9 +788,9 @@ static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict cons
|
|||||||
|
|
||||||
#ifdef OOMEM_ENABLE
|
#ifdef OOMEM_ENABLE
|
||||||
if (unlikely(flags & PROC_FILLOOM)) {
|
if (unlikely(flags & PROC_FILLOOM)) {
|
||||||
if (likely( file2str(path, "oom_score", sbuf, sizeof sbuf) != -1 ))
|
if (likely(file2str(path, "oom_score", sbuf, sizeof sbuf) != -1))
|
||||||
oomscore2proc(sbuf, p);
|
oomscore2proc(sbuf, p);
|
||||||
if (likely( file2str(path, "oom_adj", sbuf, sizeof sbuf) != -1 ))
|
if (likely(file2str(path, "oom_adj", sbuf, sizeof sbuf) != -1))
|
||||||
oomadj2proc(sbuf, p);
|
oomadj2proc(sbuf, p);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -787,7 +802,11 @@ next_proc:
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
// This reads /proc/*/task/* data, for one task.
|
// This reads /proc/*/task/* data, for one task.
|
||||||
|
#ifdef QUICK_THREADS
|
||||||
|
// p is the POSIX process (task group summary) & source for some copies if !NULL
|
||||||
|
#else
|
||||||
// p is the POSIX process (task group summary) (not needed by THIS implementation)
|
// p is the POSIX process (task group summary) (not needed by THIS implementation)
|
||||||
|
#endif
|
||||||
// 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) {
|
||||||
@ -805,31 +824,24 @@ static proc_t* simple_readtask(PROCTAB *restrict const PT, const proc_t *restric
|
|||||||
t->egid = sb.st_gid; /* need a way to get real gid */
|
t->egid = sb.st_gid; /* need a way to get real gid */
|
||||||
|
|
||||||
if (flags & PROC_FILLSTAT) { // read /proc/#/task/#/stat
|
if (flags & PROC_FILLSTAT) { // read /proc/#/task/#/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;
|
||||||
stat2proc(sbuf, t);
|
stat2proc(sbuf, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & PROC_FILLMEM) { // read /proc/#/task/#statm
|
#ifndef QUICK_THREADS
|
||||||
#if 1
|
if (flags & PROC_FILLMEM) // read /proc/#/task/#statm
|
||||||
if (likely(file2str(path, "statm", sbuf, sizeof sbuf) != -1 ))
|
if (likely(file2str(path, "statm", sbuf, sizeof sbuf) != -1))
|
||||||
statm2proc(sbuf, t);
|
statm2proc(sbuf, t);
|
||||||
#else
|
|
||||||
t->size = p->size;
|
|
||||||
t->resident = p->resident;
|
|
||||||
t->share = p->share;
|
|
||||||
t->trs = p->trs;
|
|
||||||
t->lrs = p->lrs;
|
|
||||||
t->drs = p->drs;
|
|
||||||
t->dt = p->dt;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & PROC_FILLSTATUS) { // read /proc/#/task/#/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);
|
||||||
|
#ifndef QUICK_THREADS
|
||||||
if (flags & PROC_FILLSUPGRP)
|
if (flags & PROC_FILLSUPGRP)
|
||||||
supgrps_from_supgids(t);
|
supgrps_from_supgids(t);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -853,7 +865,15 @@ static proc_t* simple_readtask(PROCTAB *restrict const PT, const proc_t *restric
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1 // begin active ------------------------
|
#ifdef QUICK_THREADS
|
||||||
|
if (!p) {
|
||||||
|
if (flags & PROC_FILLMEM)
|
||||||
|
if (likely(file2str(path, "statm", sbuf, sizeof sbuf) != -1))
|
||||||
|
statm2proc(sbuf, t);
|
||||||
|
|
||||||
|
if (flags & PROC_FILLSUPGRP)
|
||||||
|
supgrps_from_supgids(t);
|
||||||
|
#endif
|
||||||
if (unlikely(flags & PROC_FILLENV)) // read /proc/#/task/#/environ
|
if (unlikely(flags & PROC_FILLENV)) // read /proc/#/task/#/environ
|
||||||
t->environ = file2strvec(path, "environ");
|
t->environ = file2strvec(path, "environ");
|
||||||
else
|
else
|
||||||
@ -861,7 +881,7 @@ static proc_t* simple_readtask(PROCTAB *restrict const PT, const proc_t *restric
|
|||||||
|
|
||||||
if (flags & (PROC_FILLCOM|PROC_FILLARG)) { // read /proc/#/task/#/cmdline
|
if (flags & (PROC_FILLCOM|PROC_FILLARG)) { // read /proc/#/task/#/cmdline
|
||||||
if (flags & PROC_EDITCMDLCVT)
|
if (flags & PROC_EDITCMDLCVT)
|
||||||
fill_cmdline_cvt(t);
|
fill_cmdline_cvt(path, t);
|
||||||
else
|
else
|
||||||
t->cmdline = file2strvec(path, "cmdline");
|
t->cmdline = file2strvec(path, "cmdline");
|
||||||
} else
|
} else
|
||||||
@ -870,30 +890,46 @@ static proc_t* simple_readtask(PROCTAB *restrict const PT, const proc_t *restric
|
|||||||
if ((flags & PROC_FILLCGROUP) // read /proc/#/task/#/cgroup
|
if ((flags & PROC_FILLCGROUP) // read /proc/#/task/#/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(t);
|
fill_cgroup_cvt(path, t);
|
||||||
else
|
else
|
||||||
t->cgroup = file2strvec(path, "cgroup");
|
t->cgroup = file2strvec(path, "cgroup");
|
||||||
} else
|
} else
|
||||||
t->cgroup = NULL;
|
t->cgroup = NULL;
|
||||||
#else // end active --------------------------
|
|
||||||
|
#ifdef QUICK_THREADS
|
||||||
|
} else {
|
||||||
|
t->size = p->size;
|
||||||
|
t->resident = p->resident;
|
||||||
|
t->share = p->share;
|
||||||
|
t->trs = p->trs;
|
||||||
|
t->lrs = p->lrs;
|
||||||
|
t->drs = p->drs;
|
||||||
|
t->dt = p->dt;
|
||||||
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->cgroup = p->cgroup;
|
||||||
|
if (t->supgid) free(t->supgid);
|
||||||
t->supgid = p->supgid;
|
t->supgid = p->supgid;
|
||||||
t->supgrp = p->supgrp;
|
t->supgrp = p->supgrp;
|
||||||
#error we DO NOT BURDEN library users with the above insanity ANYMORE !
|
MK_THREAD(t);
|
||||||
#endif // end inactive ------------------------
|
}
|
||||||
|
|
||||||
#ifdef OOMEM_ENABLE
|
|
||||||
t->oom_score = p->oom_score;
|
|
||||||
t->oom_adj = p->oom_adj;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
t->ppid = p->ppid; // ought to put the per-task ppid somewhere
|
#ifdef OOMEM_ENABLE
|
||||||
|
if (unlikely(flags & PROC_FILLOOM)) {
|
||||||
|
if (likely(file2str(path, "oom_score", sbuf, sizeof sbuf) != -1))
|
||||||
|
oomscore2proc(sbuf, p);
|
||||||
|
if (likely(file2str(path, "oom_adj", sbuf, sizeof sbuf) != -1))
|
||||||
|
oomadj2proc(sbuf, p);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
next_task:
|
next_task:
|
||||||
return NULL;
|
return NULL;
|
||||||
|
#ifndef QUICK_THREADS
|
||||||
|
(void)p;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -905,7 +941,7 @@ static int simple_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p)
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
ent = readdir(PT->procfs);
|
ent = readdir(PT->procfs);
|
||||||
if(unlikely(unlikely(!ent) || unlikely(!ent->d_name))) return 0;
|
if(unlikely(unlikely(!ent) || unlikely(!ent->d_name))) return 0;
|
||||||
if(likely( likely(*ent->d_name > '0') && likely(*ent->d_name <= '9') )) break;
|
if(likely(likely(*ent->d_name > '0') && likely(*ent->d_name <= '9'))) break;
|
||||||
}
|
}
|
||||||
p->tgid = strtoul(ent->d_name, NULL, 10);
|
p->tgid = strtoul(ent->d_name, NULL, 10);
|
||||||
p->tid = p->tgid;
|
p->tid = p->tgid;
|
||||||
@ -932,11 +968,11 @@ static int simple_nexttid(PROCTAB *restrict const PT, const proc_t *restrict con
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
ent = readdir(PT->taskdir);
|
ent = readdir(PT->taskdir);
|
||||||
if(unlikely(unlikely(!ent) || unlikely(!ent->d_name))) return 0;
|
if(unlikely(unlikely(!ent) || unlikely(!ent->d_name))) return 0;
|
||||||
if(likely( likely(*ent->d_name > '0') && likely(*ent->d_name <= '9') )) break;
|
if(likely(likely(*ent->d_name > '0') && likely(*ent->d_name <= '9'))) break;
|
||||||
}
|
}
|
||||||
t->tid = strtoul(ent->d_name, NULL, 10);
|
t->tid = strtoul(ent->d_name, NULL, 10);
|
||||||
t->tgid = p->tgid;
|
t->tgid = p->tgid;
|
||||||
t->ppid = p->ppid; // cover for kernel behavior? we want both actually...?
|
//t->ppid = p->ppid; // cover for kernel behavior? we want both actually...?
|
||||||
snprintf(path, PROCPATHLEN, "/proc/%d/task/%s", p->tgid, ent->d_name);
|
snprintf(path, PROCPATHLEN, "/proc/%d/task/%s", p->tgid, ent->d_name);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -947,7 +983,7 @@ static int simple_nexttid(PROCTAB *restrict const PT, const proc_t *restrict con
|
|||||||
static int listed_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p) {
|
static int listed_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p) {
|
||||||
char *restrict const path = PT->path;
|
char *restrict const path = PT->path;
|
||||||
pid_t tgid = *(PT->pids)++;
|
pid_t tgid = *(PT->pids)++;
|
||||||
if(likely( tgid )){
|
if(likely(tgid)){
|
||||||
snprintf(path, PROCPATHLEN, "/proc/%d", tgid);
|
snprintf(path, PROCPATHLEN, "/proc/%d", tgid);
|
||||||
p->tgid = tgid;
|
p->tgid = tgid;
|
||||||
p->tid = tgid; // they match for leaders
|
p->tid = tgid; // they match for leaders
|
||||||
@ -983,7 +1019,7 @@ proc_t* readproc(PROCTAB *restrict const PT, proc_t *restrict p) {
|
|||||||
|
|
||||||
for(;;){
|
for(;;){
|
||||||
// fills in the path, plus p->tid and p->tgid
|
// fills in the path, plus p->tid and p->tgid
|
||||||
if (unlikely(! PT->finder(PT,p) )) goto out;
|
if (unlikely(!PT->finder(PT,p))) goto out;
|
||||||
|
|
||||||
// go read the process data
|
// go read the process data
|
||||||
ret = PT->reader(PT,p);
|
ret = PT->reader(PT,p);
|
||||||
@ -1002,7 +1038,7 @@ out:
|
|||||||
// pointer (boolean false). Use the passed buffer instead of allocating
|
// pointer (boolean false). Use the passed buffer instead of allocating
|
||||||
// space if it is non-NULL.
|
// space if it is non-NULL.
|
||||||
proc_t* readtask(PROCTAB *restrict const PT, const proc_t *restrict const p, proc_t *restrict t) {
|
proc_t* readtask(PROCTAB *restrict const PT, const proc_t *restrict const p, proc_t *restrict t) {
|
||||||
static char path[PROCPATHLEN]; // must hold /proc/2000222000/task/2000222000/cmdline
|
char path[PROCPATHLEN]; // must hold /proc/2000222000/task/2000222000/cmdline
|
||||||
proc_t *ret;
|
proc_t *ret;
|
||||||
proc_t *saved_t;
|
proc_t *saved_t;
|
||||||
|
|
||||||
@ -1011,7 +1047,12 @@ proc_t* readtask(PROCTAB *restrict const PT, const proc_t *restrict const p, pro
|
|||||||
else free_acquired(t, 1);
|
else free_acquired(t, 1);
|
||||||
|
|
||||||
// 1. got to fake a thread for old kernels
|
// 1. got to fake a thread for old kernels
|
||||||
if(task_dir_missing) {
|
#ifdef QUICK_THREADS
|
||||||
|
// 2. for single-threaded processes, this is faster (but must patch up stuff that differs!)
|
||||||
|
if(task_dir_missing || p->nlwp < 2){
|
||||||
|
#else
|
||||||
|
if(task_dir_missing){
|
||||||
|
#endif
|
||||||
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));
|
||||||
@ -1021,17 +1062,21 @@ proc_t* readtask(PROCTAB *restrict const PT, const proc_t *restrict const p, pro
|
|||||||
#else
|
#else
|
||||||
t->signal = t->_sigpnd;
|
t->signal = t->_sigpnd;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef QUICK_THREADS
|
||||||
|
MK_THREAD(t);
|
||||||
|
#else
|
||||||
t->environ = NULL;
|
t->environ = NULL;
|
||||||
t->cmdline = vectorize_this_str("n/a");
|
t->cmdline = vectorize_this_str("n/a");
|
||||||
t->cgroup = NULL;
|
t->cgroup = NULL;
|
||||||
t->supgid = NULL;
|
t->supgid = NULL;
|
||||||
t->supgrp = NULL;
|
t->supgrp = NULL;
|
||||||
|
#endif
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(;;){
|
for(;;){
|
||||||
// fills in the path, plus t->tid and t->tgid
|
// fills in the path, plus t->tid and t->tgid
|
||||||
if (unlikely(! PT->taskfinder(PT,p,t,path) )) goto out; // simple_nexttid
|
if (unlikely(!PT->taskfinder(PT,p,t,path))) goto out; // simple_nexttid
|
||||||
|
|
||||||
// go read the task data
|
// go read the task data
|
||||||
ret = PT->taskreader(PT,p,t,path); // simple_readtask
|
ret = PT->taskreader(PT,p,t,path); // simple_readtask
|
||||||
@ -1043,6 +1088,48 @@ out:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// readeither: return a pointer to a proc_t filled with requested info about
|
||||||
|
// the next unique process or task available. If no more are available,
|
||||||
|
// return a null pointer (boolean false). Use the passed buffer instead
|
||||||
|
// of allocating space if it is non-NULL.
|
||||||
|
extern proc_t* readeither (PROCTAB *restrict const PT, proc_t *restrict x) {
|
||||||
|
static proc_t skel_p; // skeleton proc_t, only uses tid + tgid
|
||||||
|
static proc_t *new_p; // for process/task transitions
|
||||||
|
char path[PROCPATHLEN];
|
||||||
|
proc_t *saved_x, *ret;
|
||||||
|
|
||||||
|
saved_x = x;
|
||||||
|
if (!x) x = xcalloc(NULL, sizeof(*x));
|
||||||
|
else free_acquired(x,1);
|
||||||
|
if (new_p) goto next_task;
|
||||||
|
|
||||||
|
next_proc:
|
||||||
|
new_p = NULL;
|
||||||
|
for (;;) {
|
||||||
|
// fills in the PT->path, plus skel_p.tid and skel_p.tgid
|
||||||
|
if (!PT->finder(PT,&skel_p)) goto end_procs; // simple_nextpid
|
||||||
|
if (!task_dir_missing) break;
|
||||||
|
if ((ret = PT->reader(PT,x))) return ret; // simple_readproc
|
||||||
|
}
|
||||||
|
|
||||||
|
next_task:
|
||||||
|
for (;;) {
|
||||||
|
// fills in our path, plus x->tid and x->tgid
|
||||||
|
if ((!(PT->taskfinder(PT,&skel_p,x,path))) // simple_nexttid
|
||||||
|
|| (!(ret = PT->taskreader(PT,new_p,x,path)))) { // simple_readtask
|
||||||
|
goto next_proc;
|
||||||
|
}
|
||||||
|
if (!new_p) new_p = ret;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
end_procs:
|
||||||
|
if (!saved_x) free(x);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// initiate a process table scan
|
// initiate a process table scan
|
||||||
@ -1116,6 +1203,7 @@ void look_up_our_self(proc_t *p) {
|
|||||||
|
|
||||||
HIDDEN_ALIAS(readproc);
|
HIDDEN_ALIAS(readproc);
|
||||||
HIDDEN_ALIAS(readtask);
|
HIDDEN_ALIAS(readtask);
|
||||||
|
HIDDEN_ALIAS(readeither);
|
||||||
|
|
||||||
/* Convenient wrapper around openproc and readproc to slurp in the whole process
|
/* Convenient wrapper around openproc and readproc to slurp in the whole process
|
||||||
* table subset satisfying the constraints of flags and the optional PID list.
|
* table subset satisfying the constraints of flags and the optional PID list.
|
||||||
@ -1155,6 +1243,7 @@ proc_t** readproctab(int flags, ...) {
|
|||||||
|
|
||||||
// Try again, this time with threads and selection.
|
// Try again, this time with threads and selection.
|
||||||
proc_data_t *readproctab2(int(*want_proc)(proc_t *buf), int(*want_task)(proc_t *buf), PROCTAB *restrict const PT) {
|
proc_data_t *readproctab2(int(*want_proc)(proc_t *buf), int(*want_task)(proc_t *buf), PROCTAB *restrict const PT) {
|
||||||
|
static proc_data_t pd;
|
||||||
proc_t** ptab = NULL;
|
proc_t** ptab = NULL;
|
||||||
unsigned n_proc_alloc = 0;
|
unsigned n_proc_alloc = 0;
|
||||||
unsigned n_proc = 0;
|
unsigned n_proc = 0;
|
||||||
@ -1167,8 +1256,6 @@ proc_data_t *readproctab2(int(*want_proc)(proc_t *buf), int(*want_task)(proc_t *
|
|||||||
unsigned n_alloc = 0;
|
unsigned n_alloc = 0;
|
||||||
unsigned long n_used = 0;
|
unsigned long n_used = 0;
|
||||||
|
|
||||||
proc_data_t *pd;
|
|
||||||
|
|
||||||
for(;;){
|
for(;;){
|
||||||
proc_t *tmp;
|
proc_t *tmp;
|
||||||
if(n_alloc == n_used){
|
if(n_alloc == n_used){
|
||||||
@ -1198,6 +1285,7 @@ proc_data_t *readproctab2(int(*want_proc)(proc_t *buf), int(*want_task)(proc_t *
|
|||||||
// 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;
|
||||||
|
memset(data+n_used+1, 0, sizeof(proc_t)*(n_alloc-(n_used+1)));
|
||||||
}
|
}
|
||||||
if(n_task_alloc == n_task){
|
if(n_task_alloc == n_task){
|
||||||
//proc_t **old = ttab;
|
//proc_t **old = ttab;
|
||||||
@ -1212,23 +1300,49 @@ proc_data_t *readproctab2(int(*want_proc)(proc_t *buf), int(*want_task)(proc_t *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pd = malloc(sizeof(proc_data_t));
|
pd.proc = ptab;
|
||||||
pd->proc = ptab;
|
pd.task = ttab;
|
||||||
pd->task = ttab;
|
pd.nproc = n_proc;
|
||||||
pd->nproc = n_proc;
|
pd.ntask = n_task;
|
||||||
pd->ntask = n_task;
|
|
||||||
if(PT->flags & PROC_LOOSE_TASKS){
|
if(PT->flags & PROC_LOOSE_TASKS){
|
||||||
pd->tab = ttab;
|
pd.tab = ttab;
|
||||||
pd->n = n_task;
|
pd.n = n_task;
|
||||||
}else{
|
}else{
|
||||||
pd->tab = ptab;
|
pd.tab = ptab;
|
||||||
pd->n = n_proc;
|
pd.n = n_proc;
|
||||||
}
|
}
|
||||||
// change array indexes to pointers
|
// change array indexes to pointers
|
||||||
while(n_proc--) ptab[n_proc] = data+(long)(ptab[n_proc]);
|
while(n_proc--) ptab[n_proc] = data+(long)(ptab[n_proc]);
|
||||||
while(n_task--) ttab[n_task] = data+(long)(ttab[n_task]);
|
while(n_task--) ttab[n_task] = data+(long)(ttab[n_task]);
|
||||||
|
|
||||||
return pd;
|
return &pd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try try yet again, this time treating processes and threads the same...
|
||||||
|
proc_data_t *readproctab3 (int(*want_task)(proc_t *buf), PROCTAB *restrict const PT) {
|
||||||
|
static proc_data_t pd;
|
||||||
|
proc_t **tab = NULL;
|
||||||
|
unsigned n_alloc = 0;
|
||||||
|
unsigned n_used = 0;
|
||||||
|
proc_t *p = NULL;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (n_alloc == n_used) {
|
||||||
|
n_alloc = n_alloc*5/4+30; // grow by over 25%
|
||||||
|
tab = realloc(tab,sizeof(proc_t*)*n_alloc);
|
||||||
|
}
|
||||||
|
// let this next guy allocate the necessary proc_t storage
|
||||||
|
// (or recycle it) since he can't tolerate realloc relocations
|
||||||
|
if (!(p = readeither_direct(PT,p))) break;
|
||||||
|
if (want_task(p)) {
|
||||||
|
tab[n_used++] = p;
|
||||||
|
p = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pd.tab = tab;
|
||||||
|
pd.n = n_used;
|
||||||
|
return &pd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1256,3 +1370,6 @@ proc_t * get_proc_stats(pid_t pid, proc_t *p) {
|
|||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef MK_THREAD
|
||||||
|
#undef IS_THREAD
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "pwcache.h"
|
#include "pwcache.h"
|
||||||
|
|
||||||
#define SIGNAL_STRING
|
#define SIGNAL_STRING
|
||||||
|
#define QUICK_THREADS /* copy (vs. read) some thread info from parent proc_t */
|
||||||
|
|
||||||
EXTERN_C_BEGIN
|
EXTERN_C_BEGIN
|
||||||
|
|
||||||
@ -44,7 +45,11 @@ typedef struct proc_t {
|
|||||||
pcpu; // stat (special) %CPU usage (is not filled in by readproc!!!)
|
pcpu; // stat (special) %CPU usage (is not filled in by readproc!!!)
|
||||||
char
|
char
|
||||||
state, // stat,status single-char code for process state (S=sleeping)
|
state, // stat,status single-char code for process state (S=sleeping)
|
||||||
|
#ifdef QUICK_THREADS
|
||||||
|
pad_1, // n/a padding (psst, also used if multi-threaded)
|
||||||
|
#else
|
||||||
pad_1, // n/a padding
|
pad_1, // n/a padding
|
||||||
|
#endif
|
||||||
pad_2, // n/a padding
|
pad_2, // n/a padding
|
||||||
pad_3; // n/a padding
|
pad_3; // n/a padding
|
||||||
// 2nd 16 bytes
|
// 2nd 16 bytes
|
||||||
@ -185,16 +190,17 @@ typedef struct 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 { // valued by: (else zero)
|
||||||
proc_t **tab;
|
proc_t **tab; // readproctab2, readproctab3
|
||||||
proc_t **proc;
|
proc_t **proc; // readproctab2
|
||||||
proc_t **task;
|
proc_t **task; // * readproctab2
|
||||||
int n;
|
int n; // readproctab2, readproctab3
|
||||||
int nproc;
|
int nproc; // readproctab2
|
||||||
int ntask;
|
int ntask; // * readproctab2
|
||||||
} proc_data_t;
|
} proc_data_t; // * when PROC_LOOSE_TASKS set
|
||||||
|
|
||||||
extern proc_data_t *readproctab2(int(*want_proc)(proc_t *buf), int(*want_task)(proc_t *buf), PROCTAB *restrict const PT);
|
extern proc_data_t *readproctab2(int(*want_proc)(proc_t *buf), int(*want_task)(proc_t *buf), PROCTAB *restrict const PT);
|
||||||
|
extern proc_data_t *readproctab3(int(*want_task)(proc_t *buf), PROCTAB *restrict const PT);
|
||||||
|
|
||||||
// Convenient wrapper around openproc and readproc to slurp in the whole process
|
// Convenient wrapper around openproc and readproc to slurp in the whole process
|
||||||
// table subset satisfying the constraints of flags and the optional PID list.
|
// table subset satisfying the constraints of flags and the optional PID list.
|
||||||
@ -207,16 +213,17 @@ extern void closeproc(PROCTAB* PT);
|
|||||||
|
|
||||||
// Retrieve the next process or task 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,
|
// Note: When NULL is used as the readproc 'p', readtask 't' or readeither 'x'
|
||||||
// the library will allocate the necessary proc_t storage.
|
// parameter, the library will allocate the necessary proc_t storage.
|
||||||
//
|
//
|
||||||
// Alternately, you may provide your own reuseable buffer address
|
// Alternatively, you may provide your own reuseable buffer address
|
||||||
// in which case that buffer *MUST* be initialized to zero one time
|
// in which case that buffer *MUST* be initialized to zero one time
|
||||||
// only before first use. Thereafter, the library will manage such
|
// only before first use. Thereafter, the library will manage such
|
||||||
// a passed proc_t, freeing any additional acquired memory associated
|
// a passed proc_t, freeing any additional acquired memory associated
|
||||||
// with the previous process or thread.
|
// 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);
|
||||||
|
extern proc_t* readeither(PROCTAB *restrict const PT, proc_t *restrict x);
|
||||||
|
|
||||||
// warning: interface may change
|
// warning: interface may change
|
||||||
extern int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid);
|
extern int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid);
|
||||||
@ -254,9 +261,9 @@ extern proc_t * get_proc_stats(pid_t pid, proc_t *p);
|
|||||||
#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_FILLSUPGRP 0x0400 // resolve supplementary group id -> group name
|
#define PROC_FILLSUPGRP 0x0400 // resolve supplementary group id -> group name
|
||||||
#define PROC_FILLOOM 0x0800 // alloc and fill in oom_score, oom_adj
|
#define PROC_FILLOOM 0x0800 // fill in proc_t oom_score and oom_adj
|
||||||
|
|
||||||
#define PROC_LOOSE_TASKS 0x2000 // threat threads as if they were processes
|
#define PROC_LOOSE_TASKS 0x2000 // treat threads as if they were processes
|
||||||
|
|
||||||
// Obsolete, consider only processes with one of the passed:
|
// Obsolete, consider only processes with one of the passed:
|
||||||
#define PROC_PID 0x1000 // process id numbers ( 0 terminated)
|
#define PROC_PID 0x1000 // process id numbers ( 0 terminated)
|
||||||
|
@ -284,7 +284,6 @@ static void lists_and_needs(void){
|
|||||||
}
|
}
|
||||||
if(!unix_f_option){
|
if(!unix_f_option){
|
||||||
proc_format_needs &= ~PROC_FILLCOM;
|
proc_format_needs &= ~PROC_FILLCOM;
|
||||||
proc_format_needs |= PROC_EDITCMDLCVT;
|
|
||||||
needs_for_sort &= ~PROC_FILLCOM;
|
needs_for_sort &= ~PROC_FILLCOM;
|
||||||
}
|
}
|
||||||
// convert ARG to COM as a standard
|
// convert ARG to COM as a standard
|
||||||
@ -508,7 +507,7 @@ static void fancy_spew(void){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(thread_flags & TF_loose_tasks){
|
if(thread_flags & TF_loose_tasks){
|
||||||
pd = readproctab2(want_this_proc_nop, want_this_proc_pcpu, ptp);
|
pd = readproctab3(want_this_proc_pcpu, ptp);
|
||||||
}else{
|
}else{
|
||||||
pd = readproctab2(want_this_proc_pcpu, (void*)0xdeadbeaful, ptp);
|
pd = readproctab2(want_this_proc_pcpu, (void*)0xdeadbeaful, ptp);
|
||||||
}
|
}
|
||||||
|
45
ps/output.c
45
ps/output.c
@ -334,8 +334,8 @@ Modifications to the arguments are not shown.
|
|||||||
/*
|
/*
|
||||||
* "args", "cmd", "command" are all the same: long unless c
|
* "args", "cmd", "command" are all the same: long unless c
|
||||||
* "comm", "ucmd", "ucomm" are all the same: short unless -f
|
* "comm", "ucmd", "ucomm" are all the same: short unless -f
|
||||||
* ( determinations are made in display.c, we just deal with results ) */
|
* ( determinations are made in display.c, we mostly deal with results ) */
|
||||||
static int pr_argcom(char *restrict const outbuf, const proc_t *restrict const pp){
|
static int pr_args(char *restrict const outbuf, const proc_t *restrict const pp){
|
||||||
char *endp = outbuf;
|
char *endp = outbuf;
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
int rightward=max_rightward;
|
int rightward=max_rightward;
|
||||||
@ -345,7 +345,33 @@ static int pr_argcom(char *restrict const outbuf, const proc_t *restrict const p
|
|||||||
endp += fh;
|
endp += fh;
|
||||||
rightward -= fh;
|
rightward -= fh;
|
||||||
}
|
}
|
||||||
if(pp->cmdline)
|
if(pp->cmdline && !bsd_c_option)
|
||||||
|
endp += escaped_copy(endp, *pp->cmdline, OUTBUF_SIZE, &rightward);
|
||||||
|
else
|
||||||
|
endp += escape_command(endp, pp, OUTBUF_SIZE, &rightward, ESC_DEFUNCT);
|
||||||
|
|
||||||
|
if(bsd_e_option && rightward>1) {
|
||||||
|
if(pp->environ && *pp->environ)
|
||||||
|
endp += escape_strlist(endp, pp->environ, OUTBUF_SIZE, &rightward);
|
||||||
|
}
|
||||||
|
return max_rightward-rightward;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "args", "cmd", "command" are all the same: long unless c
|
||||||
|
* "comm", "ucmd", "ucomm" are all the same: short unless -f
|
||||||
|
* ( determinations are made in display.c, we mostly deal with results ) */
|
||||||
|
static int pr_comm(char *restrict const outbuf, const proc_t *restrict const pp){
|
||||||
|
char *endp = outbuf;
|
||||||
|
unsigned flags;
|
||||||
|
int rightward=max_rightward;
|
||||||
|
|
||||||
|
if(forest_prefix){
|
||||||
|
int fh = forest_helper(outbuf);
|
||||||
|
endp += fh;
|
||||||
|
rightward -= fh;
|
||||||
|
}
|
||||||
|
if(pp->cmdline && unix_f_option)
|
||||||
endp += escaped_copy(endp, *pp->cmdline, OUTBUF_SIZE, &rightward);
|
endp += escaped_copy(endp, *pp->cmdline, OUTBUF_SIZE, &rightward);
|
||||||
else
|
else
|
||||||
endp += escape_command(endp, pp, OUTBUF_SIZE, &rightward, ESC_DEFUNCT);
|
endp += escape_command(endp, pp, OUTBUF_SIZE, &rightward, ESC_DEFUNCT);
|
||||||
@ -354,7 +380,6 @@ static int pr_argcom(char *restrict const outbuf, const proc_t *restrict const p
|
|||||||
if(pp->environ && *pp->environ)
|
if(pp->environ && *pp->environ)
|
||||||
endp += escape_strlist(endp, pp->environ, OUTBUF_SIZE, &rightward);
|
endp += escape_strlist(endp, pp->environ, OUTBUF_SIZE, &rightward);
|
||||||
}
|
}
|
||||||
//return endp - outbuf;
|
|
||||||
return max_rightward-rightward;
|
return max_rightward-rightward;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1283,7 +1308,7 @@ static const format_struct format_array[] = {
|
|||||||
{"addr_1", "ADDR", pr_nop, sr_nop, 1, 0, LNX, AN|LEFT},
|
{"addr_1", "ADDR", pr_nop, sr_nop, 1, 0, LNX, AN|LEFT},
|
||||||
{"alarm", "ALARM", pr_alarm, sr_alarm, 5, 0, LNX, AN|RIGHT},
|
{"alarm", "ALARM", pr_alarm, sr_alarm, 5, 0, LNX, AN|RIGHT},
|
||||||
{"argc", "ARGC", pr_nop, sr_nop, 4, 0, LNX, PO|RIGHT},
|
{"argc", "ARGC", pr_nop, sr_nop, 4, 0, LNX, PO|RIGHT},
|
||||||
{"args", "COMMAND", pr_argcom, sr_cmd, 27, ARG, U98, PO|UNLIMITED}, /*command*/
|
{"args", "COMMAND", pr_args, sr_cmd, 27, ARG, U98, PO|UNLIMITED}, /*command*/
|
||||||
{"atime", "TIME", pr_time, sr_nop, 8, 0, SOE, ET|RIGHT}, /*cputime*/ /* was 6 wide */
|
{"atime", "TIME", pr_time, sr_nop, 8, 0, SOE, ET|RIGHT}, /*cputime*/ /* was 6 wide */
|
||||||
{"blocked", "BLOCKED", pr_sigmask, sr_nop, 9, 0, BSD, TO|SIGNAL}, /*sigmask*/
|
{"blocked", "BLOCKED", pr_sigmask, sr_nop, 9, 0, BSD, TO|SIGNAL}, /*sigmask*/
|
||||||
{"bnd", "BND", pr_nop, sr_nop, 1, 0, AIX, TO|RIGHT},
|
{"bnd", "BND", pr_nop, sr_nop, 1, 0, AIX, TO|RIGHT},
|
||||||
@ -1295,11 +1320,11 @@ static const format_struct format_array[] = {
|
|||||||
{"class", "CLS", pr_class, sr_sched, 3, 0, XXX, TO|LEFT},
|
{"class", "CLS", pr_class, sr_sched, 3, 0, XXX, TO|LEFT},
|
||||||
{"cls", "CLS", pr_class, sr_sched, 3, 0, HPU, TO|RIGHT}, /*says HPUX or RT*/
|
{"cls", "CLS", pr_class, sr_sched, 3, 0, HPU, TO|RIGHT}, /*says HPUX or RT*/
|
||||||
{"cmaj_flt", "-", pr_nop, sr_cmaj_flt, 1, 0, LNX, AN|RIGHT},
|
{"cmaj_flt", "-", pr_nop, sr_cmaj_flt, 1, 0, LNX, AN|RIGHT},
|
||||||
{"cmd", "CMD", pr_argcom, sr_cmd, 27, ARG, DEC, PO|UNLIMITED}, /*ucomm*/
|
{"cmd", "CMD", pr_args, sr_cmd, 27, ARG, DEC, PO|UNLIMITED}, /*ucomm*/
|
||||||
{"cmin_flt", "-", pr_nop, sr_cmin_flt, 1, 0, LNX, AN|RIGHT},
|
{"cmin_flt", "-", pr_nop, sr_cmin_flt, 1, 0, LNX, AN|RIGHT},
|
||||||
{"cnswap", "-", pr_nop, sr_nop, 1, 0, LNX, AN|RIGHT},
|
{"cnswap", "-", pr_nop, sr_nop, 1, 0, LNX, AN|RIGHT},
|
||||||
{"comm", "COMMAND", pr_argcom, sr_cmd, 15, COM, U98, PO|UNLIMITED}, /*ucomm*/
|
{"comm", "COMMAND", pr_comm, sr_cmd, 15, COM, U98, PO|UNLIMITED}, /*ucomm*/
|
||||||
{"command", "COMMAND", pr_argcom, sr_cmd, 27, ARG, XXX, PO|UNLIMITED}, /*args*/
|
{"command", "COMMAND", pr_args, sr_cmd, 27, ARG, XXX, PO|UNLIMITED}, /*args*/
|
||||||
{"context", "CONTEXT", pr_context, sr_nop, 31, 0, LNX, ET|LEFT},
|
{"context", "CONTEXT", pr_context, sr_nop, 31, 0, LNX, ET|LEFT},
|
||||||
{"cp", "CP", pr_cp, sr_pcpu, 3, 0, DEC, ET|RIGHT}, /*cpu*/
|
{"cp", "CP", pr_cp, sr_pcpu, 3, 0, DEC, ET|RIGHT}, /*cpu*/
|
||||||
{"cpu", "CPU", pr_nop, sr_nop, 3, 0, BSD, AN|RIGHT}, /* FIXME ... HP-UX wants this as the CPU number for SMP? */
|
{"cpu", "CPU", pr_nop, sr_nop, 3, 0, BSD, AN|RIGHT}, /* FIXME ... HP-UX wants this as the CPU number for SMP? */
|
||||||
@ -1481,8 +1506,8 @@ static const format_struct format_array[] = {
|
|||||||
{"tty4", "TTY", pr_tty4, sr_tty, 4, 0, LNX, PO|LEFT},
|
{"tty4", "TTY", pr_tty4, sr_tty, 4, 0, LNX, PO|LEFT},
|
||||||
{"tty8", "TTY", pr_tty8, sr_tty, 8, 0, LNX, PO|LEFT},
|
{"tty8", "TTY", pr_tty8, sr_tty, 8, 0, LNX, PO|LEFT},
|
||||||
{"u_procp", "UPROCP", pr_nop, sr_nop, 6, 0, DEC, AN|RIGHT},
|
{"u_procp", "UPROCP", pr_nop, sr_nop, 6, 0, DEC, AN|RIGHT},
|
||||||
{"ucmd", "CMD", pr_argcom, sr_cmd, 15, COM, DEC, PO|UNLIMITED}, /*ucomm*/
|
{"ucmd", "CMD", pr_comm, sr_cmd, 15, COM, DEC, PO|UNLIMITED}, /*ucomm*/
|
||||||
{"ucomm", "COMMAND", pr_argcom, sr_cmd, 15, COM, XXX, PO|UNLIMITED}, /*comm*/
|
{"ucomm", "COMMAND", pr_comm, sr_cmd, 15, COM, XXX, PO|UNLIMITED}, /*comm*/
|
||||||
{"uid", "UID", pr_euid, sr_euid, 5, 0, XXX, ET|RIGHT},
|
{"uid", "UID", pr_euid, sr_euid, 5, 0, XXX, ET|RIGHT},
|
||||||
{"uid_hack", "UID", pr_euser, sr_euser, 8, USR, XXX, ET|USER},
|
{"uid_hack", "UID", pr_euser, sr_euser, 8, USR, XXX, ET|USER},
|
||||||
{"umask", "UMASK", pr_nop, sr_nop, 5, 0, DEC, AN|RIGHT},
|
{"umask", "UMASK", pr_nop, sr_nop, 5, 0, DEC, AN|RIGHT},
|
||||||
|
40
top.c
40
top.c
@ -104,7 +104,7 @@ static int No_ksyms = -1, // set to '0' if ksym avail, '1' otherwise
|
|||||||
Batch = 0, // batch mode, collect no input, dumb output
|
Batch = 0, // batch mode, collect no input, dumb output
|
||||||
Loops = -1, // number of iterations, -1 loops forever
|
Loops = -1, // number of iterations, -1 loops forever
|
||||||
Secure_mode = 0, // set if some functionality restricted
|
Secure_mode = 0, // set if some functionality restricted
|
||||||
Thread_mode = 0, // set w/ 'H' - show threads via readtask()
|
Thread_mode = 0, // set w/ 'H' - show threads via readeither()
|
||||||
Width_mode = 0; // set w/ 'w' - potential output override
|
Width_mode = 0; // set w/ 'w' - potential output override
|
||||||
|
|
||||||
/* Unchangeable cap's stuff built just once (if at all) and
|
/* Unchangeable cap's stuff built just once (if at all) and
|
||||||
@ -1913,57 +1913,31 @@ static proc_t **procs_refresh (proc_t **ppt) {
|
|||||||
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*(*read_something)(PROCTAB*, proc_t*);
|
||||||
|
|
||||||
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)))
|
||||||
error_exit(fmtmk("failed openproc: %s", strerror(errno)));
|
error_exit(fmtmk("failed openproc: %s", strerror(errno)));
|
||||||
|
read_something = Thread_mode ? readeither : readproc;
|
||||||
|
|
||||||
// i) Allocated Chunks: *Existing* table; refresh + reuse
|
// i) Allocated Chunks: *Existing* table; refresh + reuse
|
||||||
if (!Thread_mode) {
|
|
||||||
while (curmax < savmax) {
|
while (curmax < savmax) {
|
||||||
if (!(ptask = readproc(PT, ppt[curmax]))) break;
|
if (!(ptask = read_something(PT, ppt[curmax]))) break;
|
||||||
prochlp(ptask); // tally & complete this proc_t
|
prochlp(ptask); // tally & complete this proc_t
|
||||||
++curmax;
|
++curmax;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else { // acquire as separate threads
|
|
||||||
while (curmax < savmax) {
|
|
||||||
if (!(ptask = readproc(PT, NULL))) break;
|
|
||||||
while (curmax < savmax) {
|
|
||||||
if (!(pthrd = readtask(PT, ptask, ppt[curmax]))) break;
|
|
||||||
prochlp(pthrd); // tally & complete this thread
|
|
||||||
++curmax;
|
|
||||||
}
|
|
||||||
freeproc(ptask); // readproc's proc_t not needed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ii) Unallocated Chunks: *New* or *Existing* table; extend + fill
|
// ii) Unallocated Chunks: *New* or *Existing* table; extend + fill
|
||||||
if (!Thread_mode) {
|
|
||||||
while (ptask) {
|
while (ptask) {
|
||||||
// realloc as we go, keeping 'ppt' ahead of 'currmax++'
|
// realloc as we go, keeping 'ppt' ahead of 'currmax++'
|
||||||
ppt = alloc_r(ppt, (curmax + 1) * PTRsz);
|
ppt = alloc_r(ppt, (curmax + 1) * PTRsz);
|
||||||
// here, readproc will allocate the underlying proc_t stg
|
// here, the library will allocate the underlying proc_t stg
|
||||||
if ((ptask = readproc(PT, NULL))) {
|
if ((ptask = read_something(PT, NULL))) {
|
||||||
prochlp(ptask); // tally & complete this proc_t
|
prochlp(ptask); // tally & complete this proc_t
|
||||||
ppt[curmax++] = ptask;
|
ppt[curmax++] = ptask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else { // acquire as separate threads
|
|
||||||
while (ptask) {
|
|
||||||
if ((ptask = readproc(PT, NULL))) {
|
|
||||||
for (;;) {
|
|
||||||
ppt = alloc_r(ppt, (curmax + 1) * PTRsz);
|
|
||||||
if (!(pthrd = readtask(PT, ptask, NULL))) break;
|
|
||||||
prochlp(pthrd); // tally & complete this thread
|
|
||||||
ppt[curmax++] = pthrd;
|
|
||||||
}
|
|
||||||
freeproc(ptask); // readproc's proc_t not needed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closeproc(PT);
|
closeproc(PT);
|
||||||
|
|
||||||
// iii) Chunkless: make 'eot' entry, after ensuring proc_t exists
|
// iii) Chunkless: make 'eot' entry, after ensuring proc_t exists
|
||||||
|
Loading…
Reference in New Issue
Block a user