From 9ebadc1438a6665a98a9f0782523b0f9a2a6248f Mon Sep 17 00:00:00 2001 From: Jim Warner Date: Sat, 14 May 2016 00:00:00 -0500 Subject: [PATCH] library: standardize portions of interface, 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 --- proc/libprocps.sym | 8 +- proc/pids.c | 636 +++++++++++++++++++++------------------------ proc/pids.h | 51 ++-- 3 files changed, 312 insertions(+), 383 deletions(-) diff --git a/proc/libprocps.sym b/proc/libprocps.sym index 0b90bd3a..3542f810 100644 --- a/proc/libprocps.sym +++ b/proc/libprocps.sym @@ -25,15 +25,13 @@ global: procps_ns_read_pid; procps_pid_length; procps_pids_new; - procps_pids_read_next; - procps_pids_read_open; - procps_pids_read_shut; - procps_pids_reap; procps_pids_ref; + procps_pids_unref; + procps_pids_get; + procps_pids_reap; procps_pids_reset; procps_pids_select; procps_pids_sort; - procps_pids_unref; procps_slabinfo_new; procps_slabinfo_read; procps_slabinfo_ref; diff --git a/proc/pids.c b/proc/pids.c index b7a88ebf..68ecb2bf 100644 --- a/proc/pids.c +++ b/proc/pids.c @@ -45,16 +45,10 @@ #include "wchan.h" // ( maybe just temporary? ) //#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 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 // optimally if they are ever referenced more than once in any stack enum rel_ref { @@ -66,17 +60,16 @@ enum rel_ref { struct stacks_extent { struct pids_stack **stacks; - int ext_numitems; // includes 'logical_end' delimiter int ext_numstacks; struct stacks_extent *next; }; 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_inuse; // number of above pointers occupied 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 { @@ -86,19 +79,20 @@ struct procps_pidsinfo { enum pids_item *items; // includes 'logical_end' delimiter struct stacks_extent *extents; // anchor for all resettable extents struct stacks_extent *otherexts; // anchor for single stack invariant extents - struct fetch_support reap; // support for procps_pids_reap - struct fetch_support select; // support for procps_pids_select + struct fetch_support fetch; // support for procps_pids_reap & select int history_yes; // need historical data struct history_info *hist; // pointer to historical support data 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 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 unsigned long hertz; // for TIME_ALL & TIME_ELAPSED calculations unsigned long long boot_seconds; // for TIME_ELAPSED calculation 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_EXE, ul_int, vm_exe) 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_ANON, ul_int, vm_rss_anon) 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_EXE), 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_ANON), 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 } }; + // 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 FF #undef QS @@ -776,19 +771,17 @@ static inline void assign_results ( static inline void cleanup_stack ( - struct pids_result *p, - int depth) + struct pids_result *this) { - int i; - - for (i = 0; i < depth; i++) { - if (p->item >= PROCPS_PIDS_logical_end) + for (;;) { + enum pids_item item = this->item; + if (item >= PROCPS_PIDS_logical_end) break; - if (Item_table[p->item].freefunc) - Item_table[p->item].freefunc(p); - if (p->item > PROCPS_PIDS_noop) - p->result.ull_int = 0; - ++p; + if (Item_table[item].freefunc) + Item_table[item].freefunc(this); + if (item > PROCPS_PIDS_noop) + this->result.ull_int = 0; + ++this; } } // end: cleanup_stack @@ -801,7 +794,7 @@ static inline void cleanup_stacks_all ( while (ext) { for (i = 0; ext->stacks[i]; i++) - cleanup_stack(ext->stacks[i]->head, info->maxitems); + cleanup_stack(ext->stacks[i]->head); ext = ext->next; }; info->dirty_stacks = 0; @@ -835,52 +828,18 @@ static struct stacks_extent *extent_cut ( } // end: extent_cut -static int extent_free ( - struct procps_pidsinfo *info, - struct stacks_extent *ext) +static void extents_free_all ( + struct procps_pidsinfo *info) { - if (extent_cut(info, ext)) { - free(ext); - return 0; - } - return -1; -} // end: extent_free - + struct stacks_extent *ext = info->extents; -#ifdef FPRINT_STACKS -static void fprint_stacks ( - void *stacks, - const char *who) -{ - #include - 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 + while (ext) { + info->extents = ext->next; + free(ext); + ext = info->extents; + }; + info->dirty_stacks = 0; +} // end: extents_free_all static inline struct pids_result *itemize_stack ( @@ -900,8 +859,23 @@ static inline struct pids_result *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 ( - int maxitems, + int numitems, enum pids_item *items) { int i; @@ -914,10 +888,10 @@ static inline int items_check_failed ( * 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 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 if (items[i] < 0) return -1; @@ -936,37 +910,36 @@ static inline void libflags_set ( int i, n; 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++) { if (((e = info->items[i])) >= PROCPS_PIDS_logical_end) break; - info->flags |= Item_table[e].oldflags; + info->oldflags |= Item_table[e].oldflags; info->history_yes |= Item_table[e].needhist; n = Item_table[e].refcount; if (n > -1) ++info->ref_counts[n]; } - if (info->flags & f_either) { - if (!(info->flags & f_stat)) - info->flags |= f_status; + if (info->oldflags & f_either) { + if (!(info->oldflags & f_stat)) + info->oldflags |= f_status; } return; } // end: libflags_set static inline void oldproc_close ( - struct procps_pidsinfo *info) + PROCTAB **this) { - if (info->PT != NULL) { - closeproc(info->PT); - info->PT = NULL; + if (*this != NULL) { + closeproc(*this); + *this = NULL; } - return; } // end: oldproc_close static inline int oldproc_open ( - struct procps_pidsinfo *info, - unsigned supp_flgs, + PROCTAB **this, + unsigned flags, ...) { @@ -974,12 +947,12 @@ static inline int oldproc_open ( int *ids; int num = 0; - if (info->PT == NULL) { - va_start(vl, supp_flgs); + if (*this == NULL) { + va_start(vl, flags); 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); - if (NULL == (info->PT = openproc(info->flags | supp_flgs, ids, num))) + if (NULL == (*this = openproc(flags, ids, num))) return 0; } @@ -1044,27 +1017,27 @@ static struct stacks_extent *stacks_alloc ( if (maxstacks < 1) return NULL; - vect_size = sizeof(void *) * maxstacks; // address vectors themselves - vect_size += sizeof(void *); // plus NULL delimiter - head_size = sizeof(struct pids_stack); // a head struct - list_size = sizeof(struct pids_result) * info->maxitems; // a results stack - blob_size = sizeof(struct stacks_extent); // the extent anchor itself - blob_size += vect_size; // all vectors + delim - blob_size += head_size * maxstacks; // all head structs - blob_size += list_size * maxstacks; // all results stacks - - /* note: all memory is allocated in a single blob, facilitating a later free(). - as a minimum, it's important that the result structures themselves always be - contiguous for each stack since they're accessed through relative position). */ + vect_size = sizeof(void *) * maxstacks; // size of the addr vectors | + vect_size += sizeof(void *); // plus NULL addr delimiter | + head_size = sizeof(struct pids_stack); // size of that head struct | + list_size = sizeof(struct pids_result) * info->maxitems; // any single results stack | + blob_size = sizeof(struct stacks_extent); // the extent anchor itself | + blob_size += vect_size; // plus room for addr vects | + blob_size += head_size * maxstacks; // plus room for head thing | + blob_size += list_size * maxstacks; // plus room for our stacks | + + /* note: all of our memory is allocated in a single blob, facilitating a later free(). | + as a minimum, it is important that the result structures themselves always be | + contiguous for every stack since they are accessed through relative position. | */ if (NULL == (p_blob = calloc(1, blob_size))) return NULL; - p_blob->next = info->extents; - info->extents = p_blob; - p_blob->stacks = (void *)p_blob + sizeof(struct stacks_extent); - p_vect = p_blob->stacks; - v_head = (void *)p_vect + vect_size; - v_list = v_head + (head_size * maxstacks); + p_blob->next = info->extents; // push this extent onto... | + info->extents = p_blob; // ...some existing extents | + p_vect = (void *)p_blob + sizeof(struct stacks_extent); // prime our vector pointer | + p_blob->stacks = p_vect; // set actual vectors start | + v_head = (void *)p_vect + vect_size; // prime head pointer start | + v_list = v_head + (head_size * maxstacks); // prime our stacks pointer | for (i = 0; i < maxstacks; i++) { p_head = (struct pids_stack *)v_head; @@ -1073,114 +1046,70 @@ static struct stacks_extent *stacks_alloc ( v_list += list_size; v_head += head_size; } - p_blob->ext_numitems = info->maxitems; p_blob->ext_numstacks = maxstacks; -#ifdef FPRINT_STACKS - fprint_stacks(p_blob, __func__); -#endif return p_blob; } // 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 ( - struct procps_pidsinfo *info, - struct fetch_support *this) + struct procps_pidsinfo *info) { - #define n_alloc this->n_alloc - #define n_inuse this->n_inuse + #define n_alloc info->fetch.n_alloc + #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) struct stacks_extent *ext; - if (info == NULL || this == NULL) - return -1; - // initialize stuff ----------------------------------- - if (!this->anchor) { - if ((!(this->anchor = calloc(sizeof(void *), MEMORY_INCR))) - || (!(this->summary.stacks = calloc(sizeof(void *), MEMORY_INCR))) - || (!(ext = stacks_alloc(info, MEMORY_INCR)))) - return -1; - memcpy(this->anchor, ext->stacks, sizeof(void *) * MEMORY_INCR); + if (!info->fetch.anchor) { + if (!(info->fetch.anchor = calloc(sizeof(void *), MEMORY_INCR))) + return -ENOMEM; n_alloc = MEMORY_INCR; } - if (info->dirty_stacks) - cleanup_stacks_all(info); + if (!info->extents) { + 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); - memset(&this->summary.counts, 0, sizeof(struct pids_counts)); + memset(&info->fetch.summary.counts, 0, sizeof(struct pids_counts)); // iterate stuff -------------------------------------- n_inuse = 0; while (info->read_something(info->PT, &task)) { if (!(n_inuse < n_alloc)) { 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)))) 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; - assign_results(info, this->anchor[n_inuse++], &task); + assign_results(info, info->fetch.anchor[n_inuse++], &task); } // finalize stuff ------------------------------------- - if (this->n_alloc_save != n_alloc - && !(this->summary.stacks = realloc(this->summary.stacks, sizeof(void *) * n_alloc))) - return -1; - memcpy(this->summary.stacks, this->anchor, sizeof(void *) * n_alloc); - this->n_alloc_save = n_alloc; + if (n_saved < n_alloc + 1) { + n_saved = n_alloc + 1; + if (!(info->fetch.summary.stacks = realloc(info->fetch.summary.stacks, sizeof(void *) * n_saved))) + return -1; + } + 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 ! #undef n_alloc #undef n_inuse + #undef n_saved } // end: stacks_fetch // ___ Public Functions ||||||||||||||||||||||||||||||||||||||||||||||||||||||| -PROCPS_EXPORT struct pids_stack *fatal_proc_unmounted ( - struct procps_pidsinfo *info, - int return_self) -{ - static proc_t self; - struct stacks_extent *ext; - - // this is very likely the *only* newlib function where the - // context (procps_pidsinfo) of NULL will ever be permitted - look_up_our_self(&self); - if (!return_self) - return NULL; - - if (info == NULL - || !(ext = stacks_alloc(info, 1)) - || !extent_cut(info, ext)) - return NULL; - - ext->next = info->otherexts; - info->otherexts = ext; - assign_results(info, ext->stacks[0], &self); - - return ext->stacks[0]; -} // end: fatal_proc_unmounted - +// --- standard required functions -------------------------------------------- /* * procps_pids_new(): @@ -1191,8 +1120,8 @@ PROCPS_EXPORT struct pids_stack *fatal_proc_unmounted ( */ PROCPS_EXPORT int procps_pids_new ( struct procps_pidsinfo **info, - int maxitems, - enum pids_item *items) + enum pids_item *items, + int numitems) { struct procps_pidsinfo *p; double uptime_secs; @@ -1200,32 +1129,32 @@ PROCPS_EXPORT int procps_pids_new ( 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; + + /* 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); } - 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); + 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++; } - config_history(p); - p->hertz = procps_hertz_get(); procps_uptime(&uptime_secs, NULL); p->boot_seconds = uptime_secs; @@ -1236,52 +1165,134 @@ PROCPS_EXPORT int procps_pids_new ( } // end: procps_pids_new -PROCPS_EXPORT struct pids_stack *procps_pids_read_next ( +PROCPS_EXPORT int procps_pids_ref ( struct procps_pidsinfo *info) { - static proc_t task; // static for initial zeroes + later dynamic free(s) + if (info == NULL) + return -EINVAL; - if (info == NULL || ! READS_BEGUN) - return NULL; - if (info->dirty_stacks) { - cleanup_stack(info->read->stacks[0]->head, info->maxitems); - info->dirty_stacks = 0; + 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; } - if (NULL == info->read_something(info->PT, &task)) - return NULL; - assign_results(info, info->read->stacks[0], &task); - return info->read->stacks[0]; -} // end: procps_pids_read_next + return (*info)->refcount; +} // end: procps_pids_unref + +// --- variable interface functions ------------------------------------------- -PROCPS_EXPORT int procps_pids_read_open ( +PROCPS_EXPORT struct pids_stack *fatal_proc_unmounted ( struct procps_pidsinfo *info, - enum pids_reap_type which) + int return_self) { - 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; + static proc_t self; + struct stacks_extent *ext; - 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 + // this is very likely the *only* newlib function where the + // context (procps_pidsinfo) of NULL will ever be permitted + look_up_our_self(&self); + if (!return_self) + return NULL; + if (info == NULL + || !(ext = stacks_alloc(info, 1)) + || !extent_cut(info, ext)) + return NULL; -PROCPS_EXPORT int procps_pids_read_shut ( - struct procps_pidsinfo *info) + ext->next = info->otherexts; + info->otherexts = ext; + assign_results(info, ext->stacks[0], &self); + + return ext->stacks[0]; +} // end: fatal_proc_unmounted + + +PROCPS_EXPORT struct pids_stack *procps_pids_get ( + struct procps_pidsinfo *info, + enum pids_fetch_type which) { - if (info == NULL || ! READS_BEGUN) - return -EINVAL; - oldproc_close(info); - return stacks_dealloc(info, &info->read); -} // end: procps_pids_read_shut + static proc_t task; // static for initial zeroes + later dynamic free(s) + + if (info == NULL) + return NULL; + if (!info->curitems) + return NULL; + 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 (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; + assign_results(info, info->get_ext->stacks[0], &task); + + return info->get_ext->stacks[0]; +} // end: procps_pids_get /* procps_pids_reap(): @@ -1289,86 +1300,70 @@ PROCPS_EXPORT int procps_pids_read_shut ( * Harvest all the available tasks/threads and provide the 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_reap ( +PROCPS_EXPORT struct pids_fetch *procps_pids_reap ( struct procps_pidsinfo *info, - enum pids_reap_type which) + enum pids_fetch_type which) { int rc; - if (info == NULL || READS_BEGUN) + if (info == NULL) return NULL; - if (!info->maxitems && !info->curitems) + if (!info->curitems) 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; - if (!oldproc_open(info, 0)) + if (!oldproc_open(&info->PT, info->oldflags)) return NULL; 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 - return (rc > 0) ? &info->reap.summary : NULL; + return (rc > 0) ? &info->fetch.summary : NULL; } // 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 ( struct procps_pidsinfo *info, - int newmaxitems, - enum pids_item *newitems) + enum pids_item *newitems, + int newnumitems) { - struct stacks_extent *ext; - int i; - - if (info == NULL) - return -EINVAL; - /* disallow (for now?) absolute increases in stacks size - ( users must 'unref' and then 'new' to achieve that ) */ - if (newmaxitems + 1 > info->maxitems) + if (info == NULL || newitems == NULL) return -EINVAL; - if (items_check_failed(newmaxitems, newitems)) + if (items_check_failed(newnumitems, newitems)) return -EINVAL; /* 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! */ - if (info->curitems == newmaxitems + 1 - && !memcmp(info->items, newitems, sizeof(enum pids_item) * newmaxitems)) + if (info->curitems == newnumitems + 1 + && !memcmp(info->items, newitems, sizeof(enum pids_item) * newnumitems)) 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) cleanup_stacks_all(info); - memcpy(info->items, newitems, sizeof(enum pids_item) * newmaxitems); - info->items[newmaxitems] = PROCPS_PIDS_logical_end; + memcpy(info->items, newitems, sizeof(enum pids_item) * newnumitems); + info->items[newnumitems] = PROCPS_PIDS_logical_end; // account for above PROCPS_PIDS_logical_end - info->curitems = newmaxitems + 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; - }; + info->curitems = newnumitems + 1; + itemize_stacks_all(info); libflags_set(info); + return 0; } // 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 * 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, unsigned *these, - int maxthese, + int numthese, enum pids_select_type which) { unsigned ids[FILL_ID_MAX + 1]; int rc; - if (info == NULL || these == NULL || READS_BEGUN) + if (info == NULL || these == NULL) return NULL; - if (maxthese < 1 || maxthese > FILL_ID_MAX) + if (numthese < 1 || numthese > FILL_ID_MAX) return NULL; if (which != PROCPS_SELECT_PID && which != PROCPS_SELECT_UID) return NULL; // this zero delimiter is really only needed with PROCPS_SELECT_PID - memcpy(ids, these, sizeof(unsigned) * maxthese); - ids[maxthese] = 0; + memcpy(ids, these, sizeof(unsigned) * numthese); + ids[numthese] = 0; - if (!oldproc_open(info, which, ids, maxthese)) + if (!oldproc_open(&info->PT, (info->oldflags | which), ids, numthese)) return NULL; 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 - return (rc > -1) ? &info->select.summary : NULL; + return (rc > -1) ? &info->fetch.summary : NULL; } // end: procps_pids_select @@ -1426,7 +1421,7 @@ PROCPS_EXPORT struct pids_stack **procps_pids_sort ( struct procps_pidsinfo *info, struct pids_stack *stacks[], int numstacked, - enum pids_item sort, + enum pids_item sortitem, enum pids_sort_order order) { struct sort_parms parms; @@ -1436,7 +1431,7 @@ PROCPS_EXPORT struct pids_stack **procps_pids_sort ( if (info == NULL || stacks == NULL) return NULL; // 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; if (order != PROCPS_SORT_ASCEND && order != PROCPS_SORT_DESCEND) return NULL; @@ -1446,7 +1441,7 @@ PROCPS_EXPORT struct pids_stack **procps_pids_sort ( offset = 0; p = stacks[0]->head; for (;;) { - if (p->item == sort) + if (p->item == sortitem) break; ++offset; 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); return stacks; } // 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 diff --git a/proc/pids.h b/proc/pids.h index 9ebaf00d..e057bcfa 100644 --- a/proc/pids.h +++ b/proc/pids.h @@ -133,7 +133,6 @@ enum pids_item { PROCPS_PIDS_VM_DATA, // ul_int PROCPS_PIDS_VM_EXE, // ul_int PROCPS_PIDS_VM_LIB, // ul_int - PROCPS_PIDS_VM_LOCK, // ul_int PROCPS_PIDS_VM_RSS, // ul_int PROCPS_PIDS_VM_RSS_ANON, // ul_int PROCPS_PIDS_VM_RSS_FILE, // ul_int @@ -148,16 +147,16 @@ enum pids_item { PROCPS_PIDS_WCHAN_NAME, // str }; +enum pids_fetch_type { + PROCPS_FETCH_TASKS_ONLY, + PROCPS_FETCH_THREADS_TOO +}; + enum pids_select_type { PROCPS_SELECT_PID = 0x1000, PROCPS_SELECT_UID = 0x4000 }; -enum pids_reap_type { - PROCPS_REAP_TASKS_ONLY = 0, - PROCPS_REAP_THREADS_TOO = 1 -}; - enum pids_sort_order { PROCPS_SORT_ASCEND = +1, PROCPS_SORT_DESCEND = -1 @@ -189,7 +188,7 @@ struct pids_counts { int running, sleeping, stopped, zombied; }; -struct pids_reap { +struct pids_fetch { struct pids_stack **stacks; struct pids_counts counts; }; @@ -199,52 +198,40 @@ struct pids_reap { 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 procps_pidsinfo *info, int return_self); -int procps_pids_new ( - 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 pids_stack *procps_pids_get ( struct procps_pidsinfo *info, - enum pids_reap_type which); + enum pids_fetch_type which); -int procps_pids_read_shut ( - struct procps_pidsinfo *info); - -struct pids_reap *procps_pids_reap ( +struct pids_fetch *procps_pids_reap ( struct procps_pidsinfo *info, - enum pids_reap_type which); - -int procps_pids_ref ( - struct procps_pidsinfo *info); + enum pids_fetch_type which); int procps_pids_reset ( 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, unsigned *these, - int maxthese, + int numthese, enum pids_select_type which); struct pids_stack **procps_pids_sort ( struct procps_pidsinfo *info, struct pids_stack *stacks[], int numstacked, - enum pids_item sort, + enum pids_item sortitem, enum pids_sort_order order); -int procps_pids_unref ( - struct procps_pidsinfo **info); __END_DECLS -- 2.40.0