diff options
Diffstat (limited to 'main')
-rw-r--r-- | main/stringfields.c | 508 | ||||
-rw-r--r-- | main/utils.c | 371 |
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 e92f5c3d9..09839752b 100644 --- a/main/utils.c +++ b/main/utils.c @@ -61,9 +61,6 @@ ASTERISK_REGISTER_FILE() #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 @@ -2023,374 +2020,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) |