summaryrefslogtreecommitdiffstats
path: root/lib/libmemstat
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2005-07-24 01:28:54 +0000
committerrwatson <rwatson@FreeBSD.org>2005-07-24 01:28:54 +0000
commited2ee35685ba75f493721481c35783064c1409b8 (patch)
tree63da65af38beadf1e51e092e8598077127c700a0 /lib/libmemstat
parentad981ed9a46b2937073d58aace0368983e84efed (diff)
downloadFreeBSD-src-ed2ee35685ba75f493721481c35783064c1409b8.zip
FreeBSD-src-ed2ee35685ba75f493721481c35783064c1409b8.tar.gz
Introduce more formal error handling for libmemstat(3):
- Define a set of libmemstat(3) error constants, which are used by all libmemstat(3) methods except for memstat_mtl_alloc(), which allocates a memory type list and may return ENOMEM via errno. - Define a per-memory_type_list current error value, which is set when a call associated with a memory list fails. This requires wrapping a structure around the queue(9) list head data structure, but this change is not visible to libmemstat(3) consumers due to using access methods. - Add a new accessor method, memstat_mtl_geterror() to retrieve the error number. - Consistently set the error number in a number of failure modes where previously some combination of setting errno and printf'ing error descriptions was used. libmemstat(3) will now no longer print to stdio under any circumstances. Returns of NULL/-1 for errors remain the same. This avoids use of stdio, misuse of error numbers, and should make it easier to program a libmemstat(3) consumer able to print useful error messages. Currently, no error-to-string function is provided, as I'm unsure how to address internationalization concerns. MFC after: 1 day
Diffstat (limited to 'lib/libmemstat')
-rw-r--r--lib/libmemstat/memstat.c21
-rw-r--r--lib/libmemstat/memstat.h16
-rw-r--r--lib/libmemstat/memstat_internal.h5
-rw-r--r--lib/libmemstat/memstat_malloc.c51
-rw-r--r--lib/libmemstat/memstat_uma.c51
5 files changed, 78 insertions, 66 deletions
diff --git a/lib/libmemstat/memstat.c b/lib/libmemstat/memstat.c
index 29dd19e..f053e95 100644
--- a/lib/libmemstat/memstat.c
+++ b/lib/libmemstat/memstat.c
@@ -47,7 +47,8 @@ memstat_mtl_alloc(void)
if (mtlp == NULL)
return (NULL);
- LIST_INIT(mtlp);
+ LIST_INIT(&mtlp->mtl_list);
+ mtlp->mtl_error = MEMSTAT_ERROR_UNDEFINED;
return (mtlp);
}
@@ -55,7 +56,7 @@ struct memory_type *
memstat_mtl_first(struct memory_type_list *list)
{
- return (LIST_FIRST(list));
+ return (LIST_FIRST(&list->mtl_list));
}
struct memory_type *
@@ -70,16 +71,24 @@ memstat_mtl_free(struct memory_type_list *list)
{
struct memory_type *mtp;
- while ((mtp = LIST_FIRST(list))) {
+ while ((mtp = LIST_FIRST(&list->mtl_list))) {
LIST_REMOVE(mtp, mt_list);
free(mtp);
}
free(list);
}
+int
+memstat_mtl_geterror(struct memory_type_list *list)
+{
+
+ return (list->mtl_error);
+}
+
/*
* Look for an existing memory_type entry in a memory_type list, based on the
- * allocator and name of the type. If not found, return NULL. O(n).
+ * allocator and name of the type. If not found, return NULL. No errno or
+ * memstat error.
*/
struct memory_type *
memstat_mtl_find(struct memory_type_list *list, int allocator,
@@ -87,7 +96,7 @@ memstat_mtl_find(struct memory_type_list *list, int allocator,
{
struct memory_type *mtp;
- LIST_FOREACH(mtp, list, mt_list) {
+ LIST_FOREACH(mtp, &list->mtl_list, mt_list) {
if ((mtp->mt_allocator == allocator ||
allocator == ALLOCATOR_ANY) &&
strcmp(mtp->mt_name, name) == 0)
@@ -116,7 +125,7 @@ _memstat_mt_allocate(struct memory_type_list *list, int allocator,
mtp->mt_allocator = allocator;
strlcpy(mtp->mt_name, name, MEMTYPE_MAXNAME);
- LIST_INSERT_HEAD(list, mtp, mt_list);
+ LIST_INSERT_HEAD(&list->mtl_list, mtp, mt_list);
return (mtp);
}
diff --git a/lib/libmemstat/memstat.h b/lib/libmemstat/memstat.h
index 823338b..c2e3174 100644
--- a/lib/libmemstat/memstat.h
+++ b/lib/libmemstat/memstat.h
@@ -61,6 +61,19 @@
#define MEMTYPE_MAXNAME 32
/*
+ * Library error conditions, mostly from the underlying data sources. On
+ * failure, functions typically return (-1) or (NULL); on success, (0) or a
+ * valid data pointer. The error from the last operation is stored in
+ * struct memory_type, and accessed via memstat_get_error(mtp).
+ */
+#define MEMSTAT_ERROR_UNDEFINED 0 /* Initialization value. */
+#define MEMSTAT_ERROR_NOMEMORY 1 /* Out of memory. */
+#define MEMSTAT_ERROR_VERSION 2 /* Unsupported version. */
+#define MEMSTAT_ERROR_PERMISSION 3 /* Permission denied. */
+#define MEMSTAT_ERROR_TOOMANYCPUS 4 /* Too many CPUs. */
+#define MEMSTAT_ERROR_DATAERROR 5 /* Error in stat data. */
+
+/*
* Forward declare struct memory_type, which holds per-type properties and
* statistics. This is an opaque type, to be frobbed only from within the
* library, in order to avoid building ABI assumptions into the application.
@@ -85,6 +98,7 @@ struct memory_type *memstat_mtl_next(struct memory_type *mtp);
struct memory_type *memstat_mtl_find(struct memory_type_list *list,
int allocator, const char *name);
void memstat_mtl_free(struct memory_type_list *list);
+int memstat_mtl_geterror(struct memory_type_list *list);
/*
* Functions to retrieve data from a live kernel using sysctl.
@@ -94,7 +108,7 @@ int memstat_sysctl_malloc(struct memory_type_list *list, int flags);
int memstat_sysctl_uma(struct memory_type_list *list, int flags);
/*
- * Accessor methods for struct memory_type_list.
+ * Accessor methods for struct memory_type.
*/
const char *memstat_get_name(const struct memory_type *mtp);
int memstat_get_allocator(const struct memory_type *mtp);
diff --git a/lib/libmemstat/memstat_internal.h b/lib/libmemstat/memstat_internal.h
index edbf562..838eaa6 100644
--- a/lib/libmemstat/memstat_internal.h
+++ b/lib/libmemstat/memstat_internal.h
@@ -111,7 +111,10 @@ struct memory_type {
/*
* Description of struct memory_type_list is in memstat.h.
*/
-LIST_HEAD(memory_type_list, memory_type);
+struct memory_type_list {
+ LIST_HEAD(, memory_type) mtl_list;
+ int mtl_error;
+};
struct memory_type *_memstat_mt_allocate(struct memory_type_list *list,
int allocator, const char *name);
diff --git a/lib/libmemstat/memstat_malloc.c b/lib/libmemstat/memstat_malloc.c
index 3aed1cf..4170812 100644
--- a/lib/libmemstat/memstat_malloc.c
+++ b/lib/libmemstat/memstat_malloc.c
@@ -58,11 +58,11 @@ memstat_sysctl_malloc(struct memory_type_list *list, int flags)
struct malloc_type_header *mthp;
struct malloc_type_stats *mtsp;
struct memory_type *mtp;
- int count, error, hint_dontsearch, i, j, maxcpus;
+ int count, hint_dontsearch, i, j, maxcpus;
char *buffer, *p;
size_t size;
- hint_dontsearch = LIST_EMPTY(list);
+ hint_dontsearch = LIST_EMPTY(&list->mtl_list);
/*
* Query the number of CPUs, number of malloc types so that we can
@@ -74,33 +74,32 @@ memstat_sysctl_malloc(struct memory_type_list *list, int flags)
retry:
size = sizeof(maxcpus);
if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) {
- error = errno;
- perror("kern.smp.maxcpus");
- errno = error;
+ if (errno == EACCES || errno == EPERM)
+ list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+ else
+ list->mtl_error = MEMSTAT_ERROR_DATAERROR;
return (-1);
}
if (size != sizeof(maxcpus)) {
- fprintf(stderr, "kern.smp.maxcpus: wrong size");
- errno = EINVAL;
+ list->mtl_error = MEMSTAT_ERROR_DATAERROR;
return (-1);
}
if (maxcpus > MEMSTAT_MAXCPU) {
- fprintf(stderr, "kern.smp.maxcpus: too many CPUs\n");
- errno = EINVAL;
+ list->mtl_error = MEMSTAT_ERROR_TOOMANYCPUS;
return (-1);
}
size = sizeof(count);
if (sysctlbyname("kern.malloc_count", &count, &size, NULL, 0) < 0) {
- error = errno;
- perror("kern.malloc_count");
- errno = error;
+ if (errno == EACCES || errno == EPERM)
+ list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+ else
+ list->mtl_error = MEMSTAT_ERROR_VERSION;
return (-1);
}
if (size != sizeof(count)) {
- fprintf(stderr, "kern.malloc_count: wrong size");
- errno = EINVAL;
+ list->mtl_error = MEMSTAT_ERROR_DATAERROR;
return (-1);
}
@@ -109,9 +108,7 @@ retry:
buffer = malloc(size);
if (buffer == NULL) {
- error = errno;
- perror("malloc");
- errno = error;
+ list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
return (-1);
}
@@ -124,10 +121,11 @@ retry:
free(buffer);
goto retry;
}
- error = errno;
+ if (errno == EACCES || errno == EPERM)
+ list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+ else
+ list->mtl_error = MEMSTAT_ERROR_VERSION;
free(buffer);
- perror("kern.malloc_stats");
- errno = error;
return (-1);
}
@@ -137,9 +135,8 @@ retry:
}
if (size < sizeof(*mtshp)) {
- fprintf(stderr, "sysctl_malloc: invalid malloc header");
+ list->mtl_error = MEMSTAT_ERROR_VERSION;
free(buffer);
- errno = EINVAL;
return (-1);
}
p = buffer;
@@ -147,16 +144,14 @@ retry:
p += sizeof(*mtshp);
if (mtshp->mtsh_version != MALLOC_TYPE_STREAM_VERSION) {
- fprintf(stderr, "sysctl_malloc: unknown malloc version");
+ list->mtl_error = MEMSTAT_ERROR_VERSION;
free(buffer);
- errno = EINVAL;
return (-1);
}
if (mtshp->mtsh_maxcpus > MEMSTAT_MAXCPU) {
- fprintf(stderr, "sysctl_malloc: too many CPUs");
+ list->mtl_error = MEMSTAT_ERROR_TOOMANYCPUS;
free(buffer);
- errno = EINVAL;
return (-1);
}
@@ -182,9 +177,7 @@ retry:
if (mtp == NULL) {
memstat_mtl_free(list);
free(buffer);
- errno = ENOMEM;
- perror("malloc");
- errno = ENOMEM;
+ list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
return (-1);
}
diff --git a/lib/libmemstat/memstat_uma.c b/lib/libmemstat/memstat_uma.c
index 49cc73a..b35c4d9 100644
--- a/lib/libmemstat/memstat_uma.c
+++ b/lib/libmemstat/memstat_uma.c
@@ -59,11 +59,11 @@ memstat_sysctl_uma(struct memory_type_list *list, int flags)
struct uma_type_header *uthp;
struct uma_percpu_stat *upsp;
struct memory_type *mtp;
- int count, error, hint_dontsearch, i, j, maxcpus;
+ int count, hint_dontsearch, i, j, maxcpus;
char *buffer, *p;
size_t size;
- hint_dontsearch = LIST_EMPTY(list);
+ hint_dontsearch = LIST_EMPTY(&list->mtl_list);
/*
* Query the number of CPUs, number of malloc types so that we can
@@ -75,33 +75,32 @@ memstat_sysctl_uma(struct memory_type_list *list, int flags)
retry:
size = sizeof(maxcpus);
if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) {
- error = errno;
- perror("kern.smp.maxcpus");
- errno = error;
+ if (errno == EACCES || errno == EPERM)
+ list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+ else
+ list->mtl_error = MEMSTAT_ERROR_DATAERROR;
return (-1);
}
if (size != sizeof(maxcpus)) {
- fprintf(stderr, "kern.smp.maxcpus: wrong size");
- errno = EINVAL;
+ list->mtl_error = MEMSTAT_ERROR_DATAERROR;
return (-1);
}
if (maxcpus > MEMSTAT_MAXCPU) {
- fprintf(stderr, "kern.smp.maxcpus: too many CPUs\n");
- errno = EINVAL;
+ list->mtl_error = MEMSTAT_ERROR_TOOMANYCPUS;
return (-1);
}
size = sizeof(count);
if (sysctlbyname("vm.zone_count", &count, &size, NULL, 0) < 0) {
- error = errno;
- perror("vm.zone_count");
- errno = error;
+ if (errno == EACCES || errno == EPERM)
+ list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+ else
+ list->mtl_error = MEMSTAT_ERROR_VERSION;
return (-1);
}
if (size != sizeof(count)) {
- fprintf(stderr, "vm.zone_count: wrong size");
- errno = EINVAL;
+ list->mtl_error = MEMSTAT_ERROR_DATAERROR;
return (-1);
}
@@ -110,9 +109,7 @@ retry:
buffer = malloc(size);
if (buffer == NULL) {
- error = errno;
- perror("malloc");
- errno = error;
+ list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
return (-1);
}
@@ -125,10 +122,11 @@ retry:
free(buffer);
goto retry;
}
- error = errno;
+ if (errno == EACCES || errno == EPERM)
+ list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+ else
+ list->mtl_error = MEMSTAT_ERROR_VERSION;
free(buffer);
- perror("vm.zone_stats");
- errno = error;
return (-1);
}
@@ -138,9 +136,8 @@ retry:
}
if (size < sizeof(*ushp)) {
- fprintf(stderr, "sysctl_uma: invalid malloc header");
+ list->mtl_error = MEMSTAT_ERROR_VERSION;
free(buffer);
- errno = EINVAL;
return (-1);
}
p = buffer;
@@ -148,16 +145,14 @@ retry:
p += sizeof(*ushp);
if (ushp->ush_version != UMA_STREAM_VERSION) {
- fprintf(stderr, "sysctl_uma: unknown malloc version");
+ list->mtl_error = MEMSTAT_ERROR_VERSION;
free(buffer);
- errno = EINVAL;
return (-1);
}
if (ushp->ush_maxcpus > MEMSTAT_MAXCPU) {
- fprintf(stderr, "sysctl_uma: too many CPUs");
+ list->mtl_error = MEMSTAT_ERROR_TOOMANYCPUS;
free(buffer);
- errno = EINVAL;
return (-1);
}
@@ -183,9 +178,7 @@ retry:
if (mtp == NULL) {
memstat_mtl_free(list);
free(buffer);
- errno = ENOMEM;
- perror("malloc");
- errno = ENOMEM;
+ list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
return (-1);
}
OpenPOWER on IntegriCloud