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:
317
proc/readproc.c
317
proc/readproc.c
@@ -38,6 +38,12 @@ extern void __cyg_profile_func_enter(void*,void*);
|
||||
#define LEAVE(x)
|
||||
#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
|
||||
// convert hex string to unsigned long long
|
||||
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
|
||||
// ( 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);
|
||||
#ifdef QUICK_THREADS
|
||||
if (!IS_THREAD(p)) {
|
||||
#endif
|
||||
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);
|
||||
#ifdef QUICK_THREADS
|
||||
}
|
||||
#endif
|
||||
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
|
||||
// generalized in support of these new libproc flags:
|
||||
// PROC_EDITCGRPCVT, PROC_EDITCMDLCVT
|
||||
static int read_unvectored(char *restrict const dst, unsigned sz, unsigned pid, const char *what, char sep) {
|
||||
char name[32];
|
||||
static int read_unvectored(char *restrict const dst, unsigned sz, const char* whom, const char *what, char sep) {
|
||||
char path[PROCPATHLEN];
|
||||
int fd;
|
||||
unsigned n = 0;
|
||||
|
||||
snprintf(name, sizeof name, "/proc/%u/%s", pid, what);
|
||||
fd = open(name, O_RDONLY);
|
||||
snprintf(path, sizeof(path), "%s/%s", whom, what);
|
||||
fd = open(path, O_RDONLY);
|
||||
if(fd==-1) return 0;
|
||||
|
||||
for(;;){
|
||||
ssize_t r = read(fd,dst+n,sz-n);
|
||||
if(r==-1){
|
||||
@@ -618,17 +631,17 @@ static char** vectorize_this_str (const char* src) {
|
||||
#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
|
||||
// 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) )
|
||||
char sbuf[1024], dbuf[1024];
|
||||
char *src, *dst, *grp, *eob;
|
||||
int tot, x, whackable_int = sizeof(dbuf);
|
||||
|
||||
*(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) {
|
||||
x = 1; // loop assist
|
||||
if (!*src) continue;
|
||||
@@ -644,15 +657,15 @@ static void fill_cgroup_cvt (proc_t *restrict p) {
|
||||
#undef vMAX
|
||||
}
|
||||
|
||||
// This routine reads /proc/#/cmdline for the designated task, "escapes"
|
||||
// the result into a single string represented as a single vector and
|
||||
// guarantees the caller a valid proc_t.cmdline pointer.
|
||||
static void fill_cmdline_cvt (proc_t *restrict p) {
|
||||
// This routine reads a 'cmdline' for the designated proc_t, "escapes"
|
||||
// the result into a single string represented as a single vector
|
||||
// and guarantees the caller a valid proc_t.cmdline pointer.
|
||||
static void fill_cmdline_cvt (const char* directory, proc_t *restrict p) {
|
||||
#define uFLG ( ESC_BRACKETS | ESC_DEFUNCT )
|
||||
char sbuf[2048], dbuf[2048];
|
||||
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);
|
||||
else
|
||||
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
|
||||
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 */
|
||||
|
||||
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;
|
||||
stat2proc(sbuf, p);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
if (flags & PROC_FILLSUPGRP)
|
||||
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_EDITCMDLCVT)
|
||||
fill_cmdline_cvt(p);
|
||||
fill_cmdline_cvt(path, p);
|
||||
else
|
||||
p->cmdline = file2strvec(path, "cmdline");
|
||||
} 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
|
||||
&& linux_version_code >= LINUX_VERSION(2,6,24)) {
|
||||
if (flags & PROC_EDITCGRPCVT)
|
||||
fill_cgroup_cvt(p);
|
||||
fill_cgroup_cvt(path, p);
|
||||
else
|
||||
p->cgroup = file2strvec(path, "cgroup");
|
||||
} else
|
||||
@@ -773,9 +788,9 @@ static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict cons
|
||||
|
||||
#ifdef OOMEM_ENABLE
|
||||
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);
|
||||
if (likely( file2str(path, "oom_adj", sbuf, sizeof sbuf) != -1 ))
|
||||
if (likely(file2str(path, "oom_adj", sbuf, sizeof sbuf) != -1))
|
||||
oomadj2proc(sbuf, p);
|
||||
}
|
||||
#endif
|
||||
@@ -787,7 +802,11 @@ next_proc:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// 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)
|
||||
#endif
|
||||
// t is the POSIX thread (task group member, generally not the leader)
|
||||
// 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) {
|
||||
@@ -798,39 +817,32 @@ static proc_t* simple_readtask(PROCTAB *restrict const PT, const proc_t *restric
|
||||
if (unlikely(stat(path, &sb) == -1)) /* no such dirent (anymore) */
|
||||
goto next_task;
|
||||
|
||||
// if ((flags & PROC_UID) && !XinLN(uid_t, sb.st_uid, PT->uids, PT->nuid))
|
||||
// goto next_task; /* not one of the requested uids */
|
||||
// if ((flags & PROC_UID) && !XinLN(uid_t, sb.st_uid, PT->uids, PT->nuid))
|
||||
// goto next_task; /* not one of the requested uids */
|
||||
|
||||
t->euid = sb.st_uid; /* need a way to get real uid */
|
||||
t->egid = sb.st_gid; /* need a way to get real gid */
|
||||
|
||||
if (flags & PROC_FILLSTAT) { // read /proc/#/task/#/stat
|
||||
if (unlikely( file2str(path, "stat", sbuf, sizeof sbuf) == -1 ))
|
||||
if (flags & PROC_FILLSTAT) { // read /proc/#/task/#/stat
|
||||
if (unlikely(file2str(path, "stat", sbuf, sizeof sbuf) == -1))
|
||||
goto next_task;
|
||||
stat2proc(sbuf, t);
|
||||
}
|
||||
|
||||
if (flags & PROC_FILLMEM) { // read /proc/#/task/#statm
|
||||
#if 1
|
||||
if (likely(file2str(path, "statm", sbuf, sizeof sbuf) != -1 ))
|
||||
#ifndef QUICK_THREADS
|
||||
if (flags & PROC_FILLMEM) // read /proc/#/task/#statm
|
||||
if (likely(file2str(path, "statm", sbuf, sizeof sbuf) != -1))
|
||||
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
|
||||
}
|
||||
|
||||
if (flags & PROC_FILLSTATUS) { // read /proc/#/task/#/status
|
||||
if (likely( file2str(path, "status", sbuf, sizeof sbuf) != -1 )){
|
||||
status2proc(sbuf, t, 0);
|
||||
if (flags & PROC_FILLSUPGRP)
|
||||
supgrps_from_supgids(t);
|
||||
}
|
||||
if (flags & PROC_FILLSTATUS) { // read /proc/#/task/#/status
|
||||
if (likely(file2str(path, "status", sbuf, sizeof sbuf) != -1)) {
|
||||
status2proc(sbuf, t, 0);
|
||||
#ifndef QUICK_THREADS
|
||||
if (flags & PROC_FILLSUPGRP)
|
||||
supgrps_from_supgids(t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* some number->text resolving which is time consuming */
|
||||
@@ -853,47 +865,71 @@ static proc_t* simple_readtask(PROCTAB *restrict const PT, const proc_t *restric
|
||||
}
|
||||
}
|
||||
|
||||
#if 1 // begin active ------------------------
|
||||
if (unlikely(flags & PROC_FILLENV)) // read /proc/#/task/#/environ
|
||||
t->environ = file2strvec(path, "environ");
|
||||
else
|
||||
t->environ = NULL;
|
||||
#ifdef QUICK_THREADS
|
||||
if (!p) {
|
||||
if (flags & PROC_FILLMEM)
|
||||
if (likely(file2str(path, "statm", sbuf, sizeof sbuf) != -1))
|
||||
statm2proc(sbuf, t);
|
||||
|
||||
if (flags & (PROC_FILLCOM|PROC_FILLARG)) { // read /proc/#/task/#/cmdline
|
||||
if (flags & PROC_EDITCMDLCVT)
|
||||
fill_cmdline_cvt(t);
|
||||
if (flags & PROC_FILLSUPGRP)
|
||||
supgrps_from_supgids(t);
|
||||
#endif
|
||||
if (unlikely(flags & PROC_FILLENV)) // read /proc/#/task/#/environ
|
||||
t->environ = file2strvec(path, "environ");
|
||||
else
|
||||
t->cmdline = file2strvec(path, "cmdline");
|
||||
} else
|
||||
t->cmdline = NULL;
|
||||
t->environ = 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->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 ------------------------
|
||||
if (flags & (PROC_FILLCOM|PROC_FILLARG)) { // read /proc/#/task/#/cmdline
|
||||
if (flags & PROC_EDITCMDLCVT)
|
||||
fill_cmdline_cvt(path, t);
|
||||
else
|
||||
t->cmdline = file2strvec(path, "cmdline");
|
||||
} else
|
||||
t->cmdline = NULL;
|
||||
|
||||
#ifdef OOMEM_ENABLE
|
||||
t->oom_score = p->oom_score;
|
||||
t->oom_adj = p->oom_adj;
|
||||
if ((flags & PROC_FILLCGROUP) // read /proc/#/task/#/cgroup
|
||||
&& linux_version_code >= LINUX_VERSION(2,6,24)) {
|
||||
if (flags & PROC_EDITCGRPCVT)
|
||||
fill_cgroup_cvt(path, t);
|
||||
else
|
||||
t->cgroup = file2strvec(path, "cgroup");
|
||||
} else
|
||||
t->cgroup = NULL;
|
||||
|
||||
#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->environ = p->environ;
|
||||
t->cgroup = p->cgroup;
|
||||
if (t->supgid) free(t->supgid);
|
||||
t->supgid = p->supgid;
|
||||
t->supgrp = p->supgrp;
|
||||
MK_THREAD(t);
|
||||
}
|
||||
#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;
|
||||
next_task:
|
||||
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 (;;) {
|
||||
ent = readdir(PT->procfs);
|
||||
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->tid = p->tgid;
|
||||
@@ -932,11 +968,11 @@ static int simple_nexttid(PROCTAB *restrict const PT, const proc_t *restrict con
|
||||
for (;;) {
|
||||
ent = readdir(PT->taskdir);
|
||||
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->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);
|
||||
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) {
|
||||
char *restrict const path = PT->path;
|
||||
pid_t tgid = *(PT->pids)++;
|
||||
if(likely( tgid )){
|
||||
if(likely(tgid)){
|
||||
snprintf(path, PROCPATHLEN, "/proc/%d", tgid);
|
||||
p->tgid = tgid;
|
||||
p->tid = tgid; // they match for leaders
|
||||
@@ -983,7 +1019,7 @@ proc_t* readproc(PROCTAB *restrict const PT, proc_t *restrict p) {
|
||||
|
||||
for(;;){
|
||||
// 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
|
||||
ret = PT->reader(PT,p);
|
||||
@@ -1002,7 +1038,7 @@ out:
|
||||
// pointer (boolean false). Use the passed buffer instead of allocating
|
||||
// space if it is non-NULL.
|
||||
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 *saved_t;
|
||||
|
||||
@@ -1011,27 +1047,36 @@ proc_t* readtask(PROCTAB *restrict const PT, const proc_t *restrict const p, pro
|
||||
else free_acquired(t, 1);
|
||||
|
||||
// 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;
|
||||
PT->did_fake=1;
|
||||
memcpy(t,p,sizeof(proc_t));
|
||||
// use the per-task pending, not per-tgid pending
|
||||
#ifdef SIGNAL_STRING
|
||||
memcpy(&t->signal, &t->_sigpnd, sizeof t->signal);
|
||||
memcpy(&t->signal, &t->_sigpnd, sizeof t->signal);
|
||||
#else
|
||||
t->signal = t->_sigpnd;
|
||||
t->signal = t->_sigpnd;
|
||||
#endif
|
||||
#ifdef QUICK_THREADS
|
||||
MK_THREAD(t);
|
||||
#else
|
||||
t->environ = NULL;
|
||||
t->cmdline = vectorize_this_str("n/a");
|
||||
t->cgroup = NULL;
|
||||
t->supgid = NULL;
|
||||
t->supgrp = NULL;
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
for(;;){
|
||||
// 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
|
||||
ret = PT->taskreader(PT,p,t,path); // simple_readtask
|
||||
@@ -1043,6 +1088,48 @@ out:
|
||||
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
|
||||
@@ -1116,6 +1203,7 @@ void look_up_our_self(proc_t *p) {
|
||||
|
||||
HIDDEN_ALIAS(readproc);
|
||||
HIDDEN_ALIAS(readtask);
|
||||
HIDDEN_ALIAS(readeither);
|
||||
|
||||
/* Convenient wrapper around openproc and readproc to slurp in the whole process
|
||||
* 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.
|
||||
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;
|
||||
unsigned n_proc_alloc = 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 long n_used = 0;
|
||||
|
||||
proc_data_t *pd;
|
||||
|
||||
for(;;){
|
||||
proc_t *tmp;
|
||||
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
|
||||
tmp = data+(tmp-old);
|
||||
//if(!data) return NULL;
|
||||
memset(data+n_used+1, 0, sizeof(proc_t)*(n_alloc-(n_used+1)));
|
||||
}
|
||||
if(n_task_alloc == n_task){
|
||||
//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->task = ttab;
|
||||
pd->nproc = n_proc;
|
||||
pd->ntask = n_task;
|
||||
pd.proc = ptab;
|
||||
pd.task = ttab;
|
||||
pd.nproc = n_proc;
|
||||
pd.ntask = n_task;
|
||||
if(PT->flags & PROC_LOOSE_TASKS){
|
||||
pd->tab = ttab;
|
||||
pd->n = n_task;
|
||||
pd.tab = ttab;
|
||||
pd.n = n_task;
|
||||
}else{
|
||||
pd->tab = ptab;
|
||||
pd->n = n_proc;
|
||||
pd.tab = ptab;
|
||||
pd.n = n_proc;
|
||||
}
|
||||
// change array indexes to pointers
|
||||
while(n_proc--) ptab[n_proc] = data+(long)(ptab[n_proc]);
|
||||
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;
|
||||
}
|
||||
|
||||
#undef MK_THREAD
|
||||
#undef IS_THREAD
|
||||
|
Reference in New Issue
Block a user