[asterisk-commits] rmudgett: branch rmudgett/ao2_enhancements r360760 - in /team/rmudgett/ao2_en...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Mar 28 22:13:20 CDT 2012
Author: rmudgett
Date: Wed Mar 28 22:13:16 2012
New Revision: 360760
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=360760
Log:
* Extracted hash container specific code into a virtual method table.
* Made hash container node store the external object pointer instead of
the internal pointer. The stored internal pointer was only used to
convert it back to the external pointer.
* Made the list container a formal API call instead of a macro.
* Made __ao2_link() and __ao2_link_debug() return 0/1 instead of
NULL/!NULL.
* Rename astobj2 API parameter funcname to func.
* Rename astobj2 API iterator parameter to iter.
* Update some documentation for OBJ_MULTIPLE.
Modified:
team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h
team/rmudgett/ao2_enhancements/main/astobj2.c
Modified: team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h?view=diff&rev=360760&r1=360759&r2=360760
==============================================================================
--- team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h (original)
+++ team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h Wed Mar 28 22:13:16 2012
@@ -462,7 +462,7 @@
#endif
void *__ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *tag,
- const char *file, int line, const char *funcname, int ref_debug);
+ const char *file, int line, const char *func, int ref_debug);
void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options);
/*! @} */
@@ -503,7 +503,7 @@
#endif
-int __ao2_ref_debug(void *o, int delta, const char *tag, const char *file, int line, const char *funcname);
+int __ao2_ref_debug(void *o, int delta, const char *tag, const char *file, int line, const char *func);
int __ao2_ref(void *o, int delta);
/*! @} */
@@ -1020,7 +1020,7 @@
unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn);
struct ao2_container *__ao2_container_alloc_debug(unsigned int options,
unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn,
- const char *tag, const char *file, int line, const char *funcname, int ref_debug);
+ const char *tag, const char *file, int line, const char *func, int ref_debug);
/*!
* \brief Allocate and initialize a hash container with the desired number of buckets.
@@ -1065,11 +1065,13 @@
#endif
-struct ao2_container *__ao2_container_alloc_hash(unsigned int ao2_options, unsigned int container_options,
- unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn);
-struct ao2_container *__ao2_container_alloc_hash_debug(unsigned int ao2_options, unsigned int container_options,
- unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
- const char *tag, const char *file, int line, const char *funcname, int ref_debug);
+struct ao2_container *__ao2_container_alloc_hash(unsigned int ao2_options,
+ unsigned int container_options, unsigned int n_buckets, ao2_hash_fn *hash_fn,
+ ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn);
+struct ao2_container *__ao2_container_alloc_hash_debug(unsigned int ao2_options,
+ unsigned int container_options, unsigned int n_buckets, ao2_hash_fn *hash_fn,
+ ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
+ const char *tag, const char *file, int line, const char *func, int ref_debug);
/*!
* \brief Allocate and initialize a list container.
@@ -1085,10 +1087,35 @@
* \note Destructor is set implicitly.
* \note Implemented as a degenerate hash table.
*/
+
+#if defined(REF_DEBUG)
+
#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag) \
- ao2_t_container_alloc_hash((ao2_options), (container_options), 1, NULL, (sort_fn), (cmp_fn), (tag))
+ __ao2_container_alloc_list_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn) \
- ao2_container_alloc_hash((ao2_options), (container_options), 1, NULL, (sort_fn), (cmp_fn))
+ __ao2_container_alloc_list_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+
+#elif defined(__AST_DEBUG_MALLOC)
+
+#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag) \
+ __ao2_container_alloc_list_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn) \
+ __ao2_container_alloc_list_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+
+#else
+
+#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag) \
+ __ao2_container_alloc_list((ao2_options), (container_options), (sort_fn), (cmp_fn))
+#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn) \
+ __ao2_container_alloc_list((ao2_options), (container_options), (sort_fn), (cmp_fn))
+
+#endif
+
+struct ao2_container *__ao2_container_alloc_list(unsigned int ao2_options,
+ unsigned int container_options, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn);
+struct ao2_container *__ao2_container_alloc_list_debug(unsigned int ao2_options,
+ unsigned int container_options, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
+ const char *tag, const char *file, int line, const char *func, int ref_debug);
/*!
* \brief Allocate and initialize a red-black tree container.
@@ -1131,7 +1158,7 @@
ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn);
struct ao2_container *__ao2_container_alloc_tree_debug(unsigned int ao2_options, unsigned int container_options,
ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
- const char *tag, const char *file, int line, const char *funcname, int ref_debug);
+ const char *tag, const char *file, int line, const char *func, int ref_debug);
/*! \brief
* Returns the number of elements in a container.
@@ -1172,7 +1199,7 @@
* \retval NULL on error.
*/
struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum search_flags flags);
-struct ao2_container *__ao2_container_clone_debug(struct ao2_container *orig, enum search_flags flags, const char *tag, const char *file, int line, const char *funcname, int ref_debug);
+struct ao2_container *__ao2_container_clone_debug(struct ao2_container *orig, enum search_flags flags, const char *tag, const char *file, int line, const char *func, int ref_debug);
#if defined(REF_DEBUG)
#define ao2_t_container_clone(orig, flags, tag) __ao2_container_clone_debug(orig, flags, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
@@ -1208,8 +1235,8 @@
* \param flags search_flags to control linking the object. (OBJ_NOLOCK)
* \param tag used for debugging.
*
- * \retval NULL on errors.
- * \retval newobj on success.
+ * \retval 0 on errors.
+ * \retval 1 on success.
*
* This function inserts an object in a container according its key.
*
@@ -1236,8 +1263,8 @@
#endif
-void *__ao2_link_debug(struct ao2_container *c, void *new_obj, int flags, const char *tag, const char *file, int line, const char *funcname);
-void *__ao2_link(struct ao2_container *c, void *newobj, int flags);
+int __ao2_link_debug(struct ao2_container *c, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func);
+int __ao2_link(struct ao2_container *c, void *obj_new, int flags);
/*!
* \brief Remove an object from a container
@@ -1275,7 +1302,7 @@
#endif
-void *__ao2_unlink_debug(struct ao2_container *c, void *obj, int flags, const char *tag, const char *file, int line, const char *funcname);
+void *__ao2_unlink_debug(struct ao2_container *c, void *obj, int flags, const char *tag, const char *file, int line, const char *func);
void *__ao2_unlink(struct ao2_container *c, void *obj, int flags);
@@ -1311,12 +1338,15 @@
* also used by ao2_callback).
* \param arg passed to the callback.
* \param tag used for debugging.
- * \return when OBJ_MULTIPLE is not included in the flags parameter,
- * the return value will be either the object found or NULL if no
- * no matching object was found. If OBJ_MULTIPLE is included,
- * the return value will be a pointer to an ao2_iterator object,
- * which must be destroyed with ao2_iterator_destroy() when the
- * caller no longer needs it.
+ *
+ * \retval NULL on failure or no matching object found.
+ *
+ * \retval object found if OBJ_MULTIPLE is not set in the flags
+ * parameter.
+ *
+ * \retval ao2_iterator pointer if OBJ_MULTIPLE is set in the
+ * flags parameter. The iterator must be destroyed with
+ * ao2_iterator_destroy() when the caller no longer needs it.
*
* If the function returns any objects, their refcount is incremented,
* and the caller is in charge of decrementing them once done.
@@ -1375,7 +1405,7 @@
void *__ao2_callback_debug(struct ao2_container *c, enum search_flags flags,
ao2_callback_fn *cb_fn, void *arg, const char *tag, const char *file, int line,
- const char *funcname);
+ const char *func);
void *__ao2_callback(struct ao2_container *c, enum search_flags flags, ao2_callback_fn *cb_fn, void *arg);
/*! @} */
@@ -1413,7 +1443,7 @@
void *__ao2_callback_data_debug(struct ao2_container *c, enum search_flags flags,
ao2_callback_data_fn *cb_fn, void *arg, void *data, const char *tag, const char *file,
- int line, const char *funcname);
+ int line, const char *func);
void *__ao2_callback_data(struct ao2_container *c, enum search_flags flags,
ao2_callback_data_fn *cb_fn, void *arg, void *data);
@@ -1437,7 +1467,7 @@
#endif
void *__ao2_find_debug(struct ao2_container *c, const void *arg, enum search_flags flags,
- const char *tag, const char *file, int line, const char *funcname);
+ const char *tag, const char *file, int line, const char *func);
void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags flags);
/*! \brief
@@ -1593,7 +1623,7 @@
/*!
* \brief Destroy a container iterator
*
- * \param i the iterator to destroy
+ * \param iter the iterator to destroy
*
* \retval none
*
@@ -1602,9 +1632,9 @@
*
*/
#if defined(TEST_FRAMEWORK)
-void ao2_iterator_destroy(struct ao2_iterator *i) __attribute__((noinline));
+void ao2_iterator_destroy(struct ao2_iterator *iter) __attribute__((noinline));
#else
-void ao2_iterator_destroy(struct ao2_iterator *i);
+void ao2_iterator_destroy(struct ao2_iterator *iter);
#endif
#ifdef REF_DEBUG
@@ -1618,8 +1648,8 @@
#endif
-void *__ao2_iterator_next_debug(struct ao2_iterator *a, const char *tag, const char *file, int line, const char *funcname);
-void *__ao2_iterator_next(struct ao2_iterator *a);
+void *__ao2_iterator_next_debug(struct ao2_iterator *iter, const char *tag, const char *file, int line, const char *func);
+void *__ao2_iterator_next(struct ao2_iterator *iter);
/* extra functions */
void ao2_bt(void); /* backtrace */
Modified: team/rmudgett/ao2_enhancements/main/astobj2.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/ao2_enhancements/main/astobj2.c?view=diff&rev=360760&r1=360759&r2=360760
==============================================================================
--- team/rmudgett/ao2_enhancements/main/astobj2.c (original)
+++ team/rmudgett/ao2_enhancements/main/astobj2.c Wed Mar 28 22:13:16 2012
@@ -154,11 +154,6 @@
return p;
}
-
-enum ao2_callback_type {
- DEFAULT,
- WITH_DATA,
-};
/*!
* \brief convert from a pointer _p to an astobj2 object
@@ -414,7 +409,7 @@
return NULL;
}
-static int internal_ao2_ref(void *user_data, int delta, const char *file, int line, const char *funcname)
+static int internal_ao2_ref(void *user_data, int delta, const char *file, int line, const char *func)
{
struct astobj2 *obj = INTERNAL_OBJ(user_data);
struct astobj2_lock *obj_mutex;
@@ -446,7 +441,7 @@
/* this case must never happen */
if (current_value < 0) {
- ast_log(__LOG_ERROR, file, line, funcname,
+ ast_log(__LOG_ERROR, file, line, func,
"Invalid refcount %d on ao2 object %p\n", current_value, user_data);
}
@@ -495,7 +490,7 @@
ast_free(obj);
break;
default:
- ast_log(__LOG_ERROR, file, line, funcname,
+ ast_log(__LOG_ERROR, file, line, func,
"Invalid lock option on ao2 object %p\n", user_data);
break;
}
@@ -503,7 +498,7 @@
return ret;
}
-int __ao2_ref_debug(void *user_data, int delta, const char *tag, const char *file, int line, const char *funcname)
+int __ao2_ref_debug(void *user_data, int delta, const char *tag, const char *file, int line, const char *func)
{
struct astobj2 *obj = INTERNAL_OBJ(user_data);
@@ -514,18 +509,18 @@
FILE *refo = fopen(REF_FILE, "a");
if (refo) {
fprintf(refo, "%p %s%d %s:%d:%s (%s) [@%d]\n", user_data, (delta < 0 ? "" : "+"),
- delta, file, line, funcname, tag, obj ? obj->priv_data.ref_counter : -1);
+ delta, file, line, func, tag, obj ? obj->priv_data.ref_counter : -1);
fclose(refo);
}
}
if (obj->priv_data.ref_counter + delta == 0 && obj->priv_data.destructor_fn != NULL) { /* this isn't protected with lock; just for o/p */
FILE *refo = fopen(REF_FILE, "a");
if (refo) {
- fprintf(refo, "%p **call destructor** %s:%d:%s (%s)\n", user_data, file, line, funcname, tag);
+ fprintf(refo, "%p **call destructor** %s:%d:%s (%s)\n", user_data, file, line, func, tag);
fclose(refo);
}
}
- return internal_ao2_ref(user_data, delta, file, line, funcname);
+ return internal_ao2_ref(user_data, delta, file, line, func);
}
int __ao2_ref(void *user_data, int delta)
@@ -538,7 +533,7 @@
return internal_ao2_ref(user_data, delta, __FILE__, __LINE__, __FUNCTION__);
}
-static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *file, int line, const char *funcname)
+static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *file, int line, const char *func)
{
/* allocation */
struct astobj2 *obj;
@@ -556,7 +551,7 @@
switch (options & AO2_ALLOC_OPT_LOCK_MASK) {
case AO2_ALLOC_OPT_LOCK_MUTEX:
#if defined(__AST_DEBUG_MALLOC)
- obj_mutex = __ast_calloc(1, sizeof(*obj_mutex) + data_size, file, line, funcname);
+ obj_mutex = __ast_calloc(1, sizeof(*obj_mutex) + data_size, file, line, func);
#else
obj_mutex = ast_calloc(1, sizeof(*obj_mutex) + data_size);
#endif
@@ -569,7 +564,7 @@
break;
case AO2_ALLOC_OPT_LOCK_RWLOCK:
#if defined(__AST_DEBUG_MALLOC)
- obj_rwlock = __ast_calloc(1, sizeof(*obj_rwlock) + data_size, file, line, funcname);
+ obj_rwlock = __ast_calloc(1, sizeof(*obj_rwlock) + data_size, file, line, func);
#else
obj_rwlock = ast_calloc(1, sizeof(*obj_rwlock) + data_size);
#endif
@@ -582,7 +577,7 @@
break;
case AO2_ALLOC_OPT_LOCK_NOLOCK:
#if defined(__AST_DEBUG_MALLOC)
- obj = __ast_calloc(1, sizeof(*obj) + data_size, file, line, funcname);
+ obj = __ast_calloc(1, sizeof(*obj) + data_size, file, line, func);
#else
obj = ast_calloc(1, sizeof(*obj) + data_size);
#endif
@@ -592,7 +587,7 @@
break;
default:
/* Invalid option value. */
- ast_log(__LOG_DEBUG, file, line, funcname, "Invalid lock option requested\n");
+ ast_log(__LOG_DEBUG, file, line, func, "Invalid lock option requested\n");
return NULL;
}
@@ -614,18 +609,18 @@
}
void *__ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *tag,
- const char *file, int line, const char *funcname, int ref_debug)
+ const char *file, int line, const char *func, int ref_debug)
{
/* allocation */
void *obj;
FILE *refo;
- if ((obj = internal_ao2_alloc(data_size, destructor_fn, options, file, line, funcname)) == NULL) {
+ if ((obj = internal_ao2_alloc(data_size, destructor_fn, options, file, line, func)) == NULL) {
return NULL;
}
if (ref_debug && (refo = fopen(REF_FILE, "a"))) {
- fprintf(refo, "%p =1 %s:%d:%s (%s)\n", obj, file, line, funcname, tag);
+ fprintf(refo, "%p =1 %s:%d:%s (%s)\n", obj, file, line, func, tag);
fclose(refo);
}
@@ -712,11 +707,167 @@
}
-/* internal callback to destroy a container. */
-static void container_destruct(void *c);
-
-/* internal callback to destroy a container. */
-static void container_destruct_debug(void *c);
+/* BUGBUG may not be needed */
+enum ao2_container_type {
+ AO2_CONTAINER_TYPE_HASH,
+ AO2_CONTAINER_TYPE_LIST = 0,/* This is a degenerate hash container. */
+ AO2_CONTAINER_TYPE_TREE,
+};
+
+enum ao2_callback_type {
+ DEFAULT,
+ WITH_DATA,
+};
+
+/*!
+ * \brief Destroy this container.
+ *
+ * \param self Container to operate upon.
+ *
+ * \return Nothing
+ */
+typedef void (*ao2_container_destroy_fn)(struct ao2_container *self);
+
+/*!
+ * \brief Create an empty copy of this container.
+ *
+ * \param self Container to operate upon.
+ *
+ * \retval empty-container on success.
+ * \retval NULL on error.
+ */
+typedef struct ao2_container *(*ao2_container_alloc_empty_clone_fn)(struct ao2_container *self);
+
+/*!
+ * \brief Create an empty copy of this container. (Debug version)
+ *
+ * \param self Container to operate upon.
+ * \param tag used for debugging.
+ * \param file Debug file name invoked from
+ * \param line Debug line invoked from
+ * \param func Debug function name invoked from
+ * \param ref_debug TRUE if to output a debug reference message.
+ *
+ * \retval empty-container on success.
+ * \retval NULL on error.
+ */
+typedef struct ao2_container *(*ao2_container_alloc_empty_clone_debug_fn)(struct ao2_container *self, const char *tag, const char *file, int line, const char *func, int ref_debug);
+
+/*!
+ * \brief Link an object into this container.
+ *
+ * \param self Container to operate upon.
+ * \param obj_new Object to insert into the container.
+ * \param flags search_flags to control linking the object. (OBJ_NOLOCK)
+ * \param tag used for debugging.
+ * \param file Debug file name invoked from
+ * \param line Debug line invoked from
+ * \param func Debug function name invoked from
+ *
+ * \retval 0 on errors.
+ * \retval 1 on success.
+ */
+typedef int (*ao2_container_link_fn)(struct ao2_container *self, void *obj_new, enum search_flags flags, const char *tag, const char *file, int line, const char *func);
+
+/*!
+ * \brief Traverse the container.
+ *
+ * \param self Container to operate upon.
+ * \param flags search_flags to control traversing the container
+ * \param cb_fn Comparison callback function.
+ * \param arg Comparison callback arg parameter.
+ * \param data Data comparison callback data parameter.
+ * \param type Type of comparison callback cb_fn.
+ * \param tag used for debugging.
+ * \param file Debug file name invoked from
+ * \param line Debug line invoked from
+ * \param func Debug function name invoked from
+ *
+ * \retval NULL on failure or no matching object found.
+ *
+ * \retval object found if OBJ_MULTIPLE is not set in the flags
+ * parameter.
+ *
+ * \retval ao2_iterator pointer if OBJ_MULTIPLE is set in the
+ * flags parameter. The iterator must be destroyed with
+ * ao2_iterator_destroy() when the caller no longer needs it.
+ */
+typedef void *(*ao2_container_traverse_fn)(struct ao2_container *self, enum search_flags flags, void *cb_fn, void *arg, void *data, enum ao2_callback_type type, const char *tag, const char *file, int line, const char *func);
+
+/*!
+ * \internal
+ * \brief Find the next iteration element in the container.
+ *
+ * \param self Container to operate upon.
+ * \param iter The iterator to operate upon
+ * \param tag used for debugging.
+ * \param file Debug file name invoked from
+ * \param line Debug line invoked from
+ * \param func Debug function name invoked from
+ *
+ * \note The iterator container is already locked.
+ *
+ * \retval next-object on success.
+ * \retval NULL on error or no more elements in the container.
+ */
+typedef void *(*ao2_iterator_next_fn)(struct ao2_container *self, struct ao2_iterator *iter, const char *tag, const char *file, int line, const char *func);
+
+/*! Container virtual methods template. */
+struct container_methods {
+ /*! Destroy this container. */
+ ao2_container_destroy_fn destroy;
+ /*! \brief Create an empty copy of this container. */
+ ao2_container_alloc_empty_clone_fn alloc_empty_clone;
+ /*! \brief Create an empty copy of this container. (Debug version) */
+ ao2_container_alloc_empty_clone_debug_fn alloc_empty_clone_debug;
+ /*! Link an object into this container. */
+ ao2_container_link_fn link;
+ /*! Traverse the container. */
+ ao2_container_traverse_fn traverse;
+ /*! Find the next iteration element in the container. */
+ ao2_iterator_next_fn iterator_next;
+};
+
+/*!
+ * \brief Generic container type.
+ *
+ * \details This is the base container type that contains values
+ * common to all container types.
+ *
+ * \todo Linking and unlinking container objects is typically
+ * expensive, as it involves a malloc()/free() of a small object
+ * which is very inefficient. To optimize this, we can allocate
+ * larger arrays of container nodes when we run out of them, and
+ * then manage our own freelist. This will be more efficient as
+ * we can do the freelist management while we hold the lock
+ * (that we need anyway).
+ */
+struct ao2_container {
+ /*! Container virtual method table. */
+ const struct container_methods *v_table;
+ /*! Container sort function if the container is sorted. */
+ ao2_sort_fn *sort_fn;
+ /*! Container traversal matching function for ao2_find. */
+ ao2_callback_fn *cmp_fn;
+ /*! The container option flags */
+ uint32_t options;
+ /*! Number of elements in the container. */
+ int elements;
+ /*! Type of container. BUGBUG may not be needed. */
+ enum ao2_container_type type;
+ /*!
+ * \brief TRUE if the container is being destroyed.
+ *
+ * \note The destruction traversal should override any requested
+ * search order to do the most efficient order for destruction.
+ *
+ * \note There should not be any empty nodes in the container
+ * during destruction. If there are then an error needs to be
+ * issued about container node reference leaks. Someone forgot
+ * to call ao2_iterator_destroy() somewhere.
+ */
+ unsigned int destroying:1;
+};
/*!
* A structure to create a linked list of entries,
@@ -725,41 +876,37 @@
*/
struct bucket_entry {
AST_LIST_ENTRY(bucket_entry) entry;
+ /*! Stored object in node. */
+ void *obj;
int version;
- struct astobj2 *astobj;/* pointer to internal data */
};
+/*! BUGBUG change to a doubly linked list to support traverse order options and ref counted nodes. */
/* each bucket in the container is a tailq. */
AST_LIST_HEAD_NOLOCK(bucket, bucket_entry);
/*!
- * A container; stores the hash and callback functions, information on
- * the size, the hash bucket heads, and a version number, starting at 0
- * (for a newly created, empty container)
- * and incremented every time an object is inserted or deleted.
- * The assumption is that an object is never moved in a container,
- * but removed and readded with the new number.
- * The version number is especially useful when implementing iterators.
- * In fact, we can associate a unique, monotonically increasing number to
- * each object, which means that, within an iterator, we can store the
- * version number of the current object, and easily look for the next one,
- * which is the next one in the list with a higher number.
- * Since all objects have a version >0, we can use 0 as a marker for
- * 'we need the first object in the bucket'.
- *
- * \todo Linking and unlink objects is typically expensive, as it
- * involves a malloc() of a small object which is very inefficient.
- * To optimize this, we allocate larger arrays of bucket_entry's
- * when we run out of them, and then manage our own freelist.
- * This will be more efficient as we can do the freelist management while
- * we hold the lock (that we need anyways).
- */
-struct ao2_container {
+ * A hash container in addition to values common to all
+ * container types, stores the hash callback function,
+ * information on the number of hash buckets, the hash bucket
+ * heads, and a version number, starting at 0 (for a newly
+ * created, empty container) and incremented every time an
+ * object is inserted or deleted. The assumption is that an
+ * object is never moved in a container, but removed and readded
+ * with the new number. The version number is especially useful
+ * when implementing iterators. In fact, we can associate a
+ * unique, monotonically increasing number to each object, which
+ * means that, within an iterator, we can store the version
+ * number of the current object, and easily look for the next
+ * one, which is the next one in the list with a higher number.
+ * Since all objects have a version >0, we can use 0 as a marker
+ * for 'we need the first object in the bucket'.
+ */
+struct ao2_container_hash {
+ struct ao2_container common;
+/*! BUGBUG struct ao2_container_hash need to convert to ref counted nodes */
ao2_hash_fn *hash_fn;
- ao2_callback_fn *cmp_fn;
int n_buckets;
- /*! Number of elements in the container */
- int elements;
/*! described above */
int version;
/*! variable size */
@@ -767,70 +914,6 @@
};
/*!
- * \brief always zero hash function
- *
- * it is convenient to have a hash function that always returns 0.
- * This is basically used when we want to have a container that is
- * a simple linked list.
- *
- * \returns 0
- */
-static int hash_zero(const void *user_obj, const int flags)
-{
- return 0;
-}
-
-/*
- * A container is just an object, after all!
- */
-static struct ao2_container *internal_ao2_container_alloc(struct ao2_container *c,
- unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn)
-{
- /* XXX maybe consistency check on arguments ? */
- /* compute the container size */
-
- if (!c) {
- return NULL;
- }
-
- c->version = 1; /* 0 is a reserved value here */
- c->n_buckets = hash_fn ? n_buckets : 1;
- c->hash_fn = hash_fn ? hash_fn : hash_zero;
- c->cmp_fn = cmp_fn;
-
-#ifdef AO2_DEBUG
- ast_atomic_fetchadd_int(&ao2.total_containers, 1);
-#endif
-
- return c;
-}
-
-struct ao2_container *__ao2_container_alloc_debug(unsigned int options,
- unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn,
- const char *tag, const char *file, int line, const char *funcname, int ref_debug)
-{
- /* XXX maybe consistency check on arguments ? */
- /* compute the container size */
- unsigned int num_buckets = hash_fn ? n_buckets : 1;
- size_t container_size = sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket);
- struct ao2_container *c = __ao2_alloc_debug(container_size, container_destruct_debug, options, tag, file, line, funcname, ref_debug);
-
- return internal_ao2_container_alloc(c, num_buckets, hash_fn, cmp_fn);
-}
-
-struct ao2_container *__ao2_container_alloc(unsigned int options,
- unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn)
-{
- /* XXX maybe consistency check on arguments ? */
- /* compute the container size */
- const unsigned int num_buckets = hash_fn ? n_buckets : 1;
- size_t container_size = sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket);
- struct ao2_container *c = __ao2_alloc(container_size, container_destruct, options);
-
- return internal_ao2_container_alloc(c, num_buckets, hash_fn, cmp_fn);
-}
-
-/*!
* return the number of elements in the container
*/
int ao2_container_count(struct ao2_container *c)
@@ -841,25 +924,20 @@
/*
* link an object to a container
*/
-static struct bucket_entry *internal_ao2_link(struct ao2_container *c, void *user_data, int flags, const char *tag, const char *file, int line, const char *funcname)
+static int hash_ao2_link(struct ao2_container_hash *c, void *user_data, int flags, const char *tag, const char *file, int line, const char *func)
{
int i;
enum ao2_lock_req orig_lock;
/* create a new list entry */
struct bucket_entry *p;
- struct astobj2 *obj = INTERNAL_OBJ(user_data);
-
- if (obj == NULL) {
- return NULL;
- }
-
- if (INTERNAL_OBJ(c) == NULL) {
- return NULL;
- }
+/*! BUGBUG hash_ao2_link() need to convert to ref counted nodes */
+/*! BUGBUG hash_ao2_link() need to add sorting support */
+/*! BUGBUG hash_ao2_link() need to add insert option support */
+/*! BUGBUG hash_ao2_link() need to add duplicate handling option support */
p = ast_calloc(1, sizeof(*p));
if (!p) {
- return NULL;
+ return 0;
}
i = abs(c->hash_fn(user_data, OBJ_POINTER));
@@ -872,13 +950,13 @@
}
i %= c->n_buckets;
- p->astobj = obj;
+ p->obj = user_data;
p->version = ast_atomic_fetchadd_int(&c->version, 1);
AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
- ast_atomic_fetchadd_int(&c->elements, 1);
+ ast_atomic_fetchadd_int(&c->common.elements, 1);
if (tag) {
- __ao2_ref_debug(user_data, +1, tag, file, line, funcname);
+ __ao2_ref_debug(user_data, +1, tag, file, line, func);
} else {
__ao2_ref(user_data, +1);
}
@@ -889,17 +967,25 @@
ao2_unlock(c);
}
- return p;
-}
-
-void *__ao2_link_debug(struct ao2_container *c, void *new_obj, int flags, const char *tag, const char *file, int line, const char *funcname)
-{
- return internal_ao2_link(c, new_obj, flags, tag, file, line, funcname);
-}
-
-void *__ao2_link(struct ao2_container *c, void *new_obj, int flags)
-{
- return internal_ao2_link(c, new_obj, flags, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__);
+ return 1;
+}
+
+int __ao2_link_debug(struct ao2_container *c, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func)
+{
+ if (!INTERNAL_OBJ(obj_new) || !INTERNAL_OBJ(c) || !c->v_table || !c->v_table->link) {
+ /* Sanity checks. */
+ return 0;
+ }
+ return c->v_table->link(c, obj_new, flags, tag, file, line, func);
+}
+
+int __ao2_link(struct ao2_container *c, void *obj_new, int flags)
+{
+ if (!INTERNAL_OBJ(obj_new) || !INTERNAL_OBJ(c) || !c->v_table || !c->v_table->link) {
+ /* Sanity checks. */
+ return 0;
+ }
+ return c->v_table->link(c, obj_new, flags, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__);
}
/*!
@@ -915,21 +1001,23 @@
* and destroy the associated * bucket_entry structure.
*/
void *__ao2_unlink_debug(struct ao2_container *c, void *user_data, int flags,
- const char *tag, const char *file, int line, const char *funcname)
-{
- if (INTERNAL_OBJ(user_data) == NULL) { /* safety check on the argument */
+ const char *tag, const char *file, int line, const char *func)
+{
+ if (!INTERNAL_OBJ(user_data)) {
+ /* Sanity checks. */
return NULL;
}
flags |= (OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA);
- __ao2_callback_debug(c, flags, ao2_match_by_addr, user_data, tag, file, line, funcname);
+ __ao2_callback_debug(c, flags, ao2_match_by_addr, user_data, tag, file, line, func);
return NULL;
}
void *__ao2_unlink(struct ao2_container *c, void *user_data, int flags)
{
- if (INTERNAL_OBJ(user_data) == NULL) { /* safety check on the argument */
+ if (!INTERNAL_OBJ(user_data)) {
+ /* Sanity checks. */
return NULL;
}
@@ -959,13 +1047,13 @@
* Browse the container using different stategies accoding the flags.
* \return Is a pointer to an object or to a list of object if OBJ_MULTIPLE is
* specified.
- * Luckily, for debug purposes, the added args (tag, file, line, funcname)
+ * Luckily, for debug purposes, the added args (tag, file, line, func)
* aren't an excessive load to the system, as the callback should not be
* called as often as, say, the ao2_ref func is called.
*/
-static void *internal_ao2_callback(struct ao2_container *c, enum search_flags flags,
+static void *hash_ao2_callback(struct ao2_container_hash *c, enum search_flags flags,
void *cb_fn, void *arg, void *data, enum ao2_callback_type type, const char *tag,
- const char *file, int line, const char *funcname)
+ const char *file, int line, const char *func)
{
int i, start, last; /* search boundaries */
enum ao2_lock_req orig_lock;
@@ -975,10 +1063,9 @@
struct ao2_container *multi_container = NULL;
struct ao2_iterator *multi_iterator = NULL;
- if (INTERNAL_OBJ(c) == NULL) { /* safety check on the argument */
- return NULL;
- }
-
+/*! BUGBUG hash_ao2_callback() need to convert to ref counted nodes */
+/*! BUGBUG hash_ao2_callback() need to add sorting support */
+/*! BUGBUG hash_ao2_callback() need to add traverse order option support */
/*
* This logic is used so we can support OBJ_MULTIPLE with OBJ_NODATA
* turned off. This if statement checks for the special condition
@@ -992,7 +1079,8 @@
* is destroyed, the container will be automatically
* destroyed as well.
*/
- multi_container = __ao2_container_alloc(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL);
+ multi_container = __ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL,
+ NULL);
if (!multi_container) {
return NULL;
}
@@ -1067,9 +1155,9 @@
int match = (CMP_MATCH | CMP_STOP);
if (type == WITH_DATA) {
- match &= cb_withdata(EXTERNAL_OBJ(cur->astobj), arg, data, flags);
+ match &= cb_withdata(cur->obj, arg, data, flags);
} else {
- match &= cb_default(EXTERNAL_OBJ(cur->astobj), arg, flags);
+ match &= cb_default(cur->obj, arg, flags);
}
/* we found the object, performing operations according flags */
@@ -1083,12 +1171,13 @@
/* we have a match (CMP_MATCH) here */
if (!(flags & OBJ_NODATA)) { /* if must return the object, record the value */
/* it is important to handle this case before the unlink */
- ret = EXTERNAL_OBJ(cur->astobj);
+ ret = cur->obj;
if (!(flags & (OBJ_UNLINK | OBJ_MULTIPLE))) {
- if (tag)
- __ao2_ref_debug(ret, 1, tag, file, line, funcname);
- else
+ if (tag) {
+ __ao2_ref_debug(ret, 1, tag, file, line, func);
+ } else {
__ao2_ref(ret, 1);
+ }
}
}
@@ -1097,7 +1186,7 @@
*/
if (ret && (multi_container != NULL)) {
if (tag) {
- __ao2_link_debug(multi_container, ret, flags, tag, file, line, funcname);
+ __ao2_link_debug(multi_container, ret, flags, tag, file, line, func);
} else {
__ao2_link(multi_container, ret, flags);
}
@@ -1109,7 +1198,7 @@
ast_atomic_fetchadd_int(&c->version, 1);
AST_LIST_REMOVE_CURRENT(entry);
/* update number of elements */
- ast_atomic_fetchadd_int(&c->elements, -1);
+ ast_atomic_fetchadd_int(&c->common.elements, -1);
/* - When unlinking and not returning the result, (OBJ_NODATA), the ref from the container
* must be decremented.
@@ -1118,10 +1207,11 @@
* returned in a new container that already holds its own ref for the object. If the ref
* from the original container is not accounted for here a memory leak occurs. */
if (flags & (OBJ_NODATA | OBJ_MULTIPLE)) {
- if (tag)
- __ao2_ref_debug(EXTERNAL_OBJ(cur->astobj), -1, tag, file, line, funcname);
- else
- __ao2_ref(EXTERNAL_OBJ(cur->astobj), -1);
+ if (tag) {
+ __ao2_ref_debug(cur->obj, -1, tag, file, line, func);
+ } else {
+ __ao2_ref(cur->obj, -1);
+ }
}
ast_free(cur); /* free the link record */
}
@@ -1165,39 +1255,55 @@
void *__ao2_callback_debug(struct ao2_container *c, enum search_flags flags,
ao2_callback_fn *cb_fn, void *arg, const char *tag, const char *file, int line,
- const char *funcname)
-{
- return internal_ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, tag, file, line, funcname);
+ const char *func)
+{
+ if (!INTERNAL_OBJ(c) || !c->v_table || !c->v_table->traverse) {
+ /* Sanity checks. */
+ return NULL;
+ }
+ return c->v_table->traverse(c, flags, cb_fn, arg, NULL, DEFAULT, tag, file, line, func);
}
void *__ao2_callback(struct ao2_container *c, enum search_flags flags,
ao2_callback_fn *cb_fn, void *arg)
{
- return internal_ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, NULL, NULL, 0, NULL);
+ if (!INTERNAL_OBJ(c) || !c->v_table || !c->v_table->traverse) {
+ /* Sanity checks. */
+ return NULL;
+ }
+ return c->v_table->traverse(c, flags, cb_fn, arg, NULL, DEFAULT, NULL, NULL, 0, NULL);
}
void *__ao2_callback_data_debug(struct ao2_container *c, enum search_flags flags,
ao2_callback_data_fn *cb_fn, void *arg, void *data, const char *tag, const char *file,
- int line, const char *funcname)
-{
- return internal_ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, tag, file, line, funcname);
+ int line, const char *func)
+{
+ if (!INTERNAL_OBJ(c) || !c->v_table || !c->v_table->traverse) {
+ /* Sanity checks. */
+ return NULL;
+ }
+ return c->v_table->traverse(c, flags, cb_fn, arg, data, WITH_DATA, tag, file, line, func);
}
void *__ao2_callback_data(struct ao2_container *c, enum search_flags flags,
ao2_callback_data_fn *cb_fn, void *arg, void *data)
{
- return internal_ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, NULL, NULL, 0, NULL);
+ if (!INTERNAL_OBJ(c) || !c->v_table || !c->v_table->traverse) {
+ /* Sanity checks. */
+ return NULL;
+ }
+ return c->v_table->traverse(c, flags, cb_fn, arg, data, WITH_DATA, NULL, NULL, 0, NULL);
}
/*!
* the find function just invokes the default callback with some reasonable flags.
*/
void *__ao2_find_debug(struct ao2_container *c, const void *arg, enum search_flags flags,
- const char *tag, const char *file, int line, const char *funcname)
+ const char *tag, const char *file, int line, const char *func)
{
void *arged = (void *) arg;/* Done to avoid compiler const warning */
- return __ao2_callback_debug(c, flags, c->cmp_fn, arged, tag, file, line, funcname);
+ return __ao2_callback_debug(c, flags, c->cmp_fn, arged, tag, file, line, func);
}
void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags flags)
@@ -1225,59 +1331,204 @@
/*!
* destroy an iterator
*/
-void ao2_iterator_destroy(struct ao2_iterator *i)
-{
- ao2_ref(i->c, -1);
- if (i->flags & AO2_ITERATOR_MALLOCD) {
- ast_free(i);
+void ao2_iterator_destroy(struct ao2_iterator *iter)
+{
+ ao2_ref(iter->c, -1);
+ if (iter->flags & AO2_ITERATOR_MALLOCD) {
+ ast_free(iter);
} else {
- i->c = NULL;
+ iter->c = NULL;
}
}
/*
* move to the next element in the container.
*/
-static void *internal_ao2_iterator_next(struct ao2_iterator *a, const char *tag, const char *file, int line, const char *funcname)
+static void *internal_ao2_iterator_next(struct ao2_iterator *iter, const char *tag, const char *file, int line, const char *func)
+{
+ enum ao2_lock_req orig_lock;
+ void *ret;
+
+ if (!INTERNAL_OBJ(iter->c) || !iter->c->v_table || !iter->c->v_table->iterator_next) {
+ /* Sanity checks. */
+ return NULL;
+ }
+
+ if (iter->flags & AO2_ITERATOR_DONTLOCK) {
+ if (iter->flags & AO2_ITERATOR_UNLINK) {
+ orig_lock = adjust_lock(iter->c, AO2_LOCK_REQ_WRLOCK, 1);
+ } else {
+ orig_lock = adjust_lock(iter->c, AO2_LOCK_REQ_RDLOCK, 1);
+ }
+ } else {
+ orig_lock = AO2_LOCK_REQ_MUTEX;
+ if (iter->flags & AO2_ITERATOR_UNLINK) {
+ ao2_wrlock(iter->c);
+ } else {
+ ao2_rdlock(iter->c);
+ }
+ }
+
+ ret = iter->c->v_table->iterator_next(iter->c, iter, tag, file, line, func);
+
+ if (iter->flags & AO2_ITERATOR_DONTLOCK) {
+ adjust_lock(iter->c, orig_lock, 0);
+ } else {
+ ao2_unlock(iter->c);
+ }
+
+ return ret;
+}
+
+void *__ao2_iterator_next_debug(struct ao2_iterator *iter, const char *tag, const char *file, int line, const char *func)
+{
+ return internal_ao2_iterator_next(iter, tag, file, line, func);
+}
+
+void *__ao2_iterator_next(struct ao2_iterator *iter)
+{
+ return internal_ao2_iterator_next(iter, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__);
+}
+
+static void container_destruct(void *_c)
+{
+ struct ao2_container *c = _c;
+
+ /* Unlink any stored objects in the container. */
+ c->destroying = 1;
+ __ao2_callback(c, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
+
[... 502 lines stripped ...]
More information about the asterisk-commits
mailing list