mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 02:37:10 +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 */ | ||||
|   | ||||
							
								
								
									
										82
									
								
								utils.c
									
									
									
									
									
								
							
							
						
						
									
										82
									
								
								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); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user