From 4467ab62c857cd3c7bdaac3e75536aad7a13c7b8 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Thu, 26 Jan 2006 04:00:05 +0000 Subject: string field manager improvements: use multiple memory blocks, instead of realloc(), ensuring that field pointers will never become invalid or change don't run vs(n)printf twice when doing a field build unless required git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@8697 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- include/asterisk/stringfields.h | 53 +++++++++++++++----------- utils.c | 82 ++++++++++++++++++++++++----------------- 2 files changed, 81 insertions(+), 54 deletions(-) diff --git a/include/asterisk/stringfields.h b/include/asterisk/stringfields.h index 5631682b2..22e066d21 100644 --- a/include/asterisk/stringfields.h +++ b/include/asterisk/stringfields.h @@ -107,31 +107,40 @@ extern const char *__ast_string_field_empty; /*! \internal - \brief Structure used to manage the storage for a field pool + \brief Structure used to hold a pool of space for string fields */ struct ast_string_field_pool { - char *base; /*!< the address of the pool's base in memory */ - size_t size; /*!< the total size of the pool */ - size_t space; /*!< the space available in the pool */ - size_t used; /*!< the space used in the pool */ + struct ast_string_field_pool *prev; /*!< pointer to the previous pool, if any */ + char base[0]; /*!< storage space for the fields */ }; /*! \internal - \brief Initialize a field pool and fields - \param pool Pointer to the pool structure + \brief Structure used to manage the storage for a set of string fields +*/ +struct ast_string_field_mgr { + struct ast_string_field_pool *pool; /*!< the address of the pool's structure */ + size_t size; /*!< the total size of the current pool */ + size_t space; /*!< the space available in the current pool */ + size_t used; /*!< the space used in the current pool */ +}; + +/*! + \internal + \brief Initialize a field pool manager and fields + \param mgr Pointer to the pool manager structure \param size Amount of storage to allocate \param fields Pointer to the first entry of the field array \param num_fields Number of fields in the array \return 0 on failure, non-zero on success */ -int __ast_string_field_init(struct ast_string_field_pool *pool, size_t size, +int __ast_string_field_init(struct ast_string_field_mgr *mgr, size_t size, ast_string_field *fields, int num_fields); /*! \internal - \brief Allocate space for field in the pool - \param pool Pointer to the pool structure + \brief Allocate space for a field + \param mgr Pointer to the pool manager structure \param needed Amount of space needed for this field \param fields Pointer to the first entry of the field array \param num_fields Number of fields in the array @@ -139,24 +148,22 @@ int __ast_string_field_init(struct ast_string_field_pool *pool, size_t size, This function will allocate the requested amount of space from the field pool. If the requested amount of space is not available, - the pool will be expanded until enough space becomes available, - and the existing fields stored there will be updated to point - into the new pool. + an additional pool will be allocated. */ -ast_string_field __ast_string_field_alloc_space(struct ast_string_field_pool *pool, size_t needed, +ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, size_t needed, ast_string_field *fields, int num_fields); /*! \internal \brief Set a field to a complex (built) value - \param pool Pointer to the pool structure + \param mgr Pointer to the pool manager structure \param fields Pointer to the first entry of the field array \param num_fields Number of fields in the array \param index Index position of the field within the structure \param format printf-style format string \return nothing */ -void __ast_string_field_index_build(struct ast_string_field_pool *pool, +void __ast_string_field_index_build(struct ast_string_field_mgr *mgr, ast_string_field *fields, int num_fields, int index, const char *format, ...); @@ -179,7 +186,7 @@ void __ast_string_field_index_build(struct ast_string_field_pool *pool, ast_string_field __begin_field[0]; \ field_list \ ast_string_field __end_field[0]; \ - struct ast_string_field_pool __field_pool; + struct ast_string_field_mgr __field_mgr; /*! \brief Get the number of string fields in a structure @@ -205,7 +212,7 @@ void __ast_string_field_index_build(struct ast_string_field_pool *pool, \return 0 on failure, non-zero on success */ #define ast_string_field_init(x) \ - __ast_string_field_init(&x->__field_pool, AST_STRING_FIELD_DEFAULT_POOL, &x->__begin_field[0], ast_string_field_count(x)) + __ast_string_field_init(&x->__field_mgr, AST_STRING_FIELD_DEFAULT_POOL, &x->__begin_field[0], ast_string_field_count(x)) /*! \brief Set a field to a simple string value @@ -215,7 +222,7 @@ void __ast_string_field_index_build(struct ast_string_field_pool *pool, \return nothing */ #define ast_string_field_index_set(x, index, data) do { \ - if ((x->__begin_field[index] = __ast_string_field_alloc_space(&x->__field_pool, strlen(data) + 1, &x->__begin_field[0], ast_string_field_count(x)))) \ + if ((x->__begin_field[index] = __ast_string_field_alloc_space(&x->__field_mgr, strlen(data) + 1, &x->__begin_field[0], ast_string_field_count(x)))) \ strcpy((char *) x->__begin_field[index], data); \ } while (0) @@ -238,7 +245,7 @@ void __ast_string_field_index_build(struct ast_string_field_pool *pool, \return nothing */ #define ast_string_field_index_build(x, index, fmt, args...) \ - __ast_string_field_index_build(&x->__field_pool, &x->__begin_field[0], ast_string_field_count(x), index, fmt, args) + __ast_string_field_index_build(&x->__field_mgr, &x->__begin_field[0], ast_string_field_count(x), index, fmt, args) /*! \brief Set a field to a complex (built) value @@ -289,9 +296,13 @@ void __ast_string_field_index_build(struct ast_string_field_pool *pool, */ #define ast_string_field_free_all(x) do { \ int index; \ + struct ast_string_field_pool *this, *prev; \ for (index = 0; index < ast_string_field_count(x); index ++) \ ast_string_field_index_free(x, index); \ - free(x->__field_pool.base); \ + for (this = x->__field_mgr.pool; this; this = prev) { \ + prev = this->prev; \ + free(this); \ + } \ } while(0) #endif /* _ASTERISK_STRINGFIELDS_H */ diff --git a/utils.c b/utils.c index ef0246252..977f0cdd0 100644 --- a/utils.c +++ b/utils.c @@ -944,70 +944,86 @@ void ast_join(char *s, size_t len, char * const w[]) const char const *__ast_string_field_empty = ""; -int __ast_string_field_init(struct ast_string_field_pool *pool, size_t size, +static int add_string_pool(struct ast_string_field_mgr *mgr, size_t size) +{ + struct ast_string_field_pool *pool; + + if (!(pool = ast_calloc(1, sizeof(*pool) + size))) + return -1; + + pool->prev = mgr->pool; + mgr->pool = pool; + mgr->size = size; + mgr->space = size; + mgr->used = 0; + + return 0; +} + +int __ast_string_field_init(struct ast_string_field_mgr *mgr, size_t size, ast_string_field *fields, int num_fields) { int index; - pool->base = calloc(1, size); - if (pool->base) { - pool->size = size; - pool->space = size; - for (index = 0; index < num_fields; index++) - fields[index] = __ast_string_field_empty; - } - return pool->base ? 0 : -1; + if (add_string_pool(mgr, size)) + return -1; + + for (index = 0; index < num_fields; index++) + fields[index] = __ast_string_field_empty; + + return 0; } -ast_string_field __ast_string_field_alloc_space(struct ast_string_field_pool *pool, size_t needed, +ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, size_t needed, ast_string_field *fields, int num_fields) { char *result = NULL; - if (__builtin_expect(needed > pool->space, 0)) { - int index; - char *new_base; - size_t new_size = pool->size * 2; + if (__builtin_expect(needed > mgr->space, 0)) { + size_t new_size = mgr->size * 2; - while (new_size < (pool->used + needed)) + while (new_size < needed) new_size *= 2; - if (!(new_base = realloc(pool->base, new_size))) + if (add_string_pool(mgr, new_size)) return NULL; - - for (index = 0; index < num_fields; index++) { - if (fields[index] != __ast_string_field_empty) - fields[index] = new_base + (fields[index] - pool->base); - } - - pool->base = new_base; - pool->space += new_size - pool->size; - pool->size = new_size; } - result = pool->base + pool->used; - pool->used += needed; - pool->space -= needed; + result = mgr->pool->base + mgr->used; + mgr->used += needed; + mgr->space -= needed; return result; } -void __ast_string_field_index_build(struct ast_string_field_pool *pool, +void __ast_string_field_index_build(struct ast_string_field_mgr *mgr, ast_string_field *fields, int num_fields, int index, const char *format, ...) { - char s; size_t needed; va_list ap1, ap2; va_start(ap1, format); va_copy(ap2, ap1); - needed = vsnprintf(&s, 1, format, ap1) + 1; + needed = vsnprintf(mgr->pool->base + mgr->used, mgr->space, format, ap1) + 1; va_end(ap1); - if ((fields[index] = __ast_string_field_alloc_space(pool, needed, fields, num_fields))) - vsprintf((char *) fields[index], format, ap2); + if (needed > mgr->space) { + size_t new_size = mgr->size * 2; + + while (new_size < needed) + new_size *= 2; + + if (add_string_pool(mgr, new_size)) + return; + + vsprintf(mgr->pool->base + mgr->used, format, ap2); + } + + fields[index] = mgr->pool->base + mgr->used; + mgr->used += needed; + mgr->space -= needed; va_end(ap2); } -- cgit v1.2.3