summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason King <jason.king@joyent.com>2019-01-03 18:01:07 +0000
committerJason King <jason.king@joyent.com>2019-03-26 18:44:16 +0000
commit3f1416fd46538cb765be6df507d1ff73fb90170b (patch)
tree8306e0b75d66f43546df54ccc635a84743a2da36
parent5ffb784f5a3c76e1a0dfe2349748d3a9a8f33082 (diff)
downloadillumos-joyent-3f1416fd46538cb765be6df507d1ff73fb90170b.tar.gz
OS-7449 Add custom allocators to libcustr
Reviewed by: Robert Mustacchi <rm@joyent.com> Approved by: Mike Gerdts <mike.gerdts@joyent.com>
-rw-r--r--usr/src/lib/libcustr/common/custr.c120
-rw-r--r--usr/src/lib/libcustr/common/libcustr.h75
-rw-r--r--usr/src/lib/libcustr/common/mapfile-vers6
3 files changed, 190 insertions, 11 deletions
diff --git a/usr/src/lib/libcustr/common/custr.c b/usr/src/lib/libcustr/common/custr.c
index 5c5b0e370a..6d3a003e6b 100644
--- a/usr/src/lib/libcustr/common/custr.c
+++ b/usr/src/lib/libcustr/common/custr.c
@@ -14,7 +14,7 @@
*/
/*
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#include <stdlib.h>
@@ -27,6 +27,19 @@
#include "libcustr.h"
+/*
+ * libcustr is used by some things in usr/src/tools. If we are building
+ * on an older platform, __unused might not be defined on the build host.
+ * We define it here if needed.
+ */
+#ifndef __unused
+#if __GNUC_VERSION >= 20700
+#define __unused __attribute__((_unused__))
+#else
+#define __unused
+#endif /* __GNUC_VERSION */
+#endif /* __unused */
+
typedef enum {
CUSTR_FIXEDBUF = 0x01
} custr_flags_t;
@@ -36,10 +49,32 @@ struct custr {
size_t cus_datalen;
char *cus_data;
custr_flags_t cus_flags;
+ custr_alloc_t *cus_alloc;
};
+#define CUSTR_ALLOC(_cus, _len) \
+ (_cus)->cus_alloc->cua_ops->custr_ao_alloc((_cus)->cus_alloc, (_len))
+#define CUSTR_FREE(_cus, _p, _len) \
+ (_cus)->cus_alloc->cua_ops->custr_ao_free((_cus)->cus_alloc, \
+ (_p), (_len))
#define STRING_CHUNK_SIZE 64
+static void *custr_def_alloc(custr_alloc_t *, size_t);
+static void custr_def_free(custr_alloc_t *, void *, size_t);
+
+static custr_alloc_ops_t custr_alloc_ops_default = {
+ NULL, /* custr_ao_init */
+ NULL, /* custr_ao_fini */
+ custr_def_alloc, /* custr_ao_alloc */
+ custr_def_free /* custr_ao_free */
+};
+
+static custr_alloc_t custr_alloc_default = {
+ CUSTR_VERSION, /* cua_version */
+ &custr_alloc_ops_default, /* cua_ops */
+ NULL /* cua_arg */
+};
+
void
custr_reset(custr_t *cus)
{
@@ -97,7 +132,7 @@ custr_append_vprintf(custr_t *cus, const char *fmt, va_list ap)
/*
* Allocate replacement memory:
*/
- if ((new_data = malloc(new_datalen)) == NULL) {
+ if ((new_data = CUSTR_ALLOC(cus, new_datalen)) == NULL) {
return (-1);
}
@@ -108,7 +143,7 @@ custr_append_vprintf(custr_t *cus, const char *fmt, va_list ap)
if (cus->cus_data != NULL) {
(void) memcpy(new_data, cus->cus_data,
cus->cus_strlen + 1);
- free(cus->cus_data);
+ CUSTR_FREE(cus, cus->cus_data, cus->cus_datalen);
}
/*
@@ -155,21 +190,64 @@ custr_append(custr_t *cus, const char *name)
}
int
-custr_alloc(custr_t **cus)
+custr_alloc_init(custr_alloc_t *cua, const custr_alloc_ops_t *ops, ...)
+{
+ int ret = 0;
+
+ if (cua->cua_version != CUSTR_VERSION || ops->custr_ao_alloc == NULL ||
+ ops->custr_ao_free == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ cua->cua_ops = ops;
+ cua->cua_arg = NULL;
+
+ if (ops->custr_ao_init != NULL) {
+ va_list ap;
+
+ va_start(ap, ops);
+ ret = ops->custr_ao_init(cua, ap);
+ va_end(ap);
+ }
+
+ return ((ret == 0) ? 0 : -1);
+}
+
+void
+custr_alloc_fini(custr_alloc_t *cua)
+{
+ if (cua->cua_ops->custr_ao_fini != NULL)
+ cua->cua_ops->custr_ao_fini(cua);
+}
+
+int
+custr_xalloc(custr_t **cus, custr_alloc_t *cao)
{
custr_t *t;
- if ((t = calloc(1, sizeof (*t))) == NULL) {
+ if (cao == NULL)
+ cao = &custr_alloc_default;
+
+ if ((t = cao->cua_ops->custr_ao_alloc(cao, sizeof (*t))) == NULL) {
*cus = NULL;
return (-1);
}
+ (void) memset(t, 0, sizeof (*t));
+ t->cus_alloc = cao;
*cus = t;
return (0);
}
int
-custr_alloc_buf(custr_t **cus, void *buf, size_t buflen)
+custr_alloc(custr_t **cus)
+{
+ return (custr_xalloc(cus, NULL));
+}
+
+int
+custr_xalloc_buf(custr_t **cus, void *buf, size_t buflen, custr_alloc_t *cao)
{
int ret;
@@ -178,7 +256,7 @@ custr_alloc_buf(custr_t **cus, void *buf, size_t buflen)
return (-1);
}
- if ((ret = custr_alloc(cus)) != 0)
+ if ((ret = custr_xalloc(cus, cao)) != 0)
return (ret);
(*cus)->cus_data = buf;
@@ -190,13 +268,37 @@ custr_alloc_buf(custr_t **cus, void *buf, size_t buflen)
return (0);
}
+int
+custr_alloc_buf(custr_t **cus, void *buf, size_t buflen)
+{
+ return (custr_xalloc_buf(cus, buf, buflen, NULL));
+}
+
void
custr_free(custr_t *cus)
{
+ custr_alloc_t *cao;
+
if (cus == NULL)
return;
if ((cus->cus_flags & CUSTR_FIXEDBUF) == 0)
- free(cus->cus_data);
- free(cus);
+ CUSTR_FREE(cus, cus->cus_data, cus->cus_datalen);
+
+ cao = cus->cus_alloc;
+ cao->cua_ops->custr_ao_free(cao, cus, sizeof (*cus));
+}
+
+/*ARGSUSED*/
+static void *
+custr_def_alloc(custr_alloc_t *cao __unused, size_t len)
+{
+ return (malloc(len));
+}
+
+/*ARGSUSED*/
+static void
+custr_def_free(custr_alloc_t *cao __unused, void *p, size_t len __unused)
+{
+ free(p);
}
diff --git a/usr/src/lib/libcustr/common/libcustr.h b/usr/src/lib/libcustr/common/libcustr.h
index 7671390d7f..8fe5fee1b7 100644
--- a/usr/src/lib/libcustr/common/libcustr.h
+++ b/usr/src/lib/libcustr/common/libcustr.h
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2018, Joyent, Inc.
+ * Copyright 2019, Joyent, Inc.
*/
#ifndef _LIBCUSTR_H
@@ -26,12 +26,78 @@ extern "C" {
#endif
typedef struct custr custr_t;
+typedef struct custr_alloc_ops custr_alloc_ops_t;
+typedef struct custr_alloc custr_alloc_t;
+
+/*
+ * A custom allocator instance. To use a custom allocator, the user provides
+ * the memory for a given custr_alloc_t and calls custr_alloc_init() with the
+ * address of the instance to initialize it. custr_alloc_init() will invoke
+ * the init op (if defined) with any additional arguments. The user can then
+ * save any desired state for the allocator instance in cua_arg. If a
+ * custom allocator instance needs to do any cleanup after it's no longer
+ * needed, it should also define the fini op and invoke custr_alloc_fini() to
+ * do the cleanup.
+ */
+#define CUSTR_VERSION 1
+struct custr_alloc {
+ uint_t cua_version;
+ const custr_alloc_ops_t *cua_ops;
+ void *cua_arg;
+};
+
+struct custr_alloc_ops {
+ /*
+ * Optional allocator constructor. Returns 0 on success, -1
+ * on failure (and should set errno on failure).
+ */
+ int (*custr_ao_init)(custr_alloc_t *, va_list);
+ /*
+ * Optional allocator destructor.
+ */
+ void (*custr_ao_fini)(custr_alloc_t *);
+ /*
+ * Returns at least size_t bytes of allocated memory, or NULL.
+ * It should also set errno on failure.
+ */
+ void *(*custr_ao_alloc)(custr_alloc_t *, size_t);
+ /*
+ * Free the memory previously allocated with custr_ao_alloc.
+ */
+ void (*custr_ao_free)(custr_alloc_t *, void *, size_t);
+};
+
+/*
+ * Initializes a custr allocator. custr_alloc_t->cua_version should be set to
+ * CUSTR_VERSION prior to calling custr_alloc_init(). Both the custr_ao_alloc
+ * and custr_ao_free functions must be defined in custr_alloc_ops_t (the
+ * init and fini functions are both optional). If an init function is
+ * provided, it will be called with a va_list parameter initialized to
+ * point to any arguments after the custr_alloc_ops_t * argument.
+ *
+ * If cua_version is not CUSTR_VERSION, or if the custr_ao_alloc or
+ * custr_ao_free functions are missing, -1 is returned and errno is set to
+ * EINVAL. If an init function was given and it fails (returns -1 -- see
+ * the struct custr_alloc_ops definition aboive), -1 is returned and any
+ * value of errno set by the init function is left unchanged.
+ *
+ * On success, 0 is returned.
+ */
+int custr_alloc_init(custr_alloc_t *, const custr_alloc_ops_t *, ...);
+
+/*
+ * If a fini function was given in the custr_alloc_init() call that initalized
+ * the given custr_alloc_t instance, it is called to perform any custom
+ * cleanup needed.
+ */
+void custr_alloc_fini(custr_alloc_t *);
/*
* Allocate and free a "custr_t" dynamic string object. Returns 0 on success
* and -1 otherwise.
*/
int custr_alloc(custr_t **);
+int custr_xalloc(custr_t **, custr_alloc_t *);
void custr_free(custr_t *);
/*
@@ -41,6 +107,13 @@ void custr_free(custr_t *);
int custr_alloc_buf(custr_t **, void *, size_t);
/*
+ * Like custr_alloc_buf(), except the given allocator is used to allocate
+ * the custr_t * instance (but still uses a fixed external buffer for the
+ * string contents).
+ */
+int custr_xalloc_buf(custr_t **, void *, size_t, custr_alloc_t *);
+
+/*
* Append a single character, or a NUL-terminated string of characters, to a
* dynamic string. Returns 0 on success and -1 otherwise. The dynamic string
* will be unmodified if the function returns -1.
diff --git a/usr/src/lib/libcustr/common/mapfile-vers b/usr/src/lib/libcustr/common/mapfile-vers
index 369771929a..f94636b6f5 100644
--- a/usr/src/lib/libcustr/common/mapfile-vers
+++ b/usr/src/lib/libcustr/common/mapfile-vers
@@ -10,7 +10,7 @@
#
#
-# Copyright 2018, Joyent, Inc.
+# Copyright 2019, Joyent, Inc.
#
#
@@ -33,6 +33,8 @@ SYMBOL_VERSION ILLUMOSprivate {
global:
custr_alloc;
custr_alloc_buf;
+ custr_alloc_fini;
+ custr_alloc_init;
custr_append;
custr_appendc;
custr_append_printf;
@@ -41,6 +43,8 @@ SYMBOL_VERSION ILLUMOSprivate {
custr_free;
custr_len;
custr_reset;
+ custr_xalloc;
+ custr_xalloc_buf;
local:
*;
};