Merge "stringfields: Refactor to allow fields to be added to the end of structures" into 13

This commit is contained in:
Joshua Colp
2016-04-05 10:10:52 -05:00
committed by Gerrit Code Review
4 changed files with 908 additions and 471 deletions

View File

@@ -17,6 +17,7 @@
*/
/*! \file
\page Stringfields String Fields
\brief String fields in structures
This file contains objects and macros used to manage string
@@ -93,6 +94,80 @@
ast_free(x);
\endcode
A new feature "Extended String Fields" has been added in 13.9.0.
An extended field is one that is declared outside the AST_DECLARE_STRING_FIELDS
block but still inside the parent structure. It's most useful for extending
structures where adding a new string field to an existing AST_DECLARE_STRING_FIELDS
block would break ABI compatibility.
Example:
\code
struct original_structure_version {
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(foo);
AST_STRING_FIELD(bar);
);
int x1;
int x2;
};
\endcode
Adding "blah" to the existing string fields breaks ABI compatibility because it changes
the offsets of x1 and x2.
\code
struct new_structure_version {
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(foo);
AST_STRING_FIELD(bar);
AST_STRING_FIELD(blah);
);
int x1;
int x2;
};
\endcode
However, adding "blah" as an extended string field to the end of the structure doesn't break
ABI compatibility but still allows the use of the existing pool.
\code
struct new_structure_version {
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(foo);
AST_STRING_FIELD(bar);
);
int x1;
int x2;
AST_STRING_FIELD_EXTENDED(blah);
};
\endcode
The only additional step required is to call ast_string_field_init_extended so the
pool knows about the new field. It must be called AFTER ast_string_field_init or
ast_calloc_with_stringfields. Although ast_calloc_with_stringfields is used in the
sample below, it's not necessary for extended string fields.
\code
struct new_structure_version *x = ast_calloc_with_stringfields(1, struct new_structure_version, 252);
if (!x) {
return;
}
ast_string_field_init_extended(x, blah);
\endcode
The new field can now be treated just like any other string field and it's storage will
be released with the rest of the string fields.
\code
ast_string_field_set(x, foo, "infinite loop");
ast_stringfield_free_memory(x);
ast_free(x);
\endcode
This completes the API description.
*/
@@ -100,6 +175,7 @@
#define _ASTERISK_STRINGFIELDS_H
#include "asterisk/inline_api.h"
#include "asterisk/vector.h"
/*!
\internal
@@ -137,13 +213,30 @@ struct ast_string_field_pool {
char base[0] __attribute__((aligned(__alignof__(ast_string_field_allocation)))); /*!< storage space for the fields */
};
/*!
\internal
\brief The definition for the string field vector used for compare and copy
\since 13.9.0
*/
AST_VECTOR(ast_string_field_vector, const char **);
/*!
\internal
\brief Structure used to hold a pointer to the embedded pool and the field vector
\since 13.9.0
*/
struct ast_string_field_header {
struct ast_string_field_pool *embedded_pool; /*!< pointer to the embedded pool, if any */
struct ast_string_field_vector string_fields; /*!< field vector for compare and copy */
};
/*!
\internal
\brief Structure used to manage the storage for a set of string fields.
*/
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 */
struct ast_string_field_header *header; /*!< pointer to the header */
#if defined(__AST_DEBUG_MALLOC)
const char *owner_file; /*!< filename of owner */
const char *owner_func; /*!< function name of owner */
@@ -217,6 +310,29 @@ void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
*/
#define AST_STRING_FIELD(name) const ast_string_field name
/*!
\brief Declare an extended string field
\since 13.9.0
\param name The field name
*/
#define AST_STRING_FIELD_EXTENDED(name) AST_STRING_FIELD(name)
enum ast_stringfield_cleanup_type {
/*!
* Reset all string fields and free all extra pools that may have been created
* The allocation or structure can be reused as is.
*/
AST_STRINGFIELD_RESET = 0,
/*!
* Reset all string fields and free all pools.
* If the pointer was returned by ast_calloc_with_stringfields, it can NOT be reused
* and should be immediately freed. Otherwise, you must call ast_string_field_init
* again if you want to reuse it.
*/
AST_STRINGFIELD_DESTROY = -1,
};
/*!
\brief Declare the fields needed in a structure
\param field_list The list of fields to declare, using AST_STRING_FIELD() for each one.
@@ -239,17 +355,65 @@ void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
\brief Initialize a field pool and fields
\param x Pointer to a structure containing fields
\param size Amount of storage to allocate.
Use 0 to reset fields to the default value,
Use AST_STRINGFIELD_RESET to reset fields to the default value,
and release all but the most recent pool.
size<0 (used internally) means free all pools.
AST_STRINGFIELD_DESTROY (used internally) means free all pools which is
equivalent to calling ast_string_field_free_memory.
\return 0 on success, non-zero on failure
*/
#define ast_string_field_init(x, size) \
__ast_string_field_init(&(x)->__field_mgr, &(x)->__field_mgr_pool, size, __FILE__, __LINE__, __PRETTY_FUNCTION__)
({ \
int __res__ = -1; \
if (((void *)(x)) != NULL) { \
__res__ = __ast_string_field_init(&(x)->__field_mgr, &(x)->__field_mgr_pool, size, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
} \
__res__ ; \
})
/*! \brief free all memory - to be called before destroying the object */
#define ast_string_field_free_memory(x) \
__ast_string_field_init(&(x)->__field_mgr, &(x)->__field_mgr_pool, -1, __FILE__, __LINE__, __PRETTY_FUNCTION__)
/*!
* \brief free all memory - to be called before destroying the object
*
* \param x
*
*/
#define ast_string_field_free_memory(x) \
({ \
int __res__ = -1; \
if (((void *)(x)) != NULL) { \
__res__ = __ast_string_field_free_memory(&(x)->__field_mgr, &(x)->__field_mgr_pool, \
AST_STRINGFIELD_DESTROY, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
} \
__res__; \
})
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);
/*!
* \brief Initialize an extended string field
* \since 13.9.0
*
* \param x Pointer to a structure containing the field
* \param field The extended field to initialize
* \retval zero on success
* \retval non-zero on error
*
* \note
* This macro must be called on ALL fields defined with AST_STRING_FIELD_EXTENDED after
* ast_string_field_init has been called.
*/
#define ast_string_field_init_extended(x, field) \
({ \
int __res__ = -1; \
if (((void *)(x)) != NULL && (x)->__field_mgr.header != NULL) { \
ast_string_field *non_const = (ast_string_field *)&(x)->field; \
*non_const = __ast_string_field_empty; \
__res__ = AST_VECTOR_APPEND(&(x)->__field_mgr.header->string_fields, non_const); \
} \
__res__; \
})
/*!
* \internal
@@ -260,9 +424,10 @@ int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_
/*!
* \brief Allocate a structure with embedded stringfields in a single allocation
* \param n Number of structures to allocate (see ast_calloc)
* \param n Current imlementation only allows 1 structure to be allocated
* \param type The type of structure to allocate
* \param size The number of bytes of space (minimum) to allocate for stringfields to use
* in each structure
*
* 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
@@ -271,16 +436,16 @@ int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_
* \since 1.8
*/
#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__)
__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);
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
@@ -314,7 +479,14 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
\retval zero on success
\retval non-zero on error
*/
#define ast_string_field_ptr_set(x, ptr, data) ast_string_field_ptr_set_by_fields((x)->__field_mgr_pool, (x)->__field_mgr, ptr, data)
#define ast_string_field_ptr_set(x, ptr, data) \
({ \
int __res__ = -1; \
if (((void *)(x)) != NULL) { \
__res__ = ast_string_field_ptr_set_by_fields((x)->__field_mgr_pool, (x)->__field_mgr, ptr, data); \
} \
__res__; \
})
#define ast_string_field_ptr_set_by_fields(field_mgr_pool, field_mgr, ptr, data) \
({ \
@@ -348,7 +520,14 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
\retval zero on success
\retval non-zero on error
*/
#define ast_string_field_set(x, field, data) ast_string_field_ptr_set(x, &(x)->field, data)
#define ast_string_field_set(x, field, data) \
({ \
int __res__ = -1; \
if (((void *)(x)) != NULL) { \
__res__ = ast_string_field_ptr_set(x, &(x)->field, data); \
} \
__res__; \
})
/*!
\brief Set a field to a complex (built) value
@@ -359,7 +538,14 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
\return nothing
*/
#define ast_string_field_ptr_build(x, ptr, fmt, args...) \
__ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) ptr, fmt, args)
({ \
int __res__ = -1; \
if (((void *)(x)) != NULL) { \
__ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) ptr, fmt, args); \
__res__ = 0; \
} \
__res__; \
})
/*!
\brief Set a field to a complex (built) value
@@ -370,7 +556,14 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
\return nothing
*/
#define ast_string_field_build(x, field, fmt, args...) \
__ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args)
({ \
int __res__ = -1; \
if (((void *)(x)) != NULL) { \
__ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args); \
__res__ = 0; \
} \
__res__; \
})
/*!
\brief Set a field to a complex (built) value with prebuilt va_lists.
@@ -381,7 +574,14 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
\return nothing
*/
#define ast_string_field_ptr_build_va(x, ptr, fmt, args) \
__ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) ptr, fmt, args)
({ \
int __res__ = -1; \
if (((void *)(x)) != NULL) { \
__ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) ptr, fmt, args); \
__res__ = 0; \
} \
__res__; \
})
/*!
\brief Set a field to a complex (built) value
@@ -392,7 +592,14 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
\return nothing
*/
#define ast_string_field_build_va(x, field, fmt, args) \
__ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args)
({ \
int __res__ = -1; \
if (((void *)(x)) != NULL) { \
__ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args); \
__res__ = 0; \
} \
__res__; \
})
/*!
\brief Compare the string fields in two instances of the same structure
@@ -404,25 +611,16 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
*/
#define ast_string_fields_cmp(instance1, instance2) \
({ \
int __res__ = 0; \
size_t __ptr_size__ = sizeof(char *); \
int __len__ = ((void *)&(instance1)->__field_mgr - (void *)&(instance1)->__field_mgr_pool)/__ptr_size__ - 1; \
int __len2__ = ((void *)&(instance2)->__field_mgr - (void *)&(instance2)->__field_mgr_pool)/__ptr_size__ - 1; \
if (__len__ == __len2__) { \
char **__head1__ = (void *)&(instance1)->__field_mgr_pool + __ptr_size__; \
char **__head2__ = (void *)&(instance2)->__field_mgr_pool + __ptr_size__; \
for (__len__ -= 1; __len__ >= 0; __len__--) { \
__res__ = strcmp(__head1__[__len__], __head2__[__len__]); \
if (__res__) { \
break; \
} \
} \
} else { \
__res__ = -1; \
int __res__ = -1; \
if (((void *)(instance1)) != NULL && ((void *)(instance2)) != NULL) { \
__res__ = __ast_string_fields_cmp(&(instance1)->__field_mgr.header->string_fields, \
&(instance2)->__field_mgr.header->string_fields); \
} \
__res__; \
})
int __ast_string_fields_cmp(struct ast_string_field_vector *left, struct ast_string_field_vector *right);
/*!
\brief Copy all string fields from one instance to another of the same structure
\since 12
@@ -433,27 +631,16 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
*/
#define ast_string_fields_copy(copy, orig) \
({ \
int __outer_res__ = 0; \
size_t __ptr_size__ = sizeof(char *); \
int __len__ = ((void *)&(copy)->__field_mgr - (void *)&(copy)->__field_mgr_pool)/__ptr_size__ - 1; \
int __len2__ = ((void *)&(orig)->__field_mgr - (void *)&(orig)->__field_mgr_pool)/__ptr_size__ - 1; \
if (__len__ == __len2__) { \
ast_string_field *__copy_head__ = (void *)&(copy)->__field_mgr_pool + __ptr_size__; \
ast_string_field *__orig_head__ = (void *)&(orig)->__field_mgr_pool + __ptr_size__; \
for (__len2__ -= 1; __len2__ >= 0; __len2__--) { \
__ast_string_field_release_active((copy)->__field_mgr_pool, __copy_head__[__len2__]); \
__copy_head__[__len2__] = __ast_string_field_empty; \
} \
for (__len__ -= 1; __len__ >= 0; __len__--) { \
if (ast_string_field_ptr_set((copy), &__copy_head__[__len__], __orig_head__[__len__])) { \
__outer_res__ = -1; \
break; \
} \
} \
} else { \
__outer_res__ = -1; \
int __res__ = -1; \
if (((void *)(copy)) != NULL && ((void *)(orig)) != NULL) { \
__res__ = __ast_string_fields_copy(((copy)->__field_mgr_pool), \
(struct ast_string_field_mgr *)&((copy)->__field_mgr), \
(struct ast_string_field_mgr *)&((orig)->__field_mgr)); \
} \
__outer_res__; \
__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);
#endif /* _ASTERISK_STRINGFIELDS_H */