library: refactor meminfo providing dynamic allocation
An earlier approach to meminfo chaining, referenced in
the patch shown below, represents the first baby steps
toward the goal of some generalized approach with PIDs
processing. However, statically allocating a chain for
each task or thread is totally impractical. And, while
a single chain could serve all PIDs, that would mean a
separate call to our library for each running process.
This commit is intended as the next evolutionary step,
dynamically allocating some 'result' chains to contain
as many or as few 'items' as a caller wishes. In other
words, holding only those 'items' of current interest.
This is the kind of service useful for both top and ps
programs if we finally get around to /proc/<PID> data.
Reference(s):
commit c3fd7473c5
Signed-off-by: Jim Warner <james.warner@comcast.net>
This commit is contained in:
parent
cf6c2155dc
commit
aab537bc13
@ -39,7 +39,9 @@ global:
|
|||||||
procps_meminfo_ref;
|
procps_meminfo_ref;
|
||||||
procps_meminfo_unref;
|
procps_meminfo_unref;
|
||||||
procps_meminfo_get;
|
procps_meminfo_get;
|
||||||
procps_meminfo_get_chain;
|
procps_meminfo_getchain;
|
||||||
|
procps_meminfo_chain_fill;
|
||||||
|
procps_meminfo_chain_alloc;
|
||||||
procps_slabinfo_new;
|
procps_slabinfo_new;
|
||||||
procps_slabinfo_read;
|
procps_slabinfo_read;
|
||||||
procps_slabinfo_ref;
|
procps_slabinfo_ref;
|
||||||
|
247
proc/meminfo.c
247
proc/meminfo.c
@ -56,11 +56,25 @@ struct procps_meminfo {
|
|||||||
int refcount;
|
int refcount;
|
||||||
int meminfo_fd;
|
int meminfo_fd;
|
||||||
struct meminfo_data data;
|
struct meminfo_data data;
|
||||||
|
struct chains_anchor *chained;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct chain_vectors {
|
||||||
|
struct chains_anchor *owner;
|
||||||
|
struct meminfo_chain **heads;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct chains_anchor {
|
||||||
|
int depth;
|
||||||
|
int header_size;
|
||||||
|
struct chain_vectors *vectors;
|
||||||
|
struct chains_anchor *self;
|
||||||
|
struct chains_anchor *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* procps_meminfo_new:
|
* procps_meminfo_new():
|
||||||
*
|
*
|
||||||
* Create a new container to hold the meminfo information
|
* Create a new container to hold the meminfo information
|
||||||
*
|
*
|
||||||
@ -84,7 +98,7 @@ PROCPS_EXPORT int procps_meminfo_new (
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* procps_meminfo_read:
|
* procps_meminfo_read():
|
||||||
*
|
*
|
||||||
* Read the data out of /proc/meminfo putting the information
|
* Read the data out of /proc/meminfo putting the information
|
||||||
* into the supplied info structure
|
* into the supplied info structure
|
||||||
@ -213,7 +227,6 @@ PROCPS_EXPORT int procps_meminfo_read (
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PROCPS_EXPORT int procps_meminfo_ref (
|
PROCPS_EXPORT int procps_meminfo_ref (
|
||||||
struct procps_meminfo *info)
|
struct procps_meminfo *info)
|
||||||
{
|
{
|
||||||
@ -230,6 +243,13 @@ PROCPS_EXPORT int procps_meminfo_unref (
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
(*info)->refcount--;
|
(*info)->refcount--;
|
||||||
if ((*info)->refcount == 0) {
|
if ((*info)->refcount == 0) {
|
||||||
|
if ((*info)->chained) {
|
||||||
|
do {
|
||||||
|
struct chains_anchor *p = (*info)->chained;
|
||||||
|
(*info)->chained = (*info)->chained->next;
|
||||||
|
free(p);
|
||||||
|
} while((*info)->chained);
|
||||||
|
}
|
||||||
free(*info);
|
free(*info);
|
||||||
*info = NULL;
|
*info = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
@ -237,7 +257,9 @@ PROCPS_EXPORT int procps_meminfo_unref (
|
|||||||
return (*info)->refcount;
|
return (*info)->refcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Accessor functions */
|
/*
|
||||||
|
* Accessor functions
|
||||||
|
*/
|
||||||
PROCPS_EXPORT unsigned long procps_meminfo_get (
|
PROCPS_EXPORT unsigned long procps_meminfo_get (
|
||||||
struct procps_meminfo *info,
|
struct procps_meminfo *info,
|
||||||
enum meminfo_item item)
|
enum meminfo_item item)
|
||||||
@ -285,88 +307,249 @@ PROCPS_EXPORT unsigned long procps_meminfo_get (
|
|||||||
if (info->data.swap_free > info->data.swap_total)
|
if (info->data.swap_free > info->data.swap_total)
|
||||||
return 0;
|
return 0;
|
||||||
return info->data.swap_total - info->data.swap_free;
|
return info->data.swap_total - info->data.swap_free;
|
||||||
|
case PROCPS_MEM_noop:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PROCPS_EXPORT int procps_meminfo_get_chain (
|
PROCPS_EXPORT int procps_meminfo_getchain (
|
||||||
struct procps_meminfo *info,
|
struct procps_meminfo *info,
|
||||||
struct meminfo_result *item)
|
struct meminfo_result *these)
|
||||||
{
|
{
|
||||||
|
if (info == NULL || these == NULL)
|
||||||
if (item == NULL)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
switch (item->item) {
|
switch (these->item) {
|
||||||
case PROCPS_MEM_ACTIVE:
|
case PROCPS_MEM_ACTIVE:
|
||||||
item->result = info->data.active;
|
these->result = info->data.active;
|
||||||
break;
|
break;
|
||||||
case PROCPS_MEM_INACTIVE:
|
case PROCPS_MEM_INACTIVE:
|
||||||
item->result = info->data.inactive;
|
these->result = info->data.inactive;
|
||||||
break;
|
break;
|
||||||
case PROCPS_MEMHI_FREE:
|
case PROCPS_MEMHI_FREE:
|
||||||
item->result = info->data.high_free;
|
these->result = info->data.high_free;
|
||||||
break;
|
break;
|
||||||
case PROCPS_MEMHI_TOTAL:
|
case PROCPS_MEMHI_TOTAL:
|
||||||
item->result = info->data.high_total;
|
these->result = info->data.high_total;
|
||||||
break;
|
break;
|
||||||
case PROCPS_MEMHI_USED:
|
case PROCPS_MEMHI_USED:
|
||||||
if (info->data.high_free > info->data.high_total)
|
if (info->data.high_free > info->data.high_total)
|
||||||
item->result = 0;
|
these->result = 0;
|
||||||
else
|
else
|
||||||
item->result = info->data.high_total - info->data.high_free;
|
these->result = info->data.high_total - info->data.high_free;
|
||||||
break;
|
break;
|
||||||
case PROCPS_MEMLO_FREE:
|
case PROCPS_MEMLO_FREE:
|
||||||
item->result = info->data.low_free;
|
these->result = info->data.low_free;
|
||||||
break;
|
break;
|
||||||
case PROCPS_MEMLO_TOTAL:
|
case PROCPS_MEMLO_TOTAL:
|
||||||
item->result = info->data.low_total;
|
these->result = info->data.low_total;
|
||||||
break;
|
break;
|
||||||
case PROCPS_MEMLO_USED:
|
case PROCPS_MEMLO_USED:
|
||||||
if (info->data.low_free > info->data.low_total)
|
if (info->data.low_free > info->data.low_total)
|
||||||
item->result = 0;
|
these->result = 0;
|
||||||
else
|
else
|
||||||
item->result = info->data.low_total - info->data.low_free;
|
these->result = info->data.low_total - info->data.low_free;
|
||||||
break;
|
break;
|
||||||
case PROCPS_MEM_AVAILABLE:
|
case PROCPS_MEM_AVAILABLE:
|
||||||
item->result = info->data.available;
|
these->result = info->data.available;
|
||||||
break;
|
break;
|
||||||
case PROCPS_MEM_BUFFERS:
|
case PROCPS_MEM_BUFFERS:
|
||||||
item->result = info->data.buffers;
|
these->result = info->data.buffers;
|
||||||
break;
|
break;
|
||||||
case PROCPS_MEM_CACHED:
|
case PROCPS_MEM_CACHED:
|
||||||
item->result = info->data.cached;
|
these->result = info->data.cached;
|
||||||
break;
|
break;
|
||||||
case PROCPS_MEM_FREE:
|
case PROCPS_MEM_FREE:
|
||||||
item->result = info->data.free;
|
these->result = info->data.free;
|
||||||
break;
|
break;
|
||||||
case PROCPS_MEM_SHARED:
|
case PROCPS_MEM_SHARED:
|
||||||
item->result = info->data.shared;
|
these->result = info->data.shared;
|
||||||
break;
|
break;
|
||||||
case PROCPS_MEM_TOTAL:
|
case PROCPS_MEM_TOTAL:
|
||||||
item->result = info->data.total;
|
these->result = info->data.total;
|
||||||
break;
|
break;
|
||||||
case PROCPS_MEM_USED:
|
case PROCPS_MEM_USED:
|
||||||
item->result = info->data.used;
|
these->result = info->data.used;
|
||||||
break;
|
break;
|
||||||
case PROCPS_SWAP_FREE:
|
case PROCPS_SWAP_FREE:
|
||||||
item->result = info->data.swap_free;
|
these->result = info->data.swap_free;
|
||||||
break;
|
break;
|
||||||
case PROCPS_SWAP_TOTAL:
|
case PROCPS_SWAP_TOTAL:
|
||||||
item->result = info->data.swap_total;
|
these->result = info->data.swap_total;
|
||||||
break;
|
break;
|
||||||
case PROCPS_SWAP_USED:
|
case PROCPS_SWAP_USED:
|
||||||
if (info->data.swap_free > info->data.swap_total)
|
if (info->data.swap_free > info->data.swap_total)
|
||||||
item->result = 0;
|
these->result = 0;
|
||||||
else
|
else
|
||||||
item->result = info->data.swap_total - info->data.swap_free;
|
these->result = info->data.swap_total - info->data.swap_free;
|
||||||
|
break;
|
||||||
|
case PROCPS_MEM_noop:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
item = item->next;
|
these = these->next;
|
||||||
} while (item);
|
} while (these);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PROCPS_EXPORT int procps_meminfo_chain_fill (
|
||||||
|
struct procps_meminfo *info,
|
||||||
|
struct meminfo_chain *chain)
|
||||||
|
{
|
||||||
|
struct meminfo_result *these = chain->head;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (info == NULL || chain == NULL || these == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if ((rc == procps_meminfo_read(info)) < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return procps_meminfo_getchain(info, these);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void chains_validate (struct meminfo_chain **v, const char *who)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
#include <stdio.h>
|
||||||
|
int i, x, n = 0;
|
||||||
|
struct chain_vectors *p = (struct chain_vectors *)v - 1;
|
||||||
|
|
||||||
|
fprintf(stderr, "%s: called by '%s'\n", __func__, who);
|
||||||
|
fprintf(stderr, "%s: owned by %p (whose self = %p)\n", __func__, p->owner, p->owner->self);
|
||||||
|
for (x = 0; v[x]; x++) {
|
||||||
|
struct meminfo_chain *h = v[x];
|
||||||
|
struct meminfo_result *r = h->head;
|
||||||
|
fprintf(stderr, "%s: vector[%02d] = %p", __func__, x, h);
|
||||||
|
i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
r = r->next;
|
||||||
|
} while (r);
|
||||||
|
fprintf(stderr, ", chain %d found %d elements\n", n, i);
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "%s: found %d chain(s)\n", __func__, x);
|
||||||
|
fprintf(stderr, "%s: this header size = %2d\n", __func__, (int)p->owner->header_size);
|
||||||
|
fprintf(stderr, "%s: sizeof(struct meminfo_chain) = %2d\n", __func__, (int)sizeof(struct meminfo_chain));
|
||||||
|
fprintf(stderr, "%s: sizeof(struct meminfo_result) = %2d\n", __func__, (int)sizeof(struct meminfo_result));
|
||||||
|
fputc('\n', stderr);
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct meminfo_result *chain_make (
|
||||||
|
struct meminfo_result *p,
|
||||||
|
int maxitems,
|
||||||
|
enum meminfo_item *items)
|
||||||
|
{
|
||||||
|
struct meminfo_result *p_sav = p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < maxitems; i++) {
|
||||||
|
if (i > PROCPS_MEM_noop)
|
||||||
|
p->item = PROCPS_MEM_noop;
|
||||||
|
else
|
||||||
|
p->item = items[i];
|
||||||
|
p->result = 0;
|
||||||
|
p->next = p + 1;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
(--p)->next = NULL;
|
||||||
|
|
||||||
|
return p_sav;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* procps_meminfo_chains_alloc():
|
||||||
|
*
|
||||||
|
* A local copy of code borrowed from slab.c to support the public version
|
||||||
|
* representing a single chain. Currently there is no conceivable need
|
||||||
|
* for multiple chains in the 'memory' arena.
|
||||||
|
*/
|
||||||
|
static struct meminfo_chain **procps_meminfo_chains_alloc (
|
||||||
|
struct procps_meminfo *info,
|
||||||
|
int maxchains,
|
||||||
|
int chain_extra,
|
||||||
|
int maxitems,
|
||||||
|
enum meminfo_item *items)
|
||||||
|
{
|
||||||
|
struct chains_anchor *p_blob;
|
||||||
|
struct chain_vectors *p_vect;
|
||||||
|
struct meminfo_chain *p_head;
|
||||||
|
size_t vect_size, head_size, list_size, blob_size;
|
||||||
|
void *v_head, *v_list;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (info == NULL || items == NULL)
|
||||||
|
return NULL;
|
||||||
|
if (maxchains < 1 || maxitems < 1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
vect_size = sizeof(struct chain_vectors); // address vector struct
|
||||||
|
vect_size += sizeof(void *) * maxchains; // plus vectors themselves
|
||||||
|
vect_size += sizeof(void *); // plus NULL delimiter
|
||||||
|
head_size = sizeof(struct meminfo_chain) + chain_extra; // a head struct + user stuff
|
||||||
|
list_size = sizeof(struct meminfo_result) * maxitems; // a results chain
|
||||||
|
blob_size = sizeof(struct chains_anchor); // the anchor itself
|
||||||
|
blob_size += vect_size; // all vectors + delims
|
||||||
|
blob_size += head_size * maxchains; // all head structs + user stuff
|
||||||
|
blob_size += list_size * maxchains; // all results chains
|
||||||
|
|
||||||
|
/* 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 any given chain (just as they are when defined statically). */
|
||||||
|
if (NULL == (p_blob = calloc(1, blob_size)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
p_blob->next = info->chained;
|
||||||
|
info->chained = p_blob;
|
||||||
|
p_blob->self = p_blob;
|
||||||
|
p_blob->header_size = head_size;
|
||||||
|
p_blob->vectors = (void *)p_blob + sizeof(struct chains_anchor);
|
||||||
|
p_vect = p_blob->vectors;
|
||||||
|
p_vect->owner = p_blob->self;
|
||||||
|
p_vect->heads = (void *)p_vect + sizeof(struct chain_vectors);
|
||||||
|
v_head = (void *)p_vect + vect_size;
|
||||||
|
v_list = v_head + (head_size * maxchains);
|
||||||
|
|
||||||
|
for (i = 0; i < maxchains; i++) {
|
||||||
|
p_head = (struct meminfo_chain *)v_head;
|
||||||
|
p_head->head = chain_make((struct meminfo_result *)v_list, maxitems, items);
|
||||||
|
p_blob->vectors->heads[i] = p_head;
|
||||||
|
v_list += list_size;
|
||||||
|
v_head += head_size;
|
||||||
|
}
|
||||||
|
p_blob->depth = maxchains;
|
||||||
|
chains_validate(p_blob->vectors->heads, __func__);
|
||||||
|
return p_blob->vectors->heads;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* procps_meminfo_chain_alloc():
|
||||||
|
*
|
||||||
|
* Allocate and initialize a single result chain under a simplified interface.
|
||||||
|
*
|
||||||
|
* Such a chain will will have its result structures properly primed with
|
||||||
|
* 'items' and 'next' pointers, while the result itself is set to zero.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
PROCPS_EXPORT struct meminfo_chain *procps_meminfo_chain_alloc (
|
||||||
|
struct procps_meminfo *info,
|
||||||
|
int maxitems,
|
||||||
|
enum meminfo_item *items)
|
||||||
|
{
|
||||||
|
struct meminfo_chain **v;
|
||||||
|
|
||||||
|
if (info == NULL || items == NULL || maxitems < 1)
|
||||||
|
return NULL;
|
||||||
|
v = procps_meminfo_chains_alloc(info, 1, 0, maxitems, items);
|
||||||
|
if (!v)
|
||||||
|
return NULL;
|
||||||
|
chains_validate(v, __func__);
|
||||||
|
return v[0];
|
||||||
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef PROC_MEMINFO_H
|
#ifndef PROC_MEMINFO_H
|
||||||
#define PROC_MEMINFO_H
|
#define PROC_MEMINFO_H
|
||||||
|
|
||||||
@ -44,16 +45,22 @@ enum meminfo_item {
|
|||||||
PROCPS_MEM_USED,
|
PROCPS_MEM_USED,
|
||||||
PROCPS_SWAP_FREE,
|
PROCPS_SWAP_FREE,
|
||||||
PROCPS_SWAP_TOTAL,
|
PROCPS_SWAP_TOTAL,
|
||||||
PROCPS_SWAP_USED
|
PROCPS_SWAP_USED,
|
||||||
|
PROCPS_MEM_noop
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct procps_meminfo;
|
||||||
|
|
||||||
struct meminfo_result {
|
struct meminfo_result {
|
||||||
enum meminfo_item item;
|
enum meminfo_item item;
|
||||||
unsigned long result;
|
unsigned long result;
|
||||||
struct meminfo_result *next;
|
struct meminfo_result *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct procps_meminfo;
|
struct meminfo_chain {
|
||||||
|
struct meminfo_result *head;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
int procps_meminfo_new (struct procps_meminfo **info);
|
int procps_meminfo_new (struct procps_meminfo **info);
|
||||||
int procps_meminfo_read (struct procps_meminfo *info);
|
int procps_meminfo_read (struct procps_meminfo *info);
|
||||||
@ -61,9 +68,22 @@ int procps_meminfo_read (struct procps_meminfo *info);
|
|||||||
int procps_meminfo_ref (struct procps_meminfo *info);
|
int procps_meminfo_ref (struct procps_meminfo *info);
|
||||||
int procps_meminfo_unref (struct procps_meminfo **info);
|
int procps_meminfo_unref (struct procps_meminfo **info);
|
||||||
|
|
||||||
unsigned long procps_meminfo_get (struct procps_meminfo *info, enum meminfo_item item);
|
unsigned long procps_meminfo_get (
|
||||||
int procps_meminfo_get_chain (struct procps_meminfo *info, struct meminfo_result *item);
|
struct procps_meminfo *info,
|
||||||
|
enum meminfo_item item);
|
||||||
|
|
||||||
|
int procps_meminfo_getchain (
|
||||||
|
struct procps_meminfo *info,
|
||||||
|
struct meminfo_result *these);
|
||||||
|
|
||||||
|
int procps_meminfo_chain_fill (
|
||||||
|
struct procps_meminfo *info,
|
||||||
|
struct meminfo_chain *chain);
|
||||||
|
|
||||||
|
struct meminfo_chain *procps_meminfo_chain_alloc (
|
||||||
|
struct procps_meminfo *info,
|
||||||
|
int maxitems,
|
||||||
|
enum meminfo_item *items);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user