summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/stringfields.c508
-rw-r--r--main/utils.c371
2 files changed, 508 insertions, 371 deletions
diff --git a/main/stringfields.c b/main/stringfields.c
new file mode 100644
index 000000000..67dd06c9b
--- /dev/null
+++ b/main/stringfields.c
@@ -0,0 +1,508 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2006, Digium, Inc.
+ *
+ * Kevin P. Fleming <kpfleming@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief String fields
+ *
+ * \author Kevin P. Fleming <kpfleming@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_REGISTER_FILE()
+
+#include "asterisk/stringfields.h"
+#include "asterisk/utils.h"
+
+/* this is a little complex... string fields are stored with their
+ allocated size in the bytes preceding the string; even the
+ constant 'empty' string has to be this way, so the code that
+ checks to see if there is enough room for a new string doesn't
+ have to have any special case checks
+*/
+
+static const struct {
+ ast_string_field_allocation allocation;
+ char string[1];
+} __ast_string_field_empty_buffer;
+
+ast_string_field __ast_string_field_empty = __ast_string_field_empty_buffer.string;
+
+#define ALLOCATOR_OVERHEAD 48
+
+static size_t optimal_alloc_size(size_t size)
+{
+ unsigned int count;
+
+ size += ALLOCATOR_OVERHEAD;
+
+ for (count = 1; size; size >>= 1, count++);
+
+ return (1 << count) - ALLOCATOR_OVERHEAD;
+}
+
+static void *calloc_wrapper(unsigned int num_structs, size_t struct_size,
+ const char *file, int lineno, const char *func)
+{
+#if defined(__AST_DEBUG_MALLOC)
+ return __ast_calloc(num_structs, struct_size, file, lineno, func);
+#else
+ return ast_calloc(num_structs, struct_size);
+#endif
+}
+
+/*! \brief add a new block to the pool.
+ * We can only allocate from the topmost pool, so the
+ * fields in *mgr reflect the size of that only.
+ */
+static int add_string_pool(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head,
+ size_t size, const char *file, int lineno, const char *func)
+{
+ struct ast_string_field_pool *pool;
+ size_t alloc_size = optimal_alloc_size(sizeof(*pool) + size);
+
+ if (!(pool = calloc_wrapper(1, alloc_size, file, lineno, func))) {
+ return -1;
+ }
+
+ pool->prev = *pool_head;
+ pool->size = alloc_size - sizeof(*pool);
+ *pool_head = pool;
+ mgr->last_alloc = NULL;
+
+ return 0;
+}
+
+static void reset_field(const char **p)
+{
+ *p = __ast_string_field_empty;
+}
+
+/*!
+ * \brief Internal cleanup function
+ * \internal
+ * \param mgr
+ * \param pool_head
+ * \param cleanup_type
+ * 0: Reset all string fields and free all pools except the last or embedded pool.
+ * Keep the internal management structures so the structure can be reused.
+ * -1: Reset all string fields and free all pools except the embedded pool.
+ * Free the internal management structures.
+ * \param file
+ * \param lineno
+ * \param func
+ *
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int __ast_string_field_free_memory(struct ast_string_field_mgr *mgr,
+ struct ast_string_field_pool **pool_head, enum ast_stringfield_cleanup_type cleanup_type,
+ const char *file, int lineno, const char *func)
+{
+ struct ast_string_field_pool *cur = NULL;
+ struct ast_string_field_pool *preserve = NULL;
+
+ if (!mgr->header) {
+ return -1;
+ }
+
+ /* reset all the fields regardless of cleanup type */
+ AST_VECTOR_CALLBACK_VOID(&mgr->header->string_fields, reset_field);
+
+ switch (cleanup_type) {
+ case AST_STRINGFIELD_DESTROY:
+ AST_VECTOR_FREE(&mgr->header->string_fields);
+
+ if (mgr->header->embedded_pool) { /* ALWAYS preserve the embedded pool if there is one */
+ preserve = mgr->header->embedded_pool;
+ preserve->used = preserve->active = 0;
+ }
+
+ ast_free(mgr->header);
+ mgr->header = NULL;
+ break;
+ case AST_STRINGFIELD_RESET:
+ /* Preserve the embedded pool if there is one, otherwise the last pool */
+ if (mgr->header->embedded_pool) {
+ preserve = mgr->header->embedded_pool;
+ } else {
+ if (*pool_head == NULL) {
+ ast_log(LOG_WARNING, "trying to reset empty pool\n");
+ return -1;
+ }
+ preserve = *pool_head;
+ }
+ preserve->used = preserve->active = 0;
+ break;
+ default:
+ return -1;
+ }
+
+ cur = *pool_head;
+ while (cur) {
+ struct ast_string_field_pool *prev = cur->prev;
+
+ if (cur != preserve) {
+ ast_free(cur);
+ }
+ cur = prev;
+ }
+
+ *pool_head = preserve;
+ if (preserve) {
+ preserve->prev = NULL;
+ }
+
+ return 0;
+}
+
+/*!
+ * \brief Internal initialization function
+ * \internal
+ * \param mgr
+ * \param pool_head
+ * \param needed
+ * \param file
+ * \param lineno
+ * \param func
+ *
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head,
+ int needed, const char *file, int lineno, const char *func)
+{
+ const char **p = (const char **) pool_head + 1;
+ size_t initial_vector_size = ((size_t) (((char *)mgr) - ((char *)p))) / sizeof(*p);
+
+ if (needed <= 0) {
+ return __ast_string_field_free_memory(mgr, pool_head, needed, file, lineno, func);
+ }
+
+ mgr->last_alloc = NULL;
+#if defined(__AST_DEBUG_MALLOC)
+ mgr->owner_file = file;
+ mgr->owner_func = func;
+ mgr->owner_line = lineno;
+#endif
+
+ if (!(mgr->header = calloc_wrapper(1, sizeof(*mgr->header), file, lineno, func))) {
+ return -1;
+ }
+
+ if (AST_VECTOR_INIT(&mgr->header->string_fields, initial_vector_size)) {
+ ast_free(mgr->header);
+ mgr->header = NULL;
+ return -1;
+ }
+
+ while ((struct ast_string_field_mgr *) p != mgr) {
+ AST_VECTOR_APPEND(&mgr->header->string_fields, p);
+ *p++ = __ast_string_field_empty;
+ }
+
+ *pool_head = NULL;
+ mgr->header->embedded_pool = NULL;
+ if (add_string_pool(mgr, pool_head, needed, file, lineno, func)) {
+ AST_VECTOR_FREE(&mgr->header->string_fields);
+ ast_free(mgr->header);
+ mgr->header = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr,
+ struct ast_string_field_pool **pool_head, size_t needed)
+{
+ char *result = NULL;
+ size_t space = (*pool_head)->size - (*pool_head)->used;
+ size_t to_alloc;
+
+ /* Make room for ast_string_field_allocation and make it a multiple of that. */
+ to_alloc = ast_make_room_for(needed, ast_string_field_allocation);
+ ast_assert(to_alloc % ast_alignof(ast_string_field_allocation) == 0);
+
+ if (__builtin_expect(to_alloc > space, 0)) {
+ size_t new_size = (*pool_head)->size;
+
+ while (new_size < to_alloc) {
+ new_size *= 2;
+ }
+
+#if defined(__AST_DEBUG_MALLOC)
+ if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func))
+ return NULL;
+#else
+ if (add_string_pool(mgr, pool_head, new_size, __FILE__, __LINE__, __FUNCTION__))
+ return NULL;
+#endif
+ }
+
+ /* pool->base is always aligned (gcc aligned attribute). We ensure that
+ * to_alloc is also a multiple of ast_alignof(ast_string_field_allocation)
+ * causing result to always be aligned as well; which in turn fixes that
+ * AST_STRING_FIELD_ALLOCATION(result) is aligned. */
+ result = (*pool_head)->base + (*pool_head)->used;
+ (*pool_head)->used += to_alloc;
+ (*pool_head)->active += needed;
+ result += ast_alignof(ast_string_field_allocation);
+ AST_STRING_FIELD_ALLOCATION(result) = needed;
+ mgr->last_alloc = result;
+
+ return result;
+}
+
+int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr,
+ struct ast_string_field_pool **pool_head, size_t needed, const ast_string_field *ptr)
+{
+ ssize_t grow = needed - AST_STRING_FIELD_ALLOCATION(*ptr);
+ size_t space = (*pool_head)->size - (*pool_head)->used;
+
+ if (*ptr != mgr->last_alloc) {
+ return 1;
+ }
+
+ if (space < grow) {
+ return 1;
+ }
+
+ (*pool_head)->used += grow;
+ (*pool_head)->active += grow;
+ AST_STRING_FIELD_ALLOCATION(*ptr) += grow;
+
+ return 0;
+}
+
+void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
+ const ast_string_field ptr)
+{
+ struct ast_string_field_pool *pool, *prev;
+
+ if (ptr == __ast_string_field_empty) {
+ return;
+ }
+
+ for (pool = pool_head, prev = NULL; pool; prev = pool, pool = pool->prev) {
+ if ((ptr >= pool->base) && (ptr <= (pool->base + pool->size))) {
+ pool->active -= AST_STRING_FIELD_ALLOCATION(ptr);
+ if (pool->active == 0) {
+ if (prev) {
+ prev->prev = pool->prev;
+ ast_free(pool);
+ } else {
+ pool->used = 0;
+ }
+ }
+ break;
+ }
+ }
+}
+
+void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
+ struct ast_string_field_pool **pool_head, ast_string_field *ptr,
+ const char *format, va_list ap)
+{
+ size_t needed;
+ size_t available;
+ size_t space = (*pool_head)->size - (*pool_head)->used;
+ int res;
+ ssize_t grow;
+ char *target;
+ va_list ap2;
+
+ /* if the field already has space allocated, try to reuse it;
+ otherwise, try to use the empty space at the end of the current
+ pool
+ */
+ if (*ptr != __ast_string_field_empty) {
+ target = (char *) *ptr;
+ available = AST_STRING_FIELD_ALLOCATION(*ptr);
+ if (*ptr == mgr->last_alloc) {
+ available += space;
+ }
+ } else {
+ /* pool->used is always a multiple of ast_alignof(ast_string_field_allocation)
+ * so we don't need to re-align anything here.
+ */
+ target = (*pool_head)->base + (*pool_head)->used + ast_alignof(ast_string_field_allocation);
+ if (space > ast_alignof(ast_string_field_allocation)) {
+ available = space - ast_alignof(ast_string_field_allocation);
+ } else {
+ available = 0;
+ }
+ }
+
+ va_copy(ap2, ap);
+ res = vsnprintf(target, available, format, ap2);
+ va_end(ap2);
+
+ if (res < 0) {
+ /* Are we out of memory? */
+ return;
+ }
+ if (res == 0) {
+ __ast_string_field_release_active(*pool_head, *ptr);
+ *ptr = __ast_string_field_empty;
+ return;
+ }
+ needed = (size_t)res + 1; /* NUL byte */
+
+ if (needed > available) {
+ /* the allocation could not be satisfied using the field's current allocation
+ (if it has one), or the space available in the pool (if it does not). allocate
+ space for it, adding a new string pool if necessary.
+ */
+ if (!(target = (char *) __ast_string_field_alloc_space(mgr, pool_head, needed))) {
+ return;
+ }
+ vsprintf(target, format, ap);
+ va_end(ap); /* XXX va_end without va_start? */
+ __ast_string_field_release_active(*pool_head, *ptr);
+ *ptr = target;
+ } else if (*ptr != target) {
+ /* the allocation was satisfied using available space in the pool, but not
+ using the space already allocated to the field
+ */
+ __ast_string_field_release_active(*pool_head, *ptr);
+ mgr->last_alloc = *ptr = target;
+ ast_assert(needed < (ast_string_field_allocation)-1);
+ AST_STRING_FIELD_ALLOCATION(target) = (ast_string_field_allocation)needed;
+ (*pool_head)->used += ast_make_room_for(needed, ast_string_field_allocation);
+ (*pool_head)->active += needed;
+ } else if ((grow = (needed - AST_STRING_FIELD_ALLOCATION(*ptr))) > 0) {
+ /* the allocation was satisfied by using available space in the pool *and*
+ the field was the last allocated field from the pool, so it grew
+ */
+ AST_STRING_FIELD_ALLOCATION(*ptr) += grow;
+ (*pool_head)->used += ast_align_for(grow, ast_string_field_allocation);
+ (*pool_head)->active += grow;
+ }
+}
+
+void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
+ struct ast_string_field_pool **pool_head, ast_string_field *ptr, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ __ast_string_field_ptr_build_va(mgr, pool_head, ptr, format, ap);
+ va_end(ap);
+}
+
+void *__ast_calloc_with_stringfields(unsigned int num_structs, size_t struct_size,
+ size_t field_mgr_offset, size_t field_mgr_pool_offset, size_t pool_size, const char *file,
+ int lineno, const char *func)
+{
+ struct ast_string_field_mgr *mgr;
+ struct ast_string_field_pool *pool;
+ struct ast_string_field_pool **pool_head;
+ size_t pool_size_needed = sizeof(*pool) + pool_size;
+ size_t size_to_alloc = optimal_alloc_size(struct_size + pool_size_needed);
+ void *allocation;
+ const char **p;
+ size_t initial_vector_size;
+
+ ast_assert(num_structs == 1);
+
+ if (!(allocation = calloc_wrapper(num_structs, size_to_alloc, file, lineno, func))) {
+ return NULL;
+ }
+
+ mgr = allocation + field_mgr_offset;
+
+ /*
+ * The header is calloced in __ast_string_field_init so it also gets calloced here
+ * so __ast_string_fields_free_memory can always just free mgr->header.
+ */
+ mgr->header = calloc_wrapper(1, sizeof(*mgr->header), file, lineno, func);
+ if (!mgr->header) {
+ ast_free(allocation);
+ return NULL;
+ }
+
+ pool = allocation + struct_size;
+ pool_head = allocation + field_mgr_pool_offset;
+ p = (const char **) pool_head + 1;
+ initial_vector_size = ((size_t) (((char *)mgr) - ((char *)p))) / sizeof(*p);
+
+ if (AST_VECTOR_INIT(&mgr->header->string_fields, initial_vector_size)) {
+ ast_free(mgr->header);
+ ast_free(allocation);
+ return NULL;
+ }
+
+ while ((struct ast_string_field_mgr *) p != mgr) {
+ AST_VECTOR_APPEND(&mgr->header->string_fields, p);
+ *p++ = __ast_string_field_empty;
+ }
+
+ mgr->header->embedded_pool = pool;
+ *pool_head = pool;
+ pool->size = size_to_alloc - struct_size - sizeof(*pool);
+#if defined(__AST_DEBUG_MALLOC)
+ mgr->owner_file = file;
+ mgr->owner_func = func;
+ mgr->owner_line = lineno;
+#endif
+
+ return allocation;
+}
+
+int __ast_string_fields_cmp(struct ast_string_field_vector *left,
+ struct ast_string_field_vector *right)
+{
+ int i;
+ int res = 0;
+
+ ast_assert(AST_VECTOR_SIZE(left) == AST_VECTOR_SIZE(right));
+
+ for (i = 0; i < AST_VECTOR_SIZE(left); i++) {
+ if ((res = strcmp(*AST_VECTOR_GET(left, i), *AST_VECTOR_GET(right, i)))) {
+ return res;
+ }
+ }
+
+ return res;
+}
+
+int __ast_string_fields_copy(struct ast_string_field_pool *copy_pool,
+ struct ast_string_field_mgr *copy_mgr, struct ast_string_field_mgr *orig_mgr)
+{
+ int i;
+ struct ast_string_field_vector *dest = &(copy_mgr->header->string_fields);
+ struct ast_string_field_vector *src = &(orig_mgr->header->string_fields);
+
+ ast_assert(AST_VECTOR_SIZE(dest) == AST_VECTOR_SIZE(src));
+
+ for (i = 0; i < AST_VECTOR_SIZE(dest); i++) {
+ __ast_string_field_release_active(copy_pool, *AST_VECTOR_GET(dest, i));
+ *AST_VECTOR_GET(dest, i) = __ast_string_field_empty;
+ }
+
+ for (i = 0; i < AST_VECTOR_SIZE(dest); i++) {
+ if (ast_string_field_ptr_set_by_fields(copy_pool, *copy_mgr, AST_VECTOR_GET(dest, i),
+ *AST_VECTOR_GET(src, i))) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/main/utils.c b/main/utils.c
index 9a400d9db..95eda1102 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -61,9 +61,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/time.h"
#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
-#include "asterisk/stringfields.h"
-
-#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
#include "asterisk/utils.h"
#define AST_API_MODULE
@@ -2028,374 +2025,6 @@ char *ast_to_camel_case_delim(const char *s, const char *delim)
return res;
}
-/*
- * stringfields support routines.
- */
-
-/* this is a little complex... string fields are stored with their
- allocated size in the bytes preceding the string; even the
- constant 'empty' string has to be this way, so the code that
- checks to see if there is enough room for a new string doesn't
- have to have any special case checks
-*/
-
-static const struct {
- ast_string_field_allocation allocation;
- char string[1];
-} __ast_string_field_empty_buffer;
-
-ast_string_field __ast_string_field_empty = __ast_string_field_empty_buffer.string;
-
-#define ALLOCATOR_OVERHEAD 48
-
-static size_t optimal_alloc_size(size_t size)
-{
- unsigned int count;
-
- size += ALLOCATOR_OVERHEAD;
-
- for (count = 1; size; size >>= 1, count++);
-
- return (1 << count) - ALLOCATOR_OVERHEAD;
-}
-
-/*! \brief add a new block to the pool.
- * We can only allocate from the topmost pool, so the
- * fields in *mgr reflect the size of that only.
- */
-static int add_string_pool(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head,
- size_t size, const char *file, int lineno, const char *func)
-{
- struct ast_string_field_pool *pool;
- size_t alloc_size = optimal_alloc_size(sizeof(*pool) + size);
-
-#if defined(__AST_DEBUG_MALLOC)
- if (!(pool = __ast_calloc(1, alloc_size, file, lineno, func))) {
- return -1;
- }
-#else
- if (!(pool = ast_calloc(1, alloc_size))) {
- return -1;
- }
-#endif
-
- pool->prev = *pool_head;
- pool->size = alloc_size - sizeof(*pool);
- *pool_head = pool;
- mgr->last_alloc = NULL;
-
- return 0;
-}
-
-/*
- * This is an internal API, code should not use it directly.
- * It initializes all fields as empty, then uses 'size' for 3 functions:
- * size > 0 means initialize the pool list with a pool of given size.
- * This must be called right after allocating the object.
- * size = 0 means release all pools except the most recent one.
- * If the first pool was allocated via embedding in another
- * object, that pool will be preserved instead.
- * This is useful to e.g. reset an object to the initial value.
- * size < 0 means release all pools.
- * This must be done before destroying the object.
- */
-int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head,
- int needed, const char *file, int lineno, const char *func)
-{
- const char **p = (const char **) pool_head + 1;
- struct ast_string_field_pool *cur = NULL;
- struct ast_string_field_pool *preserve = NULL;
-
- /* clear fields - this is always necessary */
- while ((struct ast_string_field_mgr *) p != mgr) {
- *p++ = __ast_string_field_empty;
- }
-
- mgr->last_alloc = NULL;
-#if defined(__AST_DEBUG_MALLOC)
- mgr->owner_file = file;
- mgr->owner_func = func;
- mgr->owner_line = lineno;
-#endif
- if (needed > 0) { /* allocate the initial pool */
- *pool_head = NULL;
- mgr->embedded_pool = NULL;
- return add_string_pool(mgr, pool_head, needed, file, lineno, func);
- }
-
- /* if there is an embedded pool, we can't actually release *all*
- * pools, we must keep the embedded one. if the caller is about
- * to free the structure that contains the stringfield manager
- * and embedded pool anyway, it will be freed as part of that
- * operation.
- */
- if ((needed < 0) && mgr->embedded_pool) {
- needed = 0;
- }
-
- if (needed < 0) { /* reset all pools */
- cur = *pool_head;
- } else if (mgr->embedded_pool) { /* preserve the embedded pool */
- preserve = mgr->embedded_pool;
- cur = *pool_head;
- } else { /* preserve the last pool */
- if (*pool_head == NULL) {
- ast_log(LOG_WARNING, "trying to reset empty pool\n");
- return -1;
- }
- preserve = *pool_head;
- cur = preserve->prev;
- }
-
- if (preserve) {
- preserve->prev = NULL;
- preserve->used = preserve->active = 0;
- }
-
- while (cur) {
- struct ast_string_field_pool *prev = cur->prev;
-
- if (cur != preserve) {
- ast_free(cur);
- }
- cur = prev;
- }
-
- *pool_head = preserve;
-
- return 0;
-}
-
-ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr,
- struct ast_string_field_pool **pool_head, size_t needed)
-{
- char *result = NULL;
- size_t space = (*pool_head)->size - (*pool_head)->used;
- size_t to_alloc;
-
- /* Make room for ast_string_field_allocation and make it a multiple of that. */
- to_alloc = ast_make_room_for(needed, ast_string_field_allocation);
- ast_assert(to_alloc % ast_alignof(ast_string_field_allocation) == 0);
-
- if (__builtin_expect(to_alloc > space, 0)) {
- size_t new_size = (*pool_head)->size;
-
- while (new_size < to_alloc) {
- new_size *= 2;
- }
-
-#if defined(__AST_DEBUG_MALLOC)
- if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func))
- return NULL;
-#else
- if (add_string_pool(mgr, pool_head, new_size, __FILE__, __LINE__, __FUNCTION__))
- return NULL;
-#endif
- }
-
- /* pool->base is always aligned (gcc aligned attribute). We ensure that
- * to_alloc is also a multiple of ast_alignof(ast_string_field_allocation)
- * causing result to always be aligned as well; which in turn fixes that
- * AST_STRING_FIELD_ALLOCATION(result) is aligned. */
- result = (*pool_head)->base + (*pool_head)->used;
- (*pool_head)->used += to_alloc;
- (*pool_head)->active += needed;
- result += ast_alignof(ast_string_field_allocation);
- AST_STRING_FIELD_ALLOCATION(result) = needed;
- mgr->last_alloc = result;
-
- return result;
-}
-
-int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr,
- struct ast_string_field_pool **pool_head, size_t needed,
- const ast_string_field *ptr)
-{
- ssize_t grow = needed - AST_STRING_FIELD_ALLOCATION(*ptr);
- size_t space = (*pool_head)->size - (*pool_head)->used;
-
- if (*ptr != mgr->last_alloc) {
- return 1;
- }
-
- if (space < grow) {
- return 1;
- }
-
- (*pool_head)->used += grow;
- (*pool_head)->active += grow;
- AST_STRING_FIELD_ALLOCATION(*ptr) += grow;
-
- return 0;
-}
-
-void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
- const ast_string_field ptr)
-{
- struct ast_string_field_pool *pool, *prev;
-
- if (ptr == __ast_string_field_empty) {
- return;
- }
-
- for (pool = pool_head, prev = NULL; pool; prev = pool, pool = pool->prev) {
- if ((ptr >= pool->base) && (ptr <= (pool->base + pool->size))) {
- pool->active -= AST_STRING_FIELD_ALLOCATION(ptr);
- if (pool->active == 0) {
- if (prev) {
- prev->prev = pool->prev;
- ast_free(pool);
- } else {
- pool->used = 0;
- }
- }
- break;
- }
- }
-}
-
-void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
- struct ast_string_field_pool **pool_head,
- ast_string_field *ptr, const char *format, va_list ap)
-{
- size_t needed;
- size_t available;
- size_t space = (*pool_head)->size - (*pool_head)->used;
- int res;
- ssize_t grow;
- char *target;
- va_list ap2;
-
- /* if the field already has space allocated, try to reuse it;
- otherwise, try to use the empty space at the end of the current
- pool
- */
- if (*ptr != __ast_string_field_empty) {
- target = (char *) *ptr;
- available = AST_STRING_FIELD_ALLOCATION(*ptr);
- if (*ptr == mgr->last_alloc) {
- available += space;
- }
- } else {
- /* pool->used is always a multiple of ast_alignof(ast_string_field_allocation)
- * so we don't need to re-align anything here.
- */
- target = (*pool_head)->base + (*pool_head)->used + ast_alignof(ast_string_field_allocation);
- if (space > ast_alignof(ast_string_field_allocation)) {
- available = space - ast_alignof(ast_string_field_allocation);
- } else {
- available = 0;
- }
- }
-
- va_copy(ap2, ap);
- res = vsnprintf(target, available, format, ap2);
- va_end(ap2);
-
- if (res < 0) {
- /* Are we out of memory? */
- return;
- }
- if (res == 0) {
- __ast_string_field_release_active(*pool_head, *ptr);
- *ptr = __ast_string_field_empty;
- return;
- }
- needed = (size_t)res + 1; /* NUL byte */
-
- if (needed > available) {
- /* the allocation could not be satisfied using the field's current allocation
- (if it has one), or the space available in the pool (if it does not). allocate
- space for it, adding a new string pool if necessary.
- */
- if (!(target = (char *) __ast_string_field_alloc_space(mgr, pool_head, needed))) {
- return;
- }
- vsprintf(target, format, ap);
- va_end(ap); /* XXX va_end without va_start? */
- __ast_string_field_release_active(*pool_head, *ptr);
- *ptr = target;
- } else if (*ptr != target) {
- /* the allocation was satisfied using available space in the pool, but not
- using the space already allocated to the field
- */
- __ast_string_field_release_active(*pool_head, *ptr);
- mgr->last_alloc = *ptr = target;
- ast_assert(needed < (ast_string_field_allocation)-1);
- AST_STRING_FIELD_ALLOCATION(target) = (ast_string_field_allocation)needed;
- (*pool_head)->used += ast_make_room_for(needed, ast_string_field_allocation);
- (*pool_head)->active += needed;
- } else if ((grow = (needed - AST_STRING_FIELD_ALLOCATION(*ptr))) > 0) {
- /* the allocation was satisfied by using available space in the pool *and*
- the field was the last allocated field from the pool, so it grew
- */
- AST_STRING_FIELD_ALLOCATION(*ptr) += grow;
- (*pool_head)->used += ast_align_for(grow, ast_string_field_allocation);
- (*pool_head)->active += grow;
- }
-}
-
-void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
- struct ast_string_field_pool **pool_head,
- ast_string_field *ptr, const char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- __ast_string_field_ptr_build_va(mgr, pool_head, ptr, format, ap);
- va_end(ap);
-}
-
-void *__ast_calloc_with_stringfields(unsigned int num_structs, size_t struct_size, size_t field_mgr_offset,
- size_t field_mgr_pool_offset, size_t pool_size, const char *file,
- int lineno, const char *func)
-{
- struct ast_string_field_mgr *mgr;
- struct ast_string_field_pool *pool;
- struct ast_string_field_pool **pool_head;
- size_t pool_size_needed = sizeof(*pool) + pool_size;
- size_t size_to_alloc = optimal_alloc_size(struct_size + pool_size_needed);
- void *allocation;
- unsigned int x;
-
-#if defined(__AST_DEBUG_MALLOC)
- if (!(allocation = __ast_calloc(num_structs, size_to_alloc, file, lineno, func))) {
- return NULL;
- }
-#else
- if (!(allocation = ast_calloc(num_structs, size_to_alloc))) {
- return NULL;
- }
-#endif
-
- for (x = 0; x < num_structs; x++) {
- void *base = allocation + (size_to_alloc * x);
- const char **p;
-
- mgr = base + field_mgr_offset;
- pool_head = base + field_mgr_pool_offset;
- pool = base + struct_size;
-
- p = (const char **) pool_head + 1;
- while ((struct ast_string_field_mgr *) p != mgr) {
- *p++ = __ast_string_field_empty;
- }
-
- mgr->embedded_pool = pool;
- *pool_head = pool;
- pool->size = size_to_alloc - struct_size - sizeof(*pool);
-#if defined(__AST_DEBUG_MALLOC)
- mgr->owner_file = file;
- mgr->owner_func = func;
- mgr->owner_line = lineno;
-#endif
- }
-
- return allocation;
-}
-
-/* end of stringfields support */
-
AST_MUTEX_DEFINE_STATIC(fetchadd_m); /* used for all fetc&add ops */
int ast_atomic_fetchadd_int_slow(volatile int *p, int v)