diff options
author | Jason King <jason.king@joyent.com> | 2019-01-03 18:01:07 +0000 |
---|---|---|
committer | Jason King <jason.king@joyent.com> | 2019-03-26 18:44:16 +0000 |
commit | 3f1416fd46538cb765be6df507d1ff73fb90170b (patch) | |
tree | 8306e0b75d66f43546df54ccc635a84743a2da36 | |
parent | 5ffb784f5a3c76e1a0dfe2349748d3a9a8f33082 (diff) | |
download | illumos-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.c | 120 | ||||
-rw-r--r-- | usr/src/lib/libcustr/common/libcustr.h | 75 | ||||
-rw-r--r-- | usr/src/lib/libcustr/common/mapfile-vers | 6 |
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: *; }; |