library: standardize portions of interface, <PIDS> api

This represents a rather major interface redesign. The
following highlights most of the changes/enhancements.

. The 'read' interface (employed by pgrep & pidof) saw
the biggest change. The 'open', 'next' and 'shut' guys
all went bye-bye, replaced by a single 'get' function.

. The items specified at 'new' time no longer serve as
the maximum. In fact, items & numitems are now treated
as optional, should callers prefer to wait until later
when the 'reset' function would then become mandatory.

. Even at 'reset' time, the stacks are not tied to any
sort of maximum. They will grow dynamically as needed.

. The order of some parameters was changed to parallel
that found in our other APIs. Specifically, when items
& numitems are needed they're specified in that order.

. A user will no longer be prevented from concurrently
employing any accessor functions. In other words, that
'get' (old 'read') won't preclude 'reap' and 'select'.

. A duplicate enumerator was found dealing with locked
resident pages. So, the name VM_LOCK was eliminated in
favor of VM_RSS_LOCKED, which is way more descriptive.

. The struct address returned to callers following any
reap() or select() is now more sharable as pids_fetch.

. Some input parameter names were changed to make them
more descriptive of the intended purpose/requirements.

------------------------------------------------------
Internally, there were numerous implementation changes
made that did not directly impact any potential users.

. That #define FPRINT_STACKS was eliminated along with
the associated supporting function and its invocation.

. Addresses returned following 'reap' or 'select' will
now be NULL delimited, so one has the option of stacks
access via the total count or this new NULL fencepost.

. Input params were simplified and generalized in both
oldproc_open() & close() to enable more than 1 PROCTAB
to be open simultaneously, which was required for get.

. The PROCPS_PIDS_logical_end enum was relocated after
the Item_table making the need to keep it synchronized
more apparent (if the table expands it's right there).

. The 'Public function' section of the source file was
subdivided into 1) the three basic required functions;
and 2) functions that can sometimes vary between APIs.

Signed-off-by: Jim Warner <james.warner@comcast.net>
This commit is contained in:
Jim Warner 2016-05-14 00:00:00 -05:00 committed by Craig Small
parent bfb7361980
commit 9ebadc1438
3 changed files with 326 additions and 397 deletions

View File

@ -25,15 +25,13 @@ global:
procps_ns_read_pid; procps_ns_read_pid;
procps_pid_length; procps_pid_length;
procps_pids_new; procps_pids_new;
procps_pids_read_next;
procps_pids_read_open;
procps_pids_read_shut;
procps_pids_reap;
procps_pids_ref; procps_pids_ref;
procps_pids_unref;
procps_pids_get;
procps_pids_reap;
procps_pids_reset; procps_pids_reset;
procps_pids_select; procps_pids_select;
procps_pids_sort; procps_pids_sort;
procps_pids_unref;
procps_slabinfo_new; procps_slabinfo_new;
procps_slabinfo_read; procps_slabinfo_read;
procps_slabinfo_ref; procps_slabinfo_ref;

View File

@ -45,16 +45,10 @@
#include "wchan.h" // ( maybe just temporary? ) #include "wchan.h" // ( maybe just temporary? )
//#define UNREF_RPTHASH // report on hashing, at uref time //#define UNREF_RPTHASH // report on hashing, at uref time
//#define FPRINT_STACKS // enable fprint_stacks output
#define FILL_ID_MAX 255 // upper limit for pid/uid fills #define FILL_ID_MAX 255 // upper limit for pid/uid fills
#define MEMORY_INCR 128 // amt by which allocations grow #define MEMORY_INCR 128 // amt by which allocations grow
#define READS_BEGUN (info->read) // a read is in progress
// next MUST be kept in sync with highest value enum
enum pids_item PROCPS_PIDS_logical_end = PROCPS_PIDS_WCHAN_NAME + 1;
// these represent the proc_t fields whose storage cannot be managed // these represent the proc_t fields whose storage cannot be managed
// optimally if they are ever referenced more than once in any stack // optimally if they are ever referenced more than once in any stack
enum rel_ref { enum rel_ref {
@ -66,17 +60,16 @@ enum rel_ref {
struct stacks_extent { struct stacks_extent {
struct pids_stack **stacks; struct pids_stack **stacks;
int ext_numitems; // includes 'logical_end' delimiter
int ext_numstacks; int ext_numstacks;
struct stacks_extent *next; struct stacks_extent *next;
}; };
struct fetch_support { struct fetch_support {
struct pids_stack **anchor; // reapable/fillable (consolidated extents) struct pids_stack **anchor; // reap/select consolidated extents
int n_alloc; // number of above pointers allocated int n_alloc; // number of above pointers allocated
int n_inuse; // number of above pointers occupied int n_inuse; // number of above pointers occupied
int n_alloc_save; // last known summary.stacks allocation int n_alloc_save; // last known summary.stacks allocation
struct pids_reap summary; // counts + stacks for return to caller struct pids_fetch summary; // counts + stacks for return to caller
}; };
struct procps_pidsinfo { struct procps_pidsinfo {
@ -86,19 +79,20 @@ struct procps_pidsinfo {
enum pids_item *items; // includes 'logical_end' delimiter enum pids_item *items; // includes 'logical_end' delimiter
struct stacks_extent *extents; // anchor for all resettable extents struct stacks_extent *extents; // anchor for all resettable extents
struct stacks_extent *otherexts; // anchor for single stack invariant extents struct stacks_extent *otherexts; // anchor for single stack invariant extents
struct fetch_support reap; // support for procps_pids_reap struct fetch_support fetch; // support for procps_pids_reap & select
struct fetch_support select; // support for procps_pids_select
int history_yes; // need historical data int history_yes; // need historical data
struct history_info *hist; // pointer to historical support data struct history_info *hist; // pointer to historical support data
int dirty_stacks; // extents need dynamic storage clean int dirty_stacks; // extents need dynamic storage clean
struct stacks_extent *read; // an extent used for active reads
proc_t*(*read_something)(PROCTAB*, proc_t*); // readproc/readeither via which proc_t*(*read_something)(PROCTAB*, proc_t*); // readproc/readeither via which
unsigned pgs2k_shift; // to convert some proc vaules unsigned pgs2k_shift; // to convert some proc vaules
unsigned flags; // the old library PROC_FILL flagss unsigned oldflags; // the old library PROC_FILL flagss
PROCTAB *PT; // the old library essential interface PROCTAB *PT; // the old library essential interface
unsigned long hertz; // for TIME_ALL & TIME_ELAPSED calculations unsigned long hertz; // for TIME_ALL & TIME_ELAPSED calculations
unsigned long long boot_seconds; // for TIME_ELAPSED calculation unsigned long long boot_seconds; // for TIME_ELAPSED calculation
int ref_counts[MAXIMUM_ref]; // ref counts for special string fields int ref_counts[MAXIMUM_ref]; // ref counts for special string fields
PROCTAB *get_PT; // old library interface for active 'get'
struct stacks_extent *get_ext; // an extent used for active 'get'
enum pids_fetch_type get_type; // last known type of 'get' request
}; };
@ -242,7 +236,6 @@ setDECL(TTY_NUMBER) { char buf[64]; (void)I; dev_to_tty(buf, sizeof(buf), P->t
REG_set(VM_DATA, ul_int, vm_data) REG_set(VM_DATA, ul_int, vm_data)
REG_set(VM_EXE, ul_int, vm_exe) REG_set(VM_EXE, ul_int, vm_exe)
REG_set(VM_LIB, ul_int, vm_lib) REG_set(VM_LIB, ul_int, vm_lib)
REG_set(VM_LOCK, ul_int, vm_lock)
REG_set(VM_RSS, ul_int, vm_rss) REG_set(VM_RSS, ul_int, vm_rss)
REG_set(VM_RSS_ANON, ul_int, vm_rss_anon) REG_set(VM_RSS_ANON, ul_int, vm_rss_anon)
REG_set(VM_RSS_FILE, ul_int, vm_rss_file) REG_set(VM_RSS_FILE, ul_int, vm_rss_file)
@ -495,7 +488,6 @@ static struct {
{ RS(VM_DATA), f_status, NULL, QS(ul_int), 0, -1 }, { RS(VM_DATA), f_status, NULL, QS(ul_int), 0, -1 },
{ RS(VM_EXE), f_status, NULL, QS(ul_int), 0, -1 }, { RS(VM_EXE), f_status, NULL, QS(ul_int), 0, -1 },
{ RS(VM_LIB), f_status, NULL, QS(ul_int), 0, -1 }, { RS(VM_LIB), f_status, NULL, QS(ul_int), 0, -1 },
{ RS(VM_LOCK), f_status, NULL, QS(ul_int), 0, -1 },
{ RS(VM_RSS), f_status, NULL, QS(ul_int), 0, -1 }, { RS(VM_RSS), f_status, NULL, QS(ul_int), 0, -1 },
{ RS(VM_RSS_ANON), f_status, NULL, QS(ul_int), 0, -1 }, { RS(VM_RSS_ANON), f_status, NULL, QS(ul_int), 0, -1 },
{ RS(VM_RSS_FILE), f_status, NULL, QS(ul_int), 0, -1 }, { RS(VM_RSS_FILE), f_status, NULL, QS(ul_int), 0, -1 },
@ -512,6 +504,9 @@ static struct {
{ NULL, 0, NULL, NULL, 0, -1 } { NULL, 0, NULL, NULL, 0, -1 }
}; };
// next MUST be kept in sync with highest value enum
enum pids_item PROCPS_PIDS_logical_end = PROCPS_PIDS_WCHAN_NAME + 1;
#undef RS #undef RS
#undef FF #undef FF
#undef QS #undef QS
@ -776,19 +771,17 @@ static inline void assign_results (
static inline void cleanup_stack ( static inline void cleanup_stack (
struct pids_result *p, struct pids_result *this)
int depth)
{ {
int i; for (;;) {
enum pids_item item = this->item;
for (i = 0; i < depth; i++) { if (item >= PROCPS_PIDS_logical_end)
if (p->item >= PROCPS_PIDS_logical_end)
break; break;
if (Item_table[p->item].freefunc) if (Item_table[item].freefunc)
Item_table[p->item].freefunc(p); Item_table[item].freefunc(this);
if (p->item > PROCPS_PIDS_noop) if (item > PROCPS_PIDS_noop)
p->result.ull_int = 0; this->result.ull_int = 0;
++p; ++this;
} }
} // end: cleanup_stack } // end: cleanup_stack
@ -801,7 +794,7 @@ static inline void cleanup_stacks_all (
while (ext) { while (ext) {
for (i = 0; ext->stacks[i]; i++) for (i = 0; ext->stacks[i]; i++)
cleanup_stack(ext->stacks[i]->head, info->maxitems); cleanup_stack(ext->stacks[i]->head);
ext = ext->next; ext = ext->next;
}; };
info->dirty_stacks = 0; info->dirty_stacks = 0;
@ -835,52 +828,18 @@ static struct stacks_extent *extent_cut (
} // end: extent_cut } // end: extent_cut
static int extent_free ( static void extents_free_all (
struct procps_pidsinfo *info, struct procps_pidsinfo *info)
struct stacks_extent *ext)
{ {
if (extent_cut(info, ext)) { struct stacks_extent *ext = info->extents;
while (ext) {
info->extents = ext->next;
free(ext); free(ext);
return 0; ext = info->extents;
} };
return -1; info->dirty_stacks = 0;
} // end: extent_free } // end: extents_free_all
#ifdef FPRINT_STACKS
static void fprint_stacks (
void *stacks,
const char *who)
{
#include <stdio.h>
static int once = 0;
struct stacks_extent *ext = stacks;
int i, t, x, n = 0;
fprintf(stderr, " %s: called by '%s'\n", __func__, who);
fprintf(stderr, " %s: ext_numitems = %d, ext_numstacks = %d, extents = %p, next = %p\n", __func__, ext->ext_numitems, ext->ext_numstacks, ext, ext->next);
fprintf(stderr, " %s: stacks_extent results excluding the end-of-stack element ...\n", __func__);
for (x = 0; NULL != ext->stacks[x]; x++) {
struct pids_stack *h = ext->stacks[x];
struct pids_result *r = h->head;
fprintf(stderr, " %s: v[%03d] = %p, h = %p", __func__, x, h, r);
for (i = 0; r->item < PROCPS_PIDS_logical_end; i++, r++)
;
t = i + 1;
fprintf(stderr, " - found %d elements for stack %d\n", i, n);
++n;
}
if (!once) {
fprintf(stderr, " %s: found %d total stack(s), each %d bytes (including eos)\n", __func__, x, (int)(sizeof(struct pids_stack) + (sizeof(struct pids_result) * t)));
fprintf(stderr, " %s: sizeof(struct pids_stack) = %d\n", __func__, (int)sizeof(struct pids_stack));
fprintf(stderr, " %s: sizeof(struct pids_result) = %d\n", __func__, (int)sizeof(struct pids_result));
fprintf(stderr, " %s: sizeof(struct stacks_extent) = %d\n", __func__, (int)sizeof(struct stacks_extent));
once = 1;
}
fputc('\n', stderr);
return;
} // end: fprint_stacks
#endif
static inline struct pids_result *itemize_stack ( static inline struct pids_result *itemize_stack (
@ -900,8 +859,23 @@ static inline struct pids_result *itemize_stack (
} // end: itemize_stack } // end: itemize_stack
static void itemize_stacks_all (
struct procps_pidsinfo *info)
{
struct stacks_extent *ext = info->extents;
while (ext) {
int i;
for (i = 0; ext->stacks[i]; i++)
itemize_stack(ext->stacks[i]->head, info->curitems, info->items);
ext = ext->next;
};
info->dirty_stacks = 0;
}
static inline int items_check_failed ( static inline int items_check_failed (
int maxitems, int numitems,
enum pids_item *items) enum pids_item *items)
{ {
int i; int i;
@ -914,10 +888,10 @@ static inline int items_check_failed (
* if (procps_pids_new(&info, 3, PROCPS_PIDS_noop) < 0) * if (procps_pids_new(&info, 3, PROCPS_PIDS_noop) < 0)
* ^~~~~~~~~~~~~~~~ * ^~~~~~~~~~~~~~~~
*/ */
if (maxitems < 1 if (numitems < 1
|| (void *)items < (void *)0x8000) // twice as big as our largest enum || (void *)items < (void *)0x8000) // twice as big as our largest enum
return -1; return -1;
for (i = 0; i < maxitems; i++) { for (i = 0; i < numitems; i++) {
// a pids_item is currently unsigned, but we'll protect our future // a pids_item is currently unsigned, but we'll protect our future
if (items[i] < 0) if (items[i] < 0)
return -1; return -1;
@ -936,37 +910,36 @@ static inline void libflags_set (
int i, n; int i, n;
memset (info->ref_counts, 0, sizeof(info->ref_counts)); memset (info->ref_counts, 0, sizeof(info->ref_counts));
info->flags = info->history_yes = 0; info->oldflags = info->history_yes = 0;
for (i = 0; i < info->curitems; i++) { for (i = 0; i < info->curitems; i++) {
if (((e = info->items[i])) >= PROCPS_PIDS_logical_end) if (((e = info->items[i])) >= PROCPS_PIDS_logical_end)
break; break;
info->flags |= Item_table[e].oldflags; info->oldflags |= Item_table[e].oldflags;
info->history_yes |= Item_table[e].needhist; info->history_yes |= Item_table[e].needhist;
n = Item_table[e].refcount; n = Item_table[e].refcount;
if (n > -1) ++info->ref_counts[n]; if (n > -1) ++info->ref_counts[n];
} }
if (info->flags & f_either) { if (info->oldflags & f_either) {
if (!(info->flags & f_stat)) if (!(info->oldflags & f_stat))
info->flags |= f_status; info->oldflags |= f_status;
} }
return; return;
} // end: libflags_set } // end: libflags_set
static inline void oldproc_close ( static inline void oldproc_close (
struct procps_pidsinfo *info) PROCTAB **this)
{ {
if (info->PT != NULL) { if (*this != NULL) {
closeproc(info->PT); closeproc(*this);
info->PT = NULL; *this = NULL;
} }
return;
} // end: oldproc_close } // end: oldproc_close
static inline int oldproc_open ( static inline int oldproc_open (
struct procps_pidsinfo *info, PROCTAB **this,
unsigned supp_flgs, unsigned flags,
...) ...)
{ {
@ -974,12 +947,12 @@ static inline int oldproc_open (
int *ids; int *ids;
int num = 0; int num = 0;
if (info->PT == NULL) { if (*this == NULL) {
va_start(vl, supp_flgs); va_start(vl, flags);
ids = va_arg(vl, int*); ids = va_arg(vl, int*);
if (info->flags & PROC_UID) num = va_arg(vl, int); if (flags & PROC_UID) num = va_arg(vl, int);
va_end(vl); va_end(vl);
if (NULL == (info->PT = openproc(info->flags | supp_flgs, ids, num))) if (NULL == (*this = openproc(flags, ids, num)))
return 0; return 0;
} }
@ -1044,27 +1017,27 @@ static struct stacks_extent *stacks_alloc (
if (maxstacks < 1) if (maxstacks < 1)
return NULL; return NULL;
vect_size = sizeof(void *) * maxstacks; // address vectors themselves vect_size = sizeof(void *) * maxstacks; // size of the addr vectors |
vect_size += sizeof(void *); // plus NULL delimiter vect_size += sizeof(void *); // plus NULL addr delimiter |
head_size = sizeof(struct pids_stack); // a head struct head_size = sizeof(struct pids_stack); // size of that head struct |
list_size = sizeof(struct pids_result) * info->maxitems; // a results stack list_size = sizeof(struct pids_result) * info->maxitems; // any single results stack |
blob_size = sizeof(struct stacks_extent); // the extent anchor itself blob_size = sizeof(struct stacks_extent); // the extent anchor itself |
blob_size += vect_size; // all vectors + delim blob_size += vect_size; // plus room for addr vects |
blob_size += head_size * maxstacks; // all head structs blob_size += head_size * maxstacks; // plus room for head thing |
blob_size += list_size * maxstacks; // all results stacks blob_size += list_size * maxstacks; // plus room for our stacks |
/* note: all memory is allocated in a single blob, facilitating a later free(). /* note: all of our memory is allocated in a single blob, facilitating a later free(). |
as a minimum, it's important that the result structures themselves always be as a minimum, it is important that the result structures themselves always be |
contiguous for each stack since they're accessed through relative position). */ contiguous for every stack since they are accessed through relative position. | */
if (NULL == (p_blob = calloc(1, blob_size))) if (NULL == (p_blob = calloc(1, blob_size)))
return NULL; return NULL;
p_blob->next = info->extents; p_blob->next = info->extents; // push this extent onto... |
info->extents = p_blob; info->extents = p_blob; // ...some existing extents |
p_blob->stacks = (void *)p_blob + sizeof(struct stacks_extent); p_vect = (void *)p_blob + sizeof(struct stacks_extent); // prime our vector pointer |
p_vect = p_blob->stacks; p_blob->stacks = p_vect; // set actual vectors start |
v_head = (void *)p_vect + vect_size; v_head = (void *)p_vect + vect_size; // prime head pointer start |
v_list = v_head + (head_size * maxstacks); v_list = v_head + (head_size * maxstacks); // prime our stacks pointer |
for (i = 0; i < maxstacks; i++) { for (i = 0; i < maxstacks; i++) {
p_head = (struct pids_stack *)v_head; p_head = (struct pids_stack *)v_head;
@ -1073,89 +1046,187 @@ static struct stacks_extent *stacks_alloc (
v_list += list_size; v_list += list_size;
v_head += head_size; v_head += head_size;
} }
p_blob->ext_numitems = info->maxitems;
p_blob->ext_numstacks = maxstacks; p_blob->ext_numstacks = maxstacks;
#ifdef FPRINT_STACKS
fprint_stacks(p_blob, __func__);
#endif
return p_blob; return p_blob;
} // end: stacks_alloc } // end: stacks_alloc
static int stacks_dealloc (
struct procps_pidsinfo *info,
struct stacks_extent **these)
{
struct stacks_extent *ext;
int rc;
if (info == NULL || these == NULL)
return -EINVAL;
if ((*these)->stacks == NULL || (*these)->stacks[0] == NULL)
return -EINVAL;
ext = *these;
rc = extent_free(info, ext);
*these = NULL;
return rc;
} // end: stacks_dealloc
static int stacks_fetch ( static int stacks_fetch (
struct procps_pidsinfo *info, struct procps_pidsinfo *info)
struct fetch_support *this)
{ {
#define n_alloc this->n_alloc #define n_alloc info->fetch.n_alloc
#define n_inuse this->n_inuse #define n_inuse info->fetch.n_inuse
#define n_saved info->fetch.n_alloc_save
static proc_t task; // static for initial zeroes + later dynamic free(s) static proc_t task; // static for initial zeroes + later dynamic free(s)
struct stacks_extent *ext; struct stacks_extent *ext;
if (info == NULL || this == NULL)
return -1;
// initialize stuff ----------------------------------- // initialize stuff -----------------------------------
if (!this->anchor) { if (!info->fetch.anchor) {
if ((!(this->anchor = calloc(sizeof(void *), MEMORY_INCR))) if (!(info->fetch.anchor = calloc(sizeof(void *), MEMORY_INCR)))
|| (!(this->summary.stacks = calloc(sizeof(void *), MEMORY_INCR))) return -ENOMEM;
|| (!(ext = stacks_alloc(info, MEMORY_INCR))))
return -1;
memcpy(this->anchor, ext->stacks, sizeof(void *) * MEMORY_INCR);
n_alloc = MEMORY_INCR; n_alloc = MEMORY_INCR;
} }
if (info->dirty_stacks) if (!info->extents) {
cleanup_stacks_all(info); if (!(ext = stacks_alloc(info, n_alloc)))
return -ENOMEM;
memset(info->fetch.anchor, 0, sizeof(void *) * n_alloc);
memcpy(info->fetch.anchor, ext->stacks, sizeof(void *) * n_alloc);
itemize_stacks_all(info);
}
cleanup_stacks_all(info);
toggle_history(info); toggle_history(info);
memset(&this->summary.counts, 0, sizeof(struct pids_counts)); memset(&info->fetch.summary.counts, 0, sizeof(struct pids_counts));
// iterate stuff -------------------------------------- // iterate stuff --------------------------------------
n_inuse = 0; n_inuse = 0;
while (info->read_something(info->PT, &task)) { while (info->read_something(info->PT, &task)) {
if (!(n_inuse < n_alloc)) { if (!(n_inuse < n_alloc)) {
n_alloc += MEMORY_INCR; n_alloc += MEMORY_INCR;
if ((!(this->anchor = realloc(this->anchor, sizeof(void *) * n_alloc))) if ((!(info->fetch.anchor = realloc(info->fetch.anchor, sizeof(void *) * n_alloc)))
|| (!(ext = stacks_alloc(info, MEMORY_INCR)))) || (!(ext = stacks_alloc(info, MEMORY_INCR))))
return -1; return -1;
memcpy(this->anchor + n_inuse, ext->stacks, sizeof(void *) * MEMORY_INCR); memcpy(info->fetch.anchor + n_inuse, ext->stacks, sizeof(void *) * MEMORY_INCR);
} }
if (!proc_tally(info, &this->summary.counts, &task)) if (!proc_tally(info, &info->fetch.summary.counts, &task))
return -1; return -1;
assign_results(info, this->anchor[n_inuse++], &task); assign_results(info, info->fetch.anchor[n_inuse++], &task);
} }
// finalize stuff ------------------------------------- // finalize stuff -------------------------------------
if (this->n_alloc_save != n_alloc if (n_saved < n_alloc + 1) {
&& !(this->summary.stacks = realloc(this->summary.stacks, sizeof(void *) * n_alloc))) n_saved = n_alloc + 1;
return -1; if (!(info->fetch.summary.stacks = realloc(info->fetch.summary.stacks, sizeof(void *) * n_saved)))
memcpy(this->summary.stacks, this->anchor, sizeof(void *) * n_alloc); return -1;
this->n_alloc_save = n_alloc; }
memcpy(info->fetch.summary.stacks, info->fetch.anchor, sizeof(void *) * n_inuse);
info->fetch.summary.stacks[n_inuse] = NULL;
return n_inuse; // callers beware, this might be zero ! return n_inuse; // callers beware, this might be zero !
#undef n_alloc #undef n_alloc
#undef n_inuse #undef n_inuse
#undef n_saved
} // end: stacks_fetch } // end: stacks_fetch
// ___ Public Functions ||||||||||||||||||||||||||||||||||||||||||||||||||||||| // ___ Public Functions |||||||||||||||||||||||||||||||||||||||||||||||||||||||
// --- standard required functions --------------------------------------------
/*
* procps_pids_new():
*
* @info: location of returned new structure
*
* Returns: 0 on success <0 on failure
*/
PROCPS_EXPORT int procps_pids_new (
struct procps_pidsinfo **info,
enum pids_item *items,
int numitems)
{
struct procps_pidsinfo *p;
double uptime_secs;
int pgsz;
if (info == NULL || *info != NULL)
return -EINVAL;
if (!(p = calloc(1, sizeof(struct procps_pidsinfo))))
return -ENOMEM;
/* if we're without items or numitems, a later call to
procps_pids_reset() will become mandatory */
if (items && numitems) {
if (items_check_failed(numitems, items))
return -EINVAL;
// allow for our PROCPS_PIDS_logical_end
p->maxitems = numitems + 1;
if (!(p->items = calloc(p->maxitems, sizeof(enum pids_item))))
return -ENOMEM;
memcpy(p->items, items, sizeof(enum pids_item) * numitems);
p->items[numitems] = PROCPS_PIDS_logical_end;
p->curitems = p->maxitems;
libflags_set(p);
}
if (!(p->hist = calloc(MEMORY_INCR, sizeof(struct history_info))))
return -ENOMEM;
config_history(p);
pgsz = getpagesize();
while (pgsz > 1024) { pgsz >>= 1; p->pgs2k_shift++; }
p->hertz = procps_hertz_get();
procps_uptime(&uptime_secs, NULL);
p->boot_seconds = uptime_secs;
p->refcount = 1;
*info = p;
return 0;
} // end: procps_pids_new
PROCPS_EXPORT int procps_pids_ref (
struct procps_pidsinfo *info)
{
if (info == NULL)
return -EINVAL;
info->refcount++;
return info->refcount;
} // end: procps_pids_ref
PROCPS_EXPORT int procps_pids_unref (
struct procps_pidsinfo **info)
{
if (info == NULL || *info == NULL)
return -EINVAL;
(*info)->refcount--;
if ((*info)->refcount == 0) {
#ifdef UNREF_RPTHASH
unref_rpthash(*info);
#endif
if ((*info)->extents) {
cleanup_stacks_all(*info);
do {
struct stacks_extent *p = (*info)->extents;
(*info)->extents = (*info)->extents->next;
free(p);
} while ((*info)->extents);
}
if ((*info)->otherexts) {
struct stacks_extent *nextext, *ext = (*info)->otherexts;
while (ext) {
nextext = ext->next;
cleanup_stack(ext->stacks[0]->head);
free(ext);
ext = nextext;
};
}
if ((*info)->fetch.anchor)
free((*info)->fetch.anchor);
if ((*info)->fetch.summary.stacks)
free((*info)->fetch.summary.stacks);
if ((*info)->items)
free((*info)->items);
if ((*info)->hist) {
free((*info)->hist->PHist_sav);
free((*info)->hist->PHist_new);
free((*info)->hist);
}
free(*info);
*info = NULL;
return 0;
}
return (*info)->refcount;
} // end: procps_pids_unref
// --- variable interface functions -------------------------------------------
PROCPS_EXPORT struct pids_stack *fatal_proc_unmounted ( PROCPS_EXPORT struct pids_stack *fatal_proc_unmounted (
struct procps_pidsinfo *info, struct procps_pidsinfo *info,
int return_self) int return_self)
@ -1182,106 +1253,46 @@ PROCPS_EXPORT struct pids_stack *fatal_proc_unmounted (
} // end: fatal_proc_unmounted } // end: fatal_proc_unmounted
/* PROCPS_EXPORT struct pids_stack *procps_pids_get (
* procps_pids_new(): struct procps_pidsinfo *info,
* enum pids_fetch_type which)
* @info: location of returned new structure
*
* Returns: 0 on success <0 on failure
*/
PROCPS_EXPORT int procps_pids_new (
struct procps_pidsinfo **info,
int maxitems,
enum pids_item *items)
{
struct procps_pidsinfo *p;
double uptime_secs;
int pgsz;
if (info == NULL || *info != NULL)
return -EINVAL;
if (items_check_failed(maxitems, items))
return -EINVAL;
if (!(p = calloc(1, sizeof(struct procps_pidsinfo))))
return -ENOMEM;
// allow for our PROCPS_PIDS_logical_end
if (!(p->items = calloc((maxitems + 1), sizeof(enum pids_item)))) {
free(p);
return -ENOMEM;
}
if (!(p->hist = calloc((maxitems + 1), sizeof(struct history_info)))) {
free(p->items);
free(p);
return -ENOMEM;
}
memcpy(p->items, items, sizeof(enum pids_item) * maxitems);
p->items[maxitems] = PROCPS_PIDS_logical_end;
p->curitems = p->maxitems = maxitems + 1;
libflags_set(p);
pgsz = getpagesize();
while (pgsz > 1024) { pgsz >>= 1; p->pgs2k_shift++; }
config_history(p);
p->hertz = procps_hertz_get();
procps_uptime(&uptime_secs, NULL);
p->boot_seconds = uptime_secs;
p->refcount = 1;
*info = p;
return 0;
} // end: procps_pids_new
PROCPS_EXPORT struct pids_stack *procps_pids_read_next (
struct procps_pidsinfo *info)
{ {
static proc_t task; // static for initial zeroes + later dynamic free(s) static proc_t task; // static for initial zeroes + later dynamic free(s)
if (info == NULL || ! READS_BEGUN) if (info == NULL)
return NULL; return NULL;
if (info->dirty_stacks) { if (!info->curitems)
cleanup_stack(info->read->stacks[0]->head, info->maxitems); return NULL;
info->dirty_stacks = 0; if (which != PROCPS_FETCH_TASKS_ONLY && which != PROCPS_FETCH_THREADS_TOO)
return NULL;
fresh_start:
if (!info->get_ext) {
if (!(info->get_ext = stacks_alloc(info, 1)))
return NULL;
if (!oldproc_open(&info->get_PT, info->oldflags))
return NULL;
info->get_type = which;
info->read_something = which ? readeither : readproc;
} }
if (NULL == info->read_something(info->PT, &task))
if (info->get_type != which) {
oldproc_close(&info->get_PT);
cleanup_stack(info->get_ext->stacks[0]->head);
if (extent_cut(info, info->get_ext))
free(info->get_ext);
info->get_ext = NULL;
goto fresh_start;
}
cleanup_stack(info->get_ext->stacks[0]->head);
if (NULL == info->read_something(info->get_PT, &task))
return NULL; return NULL;
assign_results(info, info->read->stacks[0], &task); assign_results(info, info->get_ext->stacks[0], &task);
return info->read->stacks[0];
} // end: procps_pids_read_next
return info->get_ext->stacks[0];
PROCPS_EXPORT int procps_pids_read_open ( } // end: procps_pids_get
struct procps_pidsinfo *info,
enum pids_reap_type which)
{
if (info == NULL || READS_BEGUN)
return -EINVAL;
if (!info->maxitems && !info->curitems)
return -EINVAL;
if (which != PROCPS_REAP_TASKS_ONLY && which != PROCPS_REAP_THREADS_TOO)
return -EINVAL;
if (!(info->read = stacks_alloc(info, 1)))
return -ENOMEM;
if (!oldproc_open(info, 0))
return -1;
info->read_something = which ? readeither : readproc;
return 0;
} // end: procps_pids_read_open
PROCPS_EXPORT int procps_pids_read_shut (
struct procps_pidsinfo *info)
{
if (info == NULL || ! READS_BEGUN)
return -EINVAL;
oldproc_close(info);
return stacks_dealloc(info, &info->read);
} // end: procps_pids_read_shut
/* procps_pids_reap(): /* procps_pids_reap():
@ -1289,86 +1300,70 @@ PROCPS_EXPORT int procps_pids_read_shut (
* Harvest all the available tasks/threads and provide the result * Harvest all the available tasks/threads and provide the result
* stacks along with a summary of the information gathered. * stacks along with a summary of the information gathered.
* *
* Returns: pointer to a pids_reap struct on success, NULL on error. * Returns: pointer to a pids_fetch struct on success, NULL on error.
*/ */
PROCPS_EXPORT struct pids_reap *procps_pids_reap ( PROCPS_EXPORT struct pids_fetch *procps_pids_reap (
struct procps_pidsinfo *info, struct procps_pidsinfo *info,
enum pids_reap_type which) enum pids_fetch_type which)
{ {
int rc; int rc;
if (info == NULL || READS_BEGUN) if (info == NULL)
return NULL; return NULL;
if (!info->maxitems && !info->curitems) if (!info->curitems)
return NULL; return NULL;
if (which != PROCPS_REAP_TASKS_ONLY && which != PROCPS_REAP_THREADS_TOO) if (which != PROCPS_FETCH_TASKS_ONLY && which != PROCPS_FETCH_THREADS_TOO)
return NULL; return NULL;
if (!oldproc_open(info, 0)) if (!oldproc_open(&info->PT, info->oldflags))
return NULL; return NULL;
info->read_something = which ? readeither : readproc; info->read_something = which ? readeither : readproc;
rc = stacks_fetch(info, &info->reap); rc = stacks_fetch(info);
oldproc_close(info); oldproc_close(&info->PT);
// we better have found at least 1 pid // we better have found at least 1 pid
return (rc > 0) ? &info->reap.summary : NULL; return (rc > 0) ? &info->fetch.summary : NULL;
} // end: procps_pids_reap } // end: procps_pids_reap
PROCPS_EXPORT int procps_pids_ref (
struct procps_pidsinfo *info)
{
if (info == NULL)
return -EINVAL;
info->refcount++;
return info->refcount;
} // end: procps_pids_ref
PROCPS_EXPORT int procps_pids_reset ( PROCPS_EXPORT int procps_pids_reset (
struct procps_pidsinfo *info, struct procps_pidsinfo *info,
int newmaxitems, enum pids_item *newitems,
enum pids_item *newitems) int newnumitems)
{ {
struct stacks_extent *ext; if (info == NULL || newitems == NULL)
int i;
if (info == NULL)
return -EINVAL; return -EINVAL;
/* disallow (for now?) absolute increases in stacks size if (items_check_failed(newnumitems, newitems))
( users must 'unref' and then 'new' to achieve that ) */
if (newmaxitems + 1 > info->maxitems)
return -EINVAL;
if (items_check_failed(newmaxitems, newitems))
return -EINVAL; return -EINVAL;
/* shame on this caller, they didn't change anything. and unless they have /* shame on this caller, they didn't change anything. and unless they have
altered the depth of the stacks we're not gonna change anything either! */ altered the depth of the stacks we're not gonna change anything either! */
if (info->curitems == newmaxitems + 1 if (info->curitems == newnumitems + 1
&& !memcmp(info->items, newitems, sizeof(enum pids_item) * newmaxitems)) && !memcmp(info->items, newitems, sizeof(enum pids_item) * newnumitems))
return 0; return 0;
if (info->maxitems < newnumitems + 1) {
if (info->dirty_stacks)
cleanup_stacks_all(info);
// allow for our PROCPS_PIDS_logical_end
info->maxitems = newnumitems + 1;
if (!(info->items = realloc(info->items, sizeof(enum pids_item) * info->maxitems)))
return -ENOMEM;
extents_free_all(info);
}
if (info->dirty_stacks) if (info->dirty_stacks)
cleanup_stacks_all(info); cleanup_stacks_all(info);
memcpy(info->items, newitems, sizeof(enum pids_item) * newmaxitems); memcpy(info->items, newitems, sizeof(enum pids_item) * newnumitems);
info->items[newmaxitems] = PROCPS_PIDS_logical_end; info->items[newnumitems] = PROCPS_PIDS_logical_end;
// account for above PROCPS_PIDS_logical_end // account for above PROCPS_PIDS_logical_end
info->curitems = newmaxitems + 1; info->curitems = newnumitems + 1;
ext = info->extents;
while (ext) {
for (i = 0; ext->stacks[i]; i++)
itemize_stack(ext->stacks[i]->head, info->curitems, info->items);
#ifdef FPRINT_STACKS
fprint_stacks(ext, __func__);
#endif
ext = ext->next;
};
itemize_stacks_all(info);
libflags_set(info); libflags_set(info);
return 0; return 0;
} // end: procps_pids_reset } // end: procps_pids_reset
@ -1378,37 +1373,37 @@ PROCPS_EXPORT int procps_pids_reset (
* Harvest any processes matching the specified PID or UID and provide the * Harvest any processes matching the specified PID or UID and provide the
* result stacks along with a summary of the information gathered. * result stacks along with a summary of the information gathered.
* *
* Returns: pointer to a pids_reap struct on success, NULL on error. * Returns: pointer to a pids_fetch struct on success, NULL on error.
*/ */
PROCPS_EXPORT struct pids_reap *procps_pids_select ( PROCPS_EXPORT struct pids_fetch *procps_pids_select (
struct procps_pidsinfo *info, struct procps_pidsinfo *info,
unsigned *these, unsigned *these,
int maxthese, int numthese,
enum pids_select_type which) enum pids_select_type which)
{ {
unsigned ids[FILL_ID_MAX + 1]; unsigned ids[FILL_ID_MAX + 1];
int rc; int rc;
if (info == NULL || these == NULL || READS_BEGUN) if (info == NULL || these == NULL)
return NULL; return NULL;
if (maxthese < 1 || maxthese > FILL_ID_MAX) if (numthese < 1 || numthese > FILL_ID_MAX)
return NULL; return NULL;
if (which != PROCPS_SELECT_PID && which != PROCPS_SELECT_UID) if (which != PROCPS_SELECT_PID && which != PROCPS_SELECT_UID)
return NULL; return NULL;
// this zero delimiter is really only needed with PROCPS_SELECT_PID // this zero delimiter is really only needed with PROCPS_SELECT_PID
memcpy(ids, these, sizeof(unsigned) * maxthese); memcpy(ids, these, sizeof(unsigned) * numthese);
ids[maxthese] = 0; ids[numthese] = 0;
if (!oldproc_open(info, which, ids, maxthese)) if (!oldproc_open(&info->PT, (info->oldflags | which), ids, numthese))
return NULL; return NULL;
info->read_something = readproc; info->read_something = readproc;
rc = stacks_fetch(info, &info->select); rc = stacks_fetch(info);
oldproc_close(info); oldproc_close(&info->PT);
// no guarantee any pids/uids were found // no guarantee any pids/uids were found
return (rc > -1) ? &info->select.summary : NULL; return (rc > -1) ? &info->fetch.summary : NULL;
} // end: procps_pids_select } // end: procps_pids_select
@ -1426,7 +1421,7 @@ PROCPS_EXPORT struct pids_stack **procps_pids_sort (
struct procps_pidsinfo *info, struct procps_pidsinfo *info,
struct pids_stack *stacks[], struct pids_stack *stacks[],
int numstacked, int numstacked,
enum pids_item sort, enum pids_item sortitem,
enum pids_sort_order order) enum pids_sort_order order)
{ {
struct sort_parms parms; struct sort_parms parms;
@ -1436,7 +1431,7 @@ PROCPS_EXPORT struct pids_stack **procps_pids_sort (
if (info == NULL || stacks == NULL) if (info == NULL || stacks == NULL)
return NULL; return NULL;
// a pids_item is currently unsigned, but we'll protect our future // a pids_item is currently unsigned, but we'll protect our future
if (sort < 0 || sort >= PROCPS_PIDS_logical_end) if (sortitem < 0 || sortitem >= PROCPS_PIDS_logical_end)
return NULL; return NULL;
if (order != PROCPS_SORT_ASCEND && order != PROCPS_SORT_DESCEND) if (order != PROCPS_SORT_ASCEND && order != PROCPS_SORT_DESCEND)
return NULL; return NULL;
@ -1446,7 +1441,7 @@ PROCPS_EXPORT struct pids_stack **procps_pids_sort (
offset = 0; offset = 0;
p = stacks[0]->head; p = stacks[0]->head;
for (;;) { for (;;) {
if (p->item == sort) if (p->item == sortitem)
break; break;
++offset; ++offset;
if (offset >= info->curitems) if (offset >= info->curitems)
@ -1461,54 +1456,3 @@ PROCPS_EXPORT struct pids_stack **procps_pids_sort (
qsort_r(stacks, numstacked, sizeof(void *), (QSR_t)Item_table[p->item].sortfunc, &parms); qsort_r(stacks, numstacked, sizeof(void *), (QSR_t)Item_table[p->item].sortfunc, &parms);
return stacks; return stacks;
} // end: procps_pids_sort } // end: procps_pids_sort
PROCPS_EXPORT int procps_pids_unref (
struct procps_pidsinfo **info)
{
if (info == NULL || *info == NULL)
return -EINVAL;
(*info)->refcount--;
if ((*info)->refcount == 0) {
#ifdef UNREF_RPTHASH
unref_rpthash(*info);
#endif
if ((*info)->extents) {
cleanup_stacks_all(*info);
do {
struct stacks_extent *p = (*info)->extents;
(*info)->extents = (*info)->extents->next;
free(p);
} while ((*info)->extents);
}
if ((*info)->otherexts) {
struct stacks_extent *nextext, *ext = (*info)->otherexts;
while (ext) {
nextext = ext->next;
cleanup_stack(ext->stacks[0]->head, ext->ext_numitems);
free(ext);
ext = nextext;
};
}
if ((*info)->reap.anchor)
free((*info)->reap.anchor);
if ((*info)->reap.summary.stacks)
free((*info)->reap.summary.stacks);
if ((*info)->select.anchor)
free((*info)->select.anchor);
if ((*info)->select.summary.stacks)
free((*info)->select.summary.stacks);
if ((*info)->items)
free((*info)->items);
if ((*info)->hist) {
free((*info)->hist->PHist_sav);
free((*info)->hist->PHist_new);
free((*info)->hist);
}
free(*info);
*info = NULL;
return 0;
}
return (*info)->refcount;
} // end: procps_pids_unref

View File

@ -133,7 +133,6 @@ enum pids_item {
PROCPS_PIDS_VM_DATA, // ul_int PROCPS_PIDS_VM_DATA, // ul_int
PROCPS_PIDS_VM_EXE, // ul_int PROCPS_PIDS_VM_EXE, // ul_int
PROCPS_PIDS_VM_LIB, // ul_int PROCPS_PIDS_VM_LIB, // ul_int
PROCPS_PIDS_VM_LOCK, // ul_int
PROCPS_PIDS_VM_RSS, // ul_int PROCPS_PIDS_VM_RSS, // ul_int
PROCPS_PIDS_VM_RSS_ANON, // ul_int PROCPS_PIDS_VM_RSS_ANON, // ul_int
PROCPS_PIDS_VM_RSS_FILE, // ul_int PROCPS_PIDS_VM_RSS_FILE, // ul_int
@ -148,16 +147,16 @@ enum pids_item {
PROCPS_PIDS_WCHAN_NAME, // str PROCPS_PIDS_WCHAN_NAME, // str
}; };
enum pids_fetch_type {
PROCPS_FETCH_TASKS_ONLY,
PROCPS_FETCH_THREADS_TOO
};
enum pids_select_type { enum pids_select_type {
PROCPS_SELECT_PID = 0x1000, PROCPS_SELECT_PID = 0x1000,
PROCPS_SELECT_UID = 0x4000 PROCPS_SELECT_UID = 0x4000
}; };
enum pids_reap_type {
PROCPS_REAP_TASKS_ONLY = 0,
PROCPS_REAP_THREADS_TOO = 1
};
enum pids_sort_order { enum pids_sort_order {
PROCPS_SORT_ASCEND = +1, PROCPS_SORT_ASCEND = +1,
PROCPS_SORT_DESCEND = -1 PROCPS_SORT_DESCEND = -1
@ -189,7 +188,7 @@ struct pids_counts {
int running, sleeping, stopped, zombied; int running, sleeping, stopped, zombied;
}; };
struct pids_reap { struct pids_fetch {
struct pids_stack **stacks; struct pids_stack **stacks;
struct pids_counts counts; struct pids_counts counts;
}; };
@ -199,52 +198,40 @@ struct pids_reap {
stack -> head [ rel_enum ] . result . type stack -> head [ rel_enum ] . result . type
int procps_pids_new (struct procps_pidsinfo **info, enum pids_item *items, int numitems);
int procps_pids_ref (struct procps_pidsinfo *info);
int procps_pids_unref (struct procps_pidsinfo **info);
struct pids_stack *fatal_proc_unmounted ( struct pids_stack *fatal_proc_unmounted (
struct procps_pidsinfo *info, struct procps_pidsinfo *info,
int return_self); int return_self);
int procps_pids_new ( struct pids_stack *procps_pids_get (
struct procps_pidsinfo **info,
int maxitems,
enum pids_item *items);
struct pids_stack *procps_pids_read_next (
struct procps_pidsinfo *info);
int procps_pids_read_open (
struct procps_pidsinfo *info, struct procps_pidsinfo *info,
enum pids_reap_type which); enum pids_fetch_type which);
int procps_pids_read_shut ( struct pids_fetch *procps_pids_reap (
struct procps_pidsinfo *info);
struct pids_reap *procps_pids_reap (
struct procps_pidsinfo *info, struct procps_pidsinfo *info,
enum pids_reap_type which); enum pids_fetch_type which);
int procps_pids_ref (
struct procps_pidsinfo *info);
int procps_pids_reset ( int procps_pids_reset (
struct procps_pidsinfo *info, struct procps_pidsinfo *info,
int newmaxitems, enum pids_item *newitems,
enum pids_item *newitems); int newnumitems);
struct pids_reap *procps_pids_select ( struct pids_fetch *procps_pids_select (
struct procps_pidsinfo *info, struct procps_pidsinfo *info,
unsigned *these, unsigned *these,
int maxthese, int numthese,
enum pids_select_type which); enum pids_select_type which);
struct pids_stack **procps_pids_sort ( struct pids_stack **procps_pids_sort (
struct procps_pidsinfo *info, struct procps_pidsinfo *info,
struct pids_stack *stacks[], struct pids_stack *stacks[],
int numstacked, int numstacked,
enum pids_item sort, enum pids_item sortitem,
enum pids_sort_order order); enum pids_sort_order order);
int procps_pids_unref (
struct procps_pidsinfo **info);
__END_DECLS __END_DECLS