From 2746f589b7daee593cc4a64b2b8ddff5371a09a3 Mon Sep 17 00:00:00 2001
From: "Kevin P. Fleming" <kpfleming@digium.com>
Date: Tue, 5 May 2009 14:17:18 +0000
Subject: [PATCH] Add a more efficient way of allocating structures that use
 stringfields

This commit adds an API call that can be used to allocate a structure along with this stringfield storage in a single allocation.



git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@192362 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 include/asterisk/stringfields.h | 25 +++++++++++++++++
 main/utils.c                    | 49 +++++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+)

diff --git a/include/asterisk/stringfields.h b/include/asterisk/stringfields.h
index ca87b60ce5..38b7ef6c0b 100644
--- a/include/asterisk/stringfields.h
+++ b/include/asterisk/stringfields.h
@@ -138,6 +138,7 @@ struct ast_string_field_pool {
 */
 struct ast_string_field_mgr {
 	ast_string_field last_alloc;			/*!< the last field allocated */
+ 	struct ast_string_field_pool *embedded_pool;	/*!< pointer to the embedded pool, if any */
 #if defined(__AST_DEBUG_MALLOC)
 	const char *owner_file;				/*!< filename of owner */
 	const char *owner_func;				/*!< function name of owner */
@@ -253,6 +254,30 @@ void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
 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);
 
+/*!
+ * \brief Allocate a structure with embedded stringfields in a single allocation
+ * \param n Number of structures to allocate (see ast_calloc)
+ * \param type The type of structure to allocate
+ * \param size The number of bytes of space (minimum) to allocate for stringfields to use
+ *
+ * This function will allocate memory for one or more structures that use stringfields, and
+ * also allocate space for the stringfields and initialize the stringfield management
+ * structure embedded in the outer structure.
+ *
+ * \since 1.6.3
+ */
+#define ast_calloc_with_stringfields(n, type, size) \
+	__ast_calloc_with_stringfields(n, sizeof(type), offsetof(type, __field_mgr), offsetof(type, __field_mgr_pool), \
+				       size, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+/*!
+ * \internal
+ * \brief internal version of ast_calloc_with_stringfields
+ */
+void * attribute_malloc __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);
+
 /*!
   \internal
   \brief Release a field's allocation from a pool
diff --git a/main/utils.c b/main/utils.c
index 106667c3a0..e724160f40 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -1530,6 +1530,8 @@ static int add_string_pool(struct ast_string_field_mgr *mgr, struct ast_string_f
  * 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.
@@ -1559,6 +1561,9 @@ int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_
 
 	if (needed < 0) {		/* reset all pools */
 		/* nothing to do */
+	} 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");
@@ -1736,6 +1741,50 @@ void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
 	va_end(ap1);
 	va_end(ap2);
 }
+
+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);
+	}
+
+	return allocation;
+}
+
 /* end of stringfields support */
 
 AST_MUTEX_DEFINE_STATIC(fetchadd_m); /* used for all fetc&add ops */
-- 
GitLab