mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-06 12:36:58 +00:00
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
This commit is contained in:
@@ -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 */
|
||||
|
78
utils.c
78
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;
|
||||
if (add_string_pool(mgr, size))
|
||||
return -1;
|
||||
|
||||
for (index = 0; index < num_fields; index++)
|
||||
fields[index] = __ast_string_field_empty;
|
||||
}
|
||||
return pool->base ? 0 : -1;
|
||||
|
||||
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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user