[asterisk-commits] rmudgett: branch rmudgett/ao2_enhancements r371573 - /team/rmudgett/ao2_enhan...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Aug 20 15:20:00 CDT 2012
Author: rmudgett
Date: Mon Aug 20 15:19:57 2012
New Revision: 371573
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=371573
Log:
Refactored hash_ao2_iterator_next to extract generic container code.
Modified:
team/rmudgett/ao2_enhancements/main/astobj2.c
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=371573&r1=371572&r2=371573
==============================================================================
--- team/rmudgett/ao2_enhancements/main/astobj2.c (original)
+++ team/rmudgett/ao2_enhancements/main/astobj2.c Mon Aug 20 15:19:57 2012
@@ -852,21 +852,19 @@
typedef void (*ao2_container_find_cleanup_fn)(void *v_state);
/*!
- * \brief Find the next iteration element in the container.
+ * \brief Find the next non-empty iteration node 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);
+ * \param prev Previous node returned by the iterator.
+ * \param flags search_flags to control iterating the container.
+ * Only AO2_ITERATOR_DESCENDING is useful by the method.
+ *
+ * \note The container is already locked.
+ *
+ * \retval node on success.
+ * \retval NULL on error or no more nodes in the container.
+ */
+typedef struct ao2_container_node *(*ao2_iterator_next_fn)(struct ao2_container *self, struct ao2_container_node *prev, enum ao2_iterator_flags flags);
/*!
* \brief Display statistics of the specified container.
@@ -972,6 +970,7 @@
#if defined(AST_DEVMODE)
static void hash_ao2_link_node_stat(struct ao2_container *hash, struct ao2_container_node *hash_node);
+static void hash_ao2_unlink_node_stat(struct ao2_container *hash, struct ao2_container_node *hash_node);
#endif /* defined(AST_DEVMODE) */
/*!
@@ -1107,10 +1106,6 @@
{
return CMP_MATCH;
}
-
-#if defined(AST_DEVMODE)
-static void hash_ao2_traverse_unlink_node_stat(struct ao2_container *self, struct ao2_container_node *node);
-#endif /* defined(AST_DEVMODE) */
/*! Allow enough room for container specific traversal state structs */
#define AO2_TRAVERSAL_STATE_SIZE 100
@@ -1289,7 +1284,7 @@
#if defined(AST_DEVMODE)
switch (self->v_table->type) {
case AO2_CONTAINER_RTTI_HASH:
- hash_ao2_traverse_unlink_node_stat(self, node);
+ hash_ao2_unlink_node_stat(self, node);
break;
}
#endif /* defined(AST_DEVMODE) */
@@ -1477,6 +1472,7 @@
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;
+ struct ao2_container_node *node;
void *ret;
if (!INTERNAL_OBJ(iter->c) || !iter->c->v_table || !iter->c->v_table->iterator_next) {
@@ -1485,7 +1481,7 @@
}
if (iter->complete) {
- /* Don't return any more nodes. */
+ /* Don't return any more objects. */
return NULL;
}
@@ -1504,11 +1500,47 @@
}
}
- ret = iter->c->v_table->iterator_next(iter->c, iter, tag, file, line, func);
- if (!ret) {
+ node = iter->c->v_table->iterator_next(iter->c, iter->last_node, iter->flags);
+ if (node) {
+ ret = node->obj;
+
+ if (iter->flags & AO2_ITERATOR_UNLINK) {
+ /* update number of elements */
+ ast_atomic_fetchadd_int(&iter->c->elements, -1);
+#if defined(AST_DEVMODE)
+ switch (iter->c->v_table->type) {
+ case AO2_CONTAINER_RTTI_HASH:
+ hash_ao2_unlink_node_stat(iter->c, node);
+ break;
+ }
+#endif /* defined(AST_DEVMODE) */
+
+ /* Transfer the object ref from the container to the returned object. */
+ node->obj = NULL;
+
+ /* Transfer the container's node ref to the iterator. */
+ } else {
+ /* Bump ref of returned object */
+ if (tag) {
+ __ao2_ref_debug(ret, +1, tag, file, line, func);
+ } else {
+ __ao2_ref(ret, +1);
+ }
+
+ /* Bump the container's node ref for the iterator. */
+ __ao2_ref(node, +1);
+ }
+ } else {
/* The iteration has completed. */
iter->complete = 1;
- }
+ ret = NULL;
+ }
+
+ /* Replace the iterator's node */
+ if (iter->last_node) {
+ __ao2_ref(iter->last_node, -1);
+ }
+ iter->last_node = node;
if (iter->flags & AO2_ITERATOR_DONTLOCK) {
adjust_lock(iter->c, orig_lock, 0);
@@ -2446,45 +2478,37 @@
/*!
* \internal
- * \brief Find the next iteration element in the container.
+ * \brief Find the next non-empty iteration node in the container.
* \since 12.0
*
* \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.
- */
-static void *hash_ao2_iterator_next(struct ao2_container_hash *self, struct ao2_iterator *iter, const char *tag, const char *file, int line, const char *func)
+ * \param node Previous node returned by the iterator.
+ * \param flags search_flags to control iterating the container.
+ * Only AO2_ITERATOR_DESCENDING is useful by the method.
+ *
+ * \note The container is already locked.
+ *
+ * \retval node on success.
+ * \retval NULL on error or no more nodes in the container.
+ */
+static struct hash_bucket_node *hash_ao2_iterator_next(struct ao2_container_hash *self, struct hash_bucket_node *node, enum ao2_iterator_flags flags)
{
int cur_bucket;
- struct hash_bucket_node *node;
- void *ret;
-
- if ((struct ao2_container *) self != iter->c) {
- /* Sanity checks. */
- return NULL;
- }
-
- node = iter->last_node;
- if (iter->flags & AO2_ITERATOR_DESCENDING) {
+
+ if (flags & AO2_ITERATOR_DESCENDING) {
if (node) {
cur_bucket = node->my_bucket;
/* Find next non-empty node. */
- node = AST_DLLIST_PREV(node, links);
- while (node && !node->common.obj) {
+ for (;;) {
node = AST_DLLIST_PREV(node, links);
- }
- if (node) {
- /* Found a non-empty node. */
- goto hash_found;
+ if (!node) {
+ break;
+ }
+ if (node->common.obj) {
+ /* Found a non-empty node. */
+ return node;
+ }
}
} else {
/* Find first non-empty node. */
@@ -2494,12 +2518,12 @@
/* Find a non-empty node in the remaining buckets */
while (0 <= --cur_bucket) {
node = AST_DLLIST_LAST(&self->buckets[cur_bucket].list);
- while (node && !node->common.obj) {
+ while (node) {
+ if (node->common.obj) {
+ /* Found a non-empty node. */
+ return node;
+ }
node = AST_DLLIST_PREV(node, links);
- }
- if (node) {
- /* Found a non-empty node. */
- goto hash_found;
}
}
} else {
@@ -2507,13 +2531,15 @@
cur_bucket = node->my_bucket;
/* Find next non-empty node. */
- node = AST_DLLIST_NEXT(node, links);
- while (node && !node->common.obj) {
+ for (;;) {
node = AST_DLLIST_NEXT(node, links);
- }
- if (node) {
- /* Found a non-empty node. */
- goto hash_found;
+ if (!node) {
+ break;
+ }
+ if (node->common.obj) {
+ /* Found a non-empty node. */
+ return node;
+ }
}
} else {
/* Find first non-empty node. */
@@ -2523,56 +2549,18 @@
/* Find a non-empty node in the remaining buckets */
while (++cur_bucket < self->n_buckets) {
node = AST_DLLIST_FIRST(&self->buckets[cur_bucket].list);
- while (node && !node->common.obj) {
+ while (node) {
+ if (node->common.obj) {
+ /* Found a non-empty node. */
+ return node;
+ }
node = AST_DLLIST_NEXT(node, links);
}
- if (node) {
- /* Found a non-empty node. */
- goto hash_found;
- }
}
}
/* No more nodes to visit in the container. */
- if (iter->last_node) {
- __ao2_ref(iter->last_node, -1);
- iter->last_node = NULL;
- }
return NULL;
-
-hash_found:
- ret = node->common.obj;
-
- if (iter->flags & AO2_ITERATOR_UNLINK) {
- /* update number of elements */
- ast_atomic_fetchadd_int(&self->common.elements, -1);
-#if defined(AST_DEVMODE)
- --self->buckets[cur_bucket].elements;
-#endif /* defined(AST_DEVMODE) */
-
- /* Transfer the object ref from the container to the returned object. */
- node->common.obj = NULL;
-
- /* Transfer the container's node ref to the iterator. */
- } else {
- /* Bump ref of returned object */
- if (tag) {
- __ao2_ref_debug(ret, 1, tag, file, line, func);
- } else {
- __ao2_ref(ret, 1);
- }
-
- /* Bump the container's node ref for the iterator. */
- __ao2_ref(node, +1);
- }
-
- /* Replace the iterator's node */
- if (iter->last_node) {
- __ao2_ref(iter->last_node, -1);
- }
- iter->last_node = node;
-
- return ret;
}
#if defined(AST_DEVMODE)
@@ -2610,7 +2598,7 @@
*
* \return Nothing
*/
-static void hash_ao2_traverse_unlink_node_stat(struct ao2_container *hash, struct ao2_container_node *hash_node)
+static void hash_ao2_unlink_node_stat(struct ao2_container *hash, struct ao2_container_node *hash_node)
{
struct ao2_container_hash *self = (struct ao2_container_hash *) hash;
struct hash_bucket_node *node = (struct hash_bucket_node *) hash_node;
@@ -2802,6 +2790,12 @@
/* Check bucket forward/backward obj count. */
if (count_obj_forward != count_obj_backward) {
ast_log(LOG_ERROR, "Forward/backward object count does not match!\n");
+ return -1;
+ }
+
+ /* Check bucket obj count statistic. */
+ if (count_obj_forward != self->buckets[bucket].elements) {
+ ast_log(LOG_ERROR, "Bucket object count stat does not match!\n");
return -1;
}
More information about the asterisk-commits
mailing list