[asterisk-commits] gtjoseph: trunk r416807 - in /trunk: ./ build_tools/ main/ tests/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Jun 20 10:27:50 CDT 2014


Author: gtjoseph
Date: Fri Jun 20 10:27:43 2014
New Revision: 416807

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=416807
Log:
astobj2: Additional refactoring to push impl specific code down into the impls.

Move some implementation specific code from astobj2_container.c into
astobj2_hash.c and astobj2_rbtree.c.  This completely removes the need for
astobj2_container to switch on RTTI and it no longer has any knowledge of
the implementation details.

Also adds AO2_DEBUG as a new compile option in menuselect which controls
astobj2 debugging independently of AST_DEVMODE and REF_DEBUG.

Tested by: George Joseph
Review: https://reviewboard.asterisk.org/r/3593/
........

Merged revisions 416806 from http://svn.asterisk.org/svn/asterisk/branches/12

Modified:
    trunk/   (props changed)
    trunk/build_tools/cflags.xml
    trunk/main/astobj2_container.c
    trunk/main/astobj2_container_private.h
    trunk/main/astobj2_hash.c
    trunk/main/astobj2_private.h
    trunk/main/astobj2_rbtree.c
    trunk/tests/test_astobj2.c

Propchange: trunk/
------------------------------------------------------------------------------
Binary property 'branch-12-merged' - no diff available.

Modified: trunk/build_tools/cflags.xml
URL: http://svnview.digium.com/svn/asterisk/trunk/build_tools/cflags.xml?view=diff&rev=416807&r1=416806&r2=416807
==============================================================================
--- trunk/build_tools/cflags.xml (original)
+++ trunk/build_tools/cflags.xml Fri Jun 20 10:27:43 2014
@@ -6,6 +6,9 @@
 			<support_level>core</support_level>
 		</member>
 		<member name="REF_DEBUG" displayname="Enable reference count debugging">
+			<support_level>extended</support_level>
+		</member>
+		<member name="AO2_DEBUG" displayname="Enable internal Astobj2 debugging">
 			<support_level>extended</support_level>
 		</member>
 		<member name="STATIC_BUILD" displayname="Build static binaries">

Modified: trunk/main/astobj2_container.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/astobj2_container.c?view=diff&rev=416807&r1=416806&r2=416807
==============================================================================
--- trunk/main/astobj2_container.c (original)
+++ trunk/main/astobj2_container.c Fri Jun 20 10:27:43 2014
@@ -36,6 +36,49 @@
 int ao2_container_count(struct ao2_container *c)
 {
 	return ast_atomic_fetchadd_int(&c->elements, 0);
+}
+
+int __container_unlink_node_debug(struct ao2_container_node *node, uint32_t flags,
+	const char *tag, const char *file, int line, const char *func)
+{
+	struct ao2_container *container = node->my_container;
+
+	if (container == NULL && (flags & AO2_UNLINK_NODE_DEC_COUNT)) {
+		return 0;
+	}
+
+	if ((flags & AO2_UNLINK_NODE_UNLINK_OBJECT)
+		&& !(flags & AO2_UNLINK_NODE_NOUNREF_OBJECT)) {
+		if (tag) {
+			__ao2_ref_debug(node->obj, -1, tag, file, line, func);
+		} else {
+			ao2_t_ref(node->obj, -1, "Remove obj from container");
+		}
+	}
+
+	node->obj = NULL;
+
+	if (flags & AO2_UNLINK_NODE_DEC_COUNT) {
+		ast_atomic_fetchadd_int(&container->elements, -1);
+#if defined(AO2_DEBUG)
+		{
+			int empty = container->nodes - container->elements;
+
+			if (container->max_empty_nodes < empty) {
+				container->max_empty_nodes = empty;
+			}
+			if (container->v_table->unlink_stat) {
+				container->v_table->unlink_stat(container, node);
+			}
+		}
+#endif	/* defined(AO2_DEBUG) */
+	}
+
+	if (flags & AO2_UNLINK_NODE_UNREF_NODE) {
+		ao2_t_ref(node, -1, "Remove node from container");
+	}
+
+	return 1;
 }
 
 /*!
@@ -76,71 +119,36 @@
 	res = 0;
 	node = self->v_table->new_node(self, obj_new, tag, file, line, func);
 	if (node) {
-#if defined(AO2_DEBUG) && defined(AST_DEVMODE)
-		switch (self->v_table->type) {
-		case AO2_CONTAINER_RTTI_HASH:
-			if (!self->sort_fn) {
-				/*
-				 * XXX chan_iax2 plays games with the hash function so we cannot
-				 * routinely do an integrity check on this type of container.
-				 * chan_iax2 should be changed to not abuse the hash function.
-				 */
-				break;
-			}
-			/* Fall through. */
-		case AO2_CONTAINER_RTTI_RBTREE:
-			if (ao2_container_check(self, OBJ_NOLOCK)) {
-				ast_log(LOG_ERROR, "Container integrity failed before insert.\n");
-			}
-			break;
-		}
-#endif	/* defined(AO2_DEBUG) && defined(AST_DEVMODE) */
+#if defined(AO2_DEBUG)
+		if (ao2_container_check(self, OBJ_NOLOCK)) {
+			ast_log(LOG_ERROR, "Container integrity failed before insert.\n");
+		}
+#endif	/* defined(AO2_DEBUG) */
+
 		/* Insert the new node. */
 		switch (self->v_table->insert(self, node)) {
 		case AO2_CONTAINER_INSERT_NODE_INSERTED:
 			node->is_linked = 1;
 			ast_atomic_fetchadd_int(&self->elements, 1);
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 			AO2_DEVMODE_STAT(++self->nodes);
-			switch (self->v_table->type) {
-			case AO2_CONTAINER_RTTI_HASH:
-				hash_ao2_link_node_stat(self, node);
-				break;
-			case AO2_CONTAINER_RTTI_RBTREE:
-				break;
+			if (self->v_table->link_stat) {
+				self->v_table->link_stat(self, node);
 			}
-#endif	/* defined(AST_DEVMODE) */
-
+#endif	/* defined(AO2_DEBUG) */
+			/* Fall through */
+		case AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED:
+#if defined(AO2_DEBUG)
+			if (ao2_container_check(self, OBJ_NOLOCK)) {
+				ast_log(LOG_ERROR, "Container integrity failed after insert or replace.\n");
+			}
+#endif	/* defined(AO2_DEBUG) */
 			res = 1;
 			break;
-		case AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED:
-			res = 1;
-			/* Fall through */
 		case AO2_CONTAINER_INSERT_NODE_REJECTED:
 			__ao2_ref(node, -1);
 			break;
 		}
-#if defined(AO2_DEBUG) && defined(AST_DEVMODE)
-		if (res) {
-			switch (self->v_table->type) {
-			case AO2_CONTAINER_RTTI_HASH:
-				if (!self->sort_fn) {
-					/*
-					 * XXX chan_iax2 plays games with the hash function so we cannot
-					 * routinely do an integrity check on this type of container.
-					 * chan_iax2 should be changed to not abuse the hash function.
-					 */
-					break;
-				}
-				/* Fall through. */
-			case AO2_CONTAINER_RTTI_RBTREE:
-				if (ao2_container_check(self, OBJ_NOLOCK)) {
-					ast_log(LOG_ERROR, "Container integrity failed after insert.\n");
-				}
-				break;
-			}
-		}
-#endif	/* defined(AO2_DEBUG) && defined(AST_DEVMODE) */
 	}
 
 	if (flags & OBJ_NOLOCK) {
@@ -391,48 +399,11 @@
 			}
 
 			if (flags & OBJ_UNLINK) {
-				/* update number of elements */
-				ast_atomic_fetchadd_int(&self->elements, -1);
-#if defined(AST_DEVMODE)
-				{
-					int empty = self->nodes - self->elements;
-
-					if (self->max_empty_nodes < empty) {
-						self->max_empty_nodes = empty;
-					}
+				int ulflag = AO2_UNLINK_NODE_UNREF_NODE | AO2_UNLINK_NODE_DEC_COUNT;
+				if (multi_container || (flags & OBJ_NODATA)) {
+					ulflag |= AO2_UNLINK_NODE_UNLINK_OBJECT;
 				}
-				switch (self->v_table->type) {
-				case AO2_CONTAINER_RTTI_HASH:
-					hash_ao2_unlink_node_stat(self, node);
-					break;
-				case AO2_CONTAINER_RTTI_RBTREE:
-					break;
-				}
-#endif	/* defined(AST_DEVMODE) */
-
-				/*
-				 * - When unlinking and not returning the result, OBJ_NODATA is
-				 * set, the ref from the container must be decremented.
-				 *
-				 * - When unlinking with a multi_container the ref from the
-				 * original container must be decremented.  This is because the
-				 * result is 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 (multi_container || (flags & OBJ_NODATA)) {
-					if (tag) {
-						__ao2_ref_debug(node->obj, -1, tag, file, line, func);
-					} else {
-						ao2_t_ref(node->obj, -1, "Unlink container obj reference.");
-					}
-				}
-				node->obj = NULL;
-
-				/* Unref the node from the container. */
-				__ao2_ref(node, -1);
+				__container_unlink_node_debug(node, ulflag, tag, file, line, func);
 			}
 		}
 
@@ -630,27 +601,8 @@
 		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)
-			{
-				int empty = iter->c->nodes - iter->c->elements;
-
-				if (iter->c->max_empty_nodes < empty) {
-					iter->c->max_empty_nodes = empty;
-				}
-			}
-			switch (iter->c->v_table->type) {
-			case AO2_CONTAINER_RTTI_HASH:
-				hash_ao2_unlink_node_stat(iter->c, node);
-				break;
-			case AO2_CONTAINER_RTTI_RBTREE:
-				break;
-			}
-#endif	/* defined(AST_DEVMODE) */
-
 			/* Transfer the object ref from the container to the returned object. */
-			node->obj = NULL;
+			__container_unlink_node_debug(node, AO2_UNLINK_NODE_DEC_COUNT, tag, file, line, func);
 
 			/* Transfer the container's node ref to the iterator. */
 		} else {
@@ -713,7 +665,7 @@
 		c->v_table->destroy(c);
 	}
 
-#ifdef AO2_DEBUG
+#if defined(AO2_DEBUG)
 	ast_atomic_fetchadd_int(&ao2.total_containers, -1);
 #endif
 }
@@ -732,7 +684,7 @@
 		c->v_table->destroy(c);
 	}
 
-#ifdef AO2_DEBUG
+#if defined(AO2_DEBUG)
 	ast_atomic_fetchadd_int(&ao2.total_containers, -1);
 #endif
 }
@@ -863,11 +815,11 @@
 	if (name) {
 		prnt(where, "Container name: %s\n", name);
 	}
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 	if (self->v_table->dump) {
 		self->v_table->dump(self, where, prnt, prnt_obj);
 	} else
-#endif	/* defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 	{
 		prnt(where, "Container dump not available.\n");
 	}
@@ -891,7 +843,7 @@
 		prnt(where, "Container name: %s\n", name);
 	}
 	prnt(where, "Number of objects: %d\n", self->elements);
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 	prnt(where, "Number of nodes: %d\n", self->nodes);
 	prnt(where, "Number of empty nodes: %d\n", self->nodes - self->elements);
 	/*
@@ -907,7 +859,7 @@
 	if (self->v_table->stats) {
 		self->v_table->stats(self, where, prnt);
 	}
-#endif	/* defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 	if (!(flags & OBJ_NOLOCK)) {
 		ao2_unlock(self);
 	}
@@ -922,7 +874,7 @@
 		ast_assert(0);
 		return -1;
 	}
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 	if (!self->v_table->integrity) {
 		/* No ingetrigy check available.  Assume container is ok. */
 		return 0;
@@ -935,11 +887,11 @@
 	if (!(flags & OBJ_NOLOCK)) {
 		ao2_unlock(self);
 	}
-#endif	/* defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 	return res;
 }
 
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 static struct ao2_container *reg_containers;
 
 struct ao2_reg_container {
@@ -964,9 +916,9 @@
 	/*! Count of the matches already found. */
 	int count;
 };
-#endif	/* defined(AST_DEVMODE) */
-
-#if defined(AST_DEVMODE)
+#endif	/* defined(AO2_DEBUG) */
+
+#if defined(AO2_DEBUG)
 static int ao2_reg_sort_cb(const void *obj_left, const void *obj_right, int flags)
 {
 	const struct ao2_reg_container *reg_left = obj_left;
@@ -1002,9 +954,9 @@
 	}
 	return cmp;
 }
-#endif	/* defined(AST_DEVMODE) */
-
-#if defined(AST_DEVMODE)
+#endif	/* defined(AO2_DEBUG) */
+
+#if defined(AO2_DEBUG)
 static void ao2_reg_destructor(void *v_doomed)
 {
 	struct ao2_reg_container *doomed = v_doomed;
@@ -1013,12 +965,12 @@
 		ao2_t_ref(doomed->registered, -1, "Releasing registered container.");
 	}
 }
-#endif	/* defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 
 int ao2_container_register(const char *name, struct ao2_container *self, ao2_prnt_obj_fn *prnt_obj)
 {
 	int res = 0;
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 	struct ao2_reg_container *reg;
 
 	reg = ao2_t_alloc_options(sizeof(*reg) + strlen(name), ao2_reg_destructor,
@@ -1038,19 +990,19 @@
 	}
 
 	ao2_t_ref(reg, -1, "Done registering container.");
-#endif	/* defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 	return res;
 }
 
 void ao2_container_unregister(const char *name)
 {
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 	ao2_t_find(reg_containers, name, OBJ_UNLINK | OBJ_NODATA | OBJ_SEARCH_KEY,
 		"Unregister container");
-#endif	/* defined(AST_DEVMODE) */
-}
-
-#if defined(AST_DEVMODE)
+#endif	/* defined(AO2_DEBUG) */
+}
+
+#if defined(AO2_DEBUG)
 static int ao2_complete_reg_cb(void *obj, void *arg, void *data, int flags)
 {
 	struct ao2_reg_match *which = data;
@@ -1058,9 +1010,9 @@
 	/* ao2_reg_sort_cb() has already filtered the search to matching keys */
 	return (which->find_nth < ++which->count) ? (CMP_MATCH | CMP_STOP) : 0;
 }
-#endif	/* defined(AST_DEVMODE) */
-
-#if defined(AST_DEVMODE)
+#endif	/* defined(AO2_DEBUG) */
+
+#if defined(AO2_DEBUG)
 static char *complete_container_names(struct ast_cli_args *a)
 {
 	struct ao2_reg_partial_key partial_key;
@@ -1086,9 +1038,9 @@
 	}
 	return name;
 }
-#endif	/* defined(AST_DEVMODE) */
-
-#if defined(AST_DEVMODE)
+#endif	/* defined(AO2_DEBUG) */
+
+#if defined(AO2_DEBUG)
 AST_THREADSTORAGE(ao2_out_buf);
 
 /*!
@@ -1120,9 +1072,9 @@
 		ast_cli(*(int *) where, "%s", ast_str_buffer(buf));
 	}
 }
-#endif	/* defined(AST_DEVMODE) */
-
-#if defined(AST_DEVMODE)
+#endif	/* defined(AO2_DEBUG) */
+
+#if defined(AO2_DEBUG)
 /*! \brief Show container contents - CLI command */
 static char *handle_cli_astobj2_container_dump(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
@@ -1156,9 +1108,9 @@
 
 	return CLI_SUCCESS;
 }
-#endif	/* defined(AST_DEVMODE) */
-
-#if defined(AST_DEVMODE)
+#endif	/* defined(AO2_DEBUG) */
+
+#if defined(AO2_DEBUG)
 /*! \brief Show container statistics - CLI command */
 static char *handle_cli_astobj2_container_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
@@ -1191,9 +1143,9 @@
 
 	return CLI_SUCCESS;
 }
-#endif	/* defined(AST_DEVMODE) */
-
-#if defined(AST_DEVMODE)
+#endif	/* defined(AO2_DEBUG) */
+
+#if defined(AO2_DEBUG)
 /*! \brief Show container check results - CLI command */
 static char *handle_cli_astobj2_container_check(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
@@ -1227,17 +1179,17 @@
 
 	return CLI_SUCCESS;
 }
-#endif	/* defined(AST_DEVMODE) */
-
-#if defined(AST_DEVMODE)
+#endif	/* defined(AO2_DEBUG) */
+
+#if defined(AO2_DEBUG)
 static struct ast_cli_entry cli_astobj2[] = {
 	AST_CLI_DEFINE(handle_cli_astobj2_container_dump, "Show container contents"),
 	AST_CLI_DEFINE(handle_cli_astobj2_container_stats, "Show container statistics"),
 	AST_CLI_DEFINE(handle_cli_astobj2_container_check, "Perform a container integrity check"),
 };
-#endif	/* defined(AST_DEVMODE) */
-
-#if defined(AST_DEVMODE)
+#endif	/* defined(AO2_DEBUG) */
+
+#if defined(AO2_DEBUG)
 static void container_cleanup(void)
 {
 	ao2_t_ref(reg_containers, -1, "Releasing container registration container");
@@ -1245,11 +1197,11 @@
 
 	ast_cli_unregister_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
 }
-#endif	/* defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 
 int container_init(void)
 {
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 	reg_containers = ao2_t_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK,
 		AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, ao2_reg_sort_cb, NULL,
 		"Container registration container.");
@@ -1259,7 +1211,7 @@
 
 	ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
 	ast_register_atexit(container_cleanup);
-#endif	/* defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 
 	return 0;
 }

Modified: trunk/main/astobj2_container_private.h
URL: http://svnview.digium.com/svn/asterisk/trunk/main/astobj2_container_private.h?view=diff&rev=416807&r1=416806&r2=416807
==============================================================================
--- trunk/main/astobj2_container_private.h (original)
+++ trunk/main/astobj2_container_private.h Fri Jun 20 10:27:43 2014
@@ -25,6 +25,22 @@
 #define ASTOBJ2_CONTAINER_PRIVATE_H_
 
 #include "asterisk/astobj2.h"
+
+/*!
+ * \internal
+ * \brief Enum for internal_ao2_unlink_node.
+ */
+enum ao2_unlink_node_flags {
+	/*! Remove the node from the object's weak link list
+	 * OR unref the object if it's a strong reference. */
+	AO2_UNLINK_NODE_UNLINK_OBJECT = (1 << 0),
+	/*! Modified unlink_object to skip the unref of the object. */
+	AO2_UNLINK_NODE_NOUNREF_OBJECT = (1 << 1),
+	/*! Unref the node. */
+	AO2_UNLINK_NODE_UNREF_NODE = (1 << 2),
+	/*! Decrement the container's element count. */
+	AO2_UNLINK_NODE_DEC_COUNT = (1 << 3),
+};
 
 enum ao2_callback_type {
 	AO2_CALLBACK_DEFAULT,
@@ -40,13 +56,6 @@
 	AO2_CONTAINER_INSERT_NODE_REJECTED,
 };
 
-enum ao2_container_rtti {
-	/*! This is a hash container */
-	AO2_CONTAINER_RTTI_HASH,
-	/*! This is a red-black tree container */
-	AO2_CONTAINER_RTTI_RBTREE,
-};
-
 /*! Allow enough room for container specific traversal state structs */
 #define AO2_TRAVERSAL_STATE_SIZE	100
 
@@ -211,10 +220,32 @@
  */
 typedef int (*ao2_container_integrity)(struct ao2_container *self);
 
+/*!
+ * \internal
+ * \brief Increment the container linked object statistic.
+ * \since 12.4.0
+ *
+ * \param container Container to operate upon.
+ * \param node Container node linking object to.
+ *
+ * \return Nothing
+ */
+typedef void (*ao2_link_node_stat_fn)(struct ao2_container *container, struct ao2_container_node *node);
+
+/*!
+ * \internal
+ * \brief Decrement the container linked object statistic.
+ * \since 12.4.0
+ *
+ * \param container Container to operate upon.
+ * \param node Container node unlinking object from.
+ *
+ * \return Nothing
+ */
+typedef void (*ao2_unlink_node_stat_fn)(struct ao2_container *container, struct ao2_container_node *node);
+
 /*! Container virtual methods template. */
 struct ao2_container_methods {
-	/*! Run Time Type Identification */
-	enum ao2_container_rtti type;
 	/*! Destroy this container. */
 	ao2_container_destroy_fn destroy;
 	/*! \brief Create an empty copy of this container. */
@@ -233,14 +264,18 @@
 	ao2_container_find_cleanup_fn traverse_cleanup;
 	/*! Find the next iteration element in the container. */
 	ao2_iterator_next_fn iterator_next;
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
+	/*! Increment the container linked object statistic. */
+	ao2_link_node_stat_fn link_stat;
+	/*! Deccrement the container linked object statistic. */
+	ao2_unlink_node_stat_fn unlink_stat;
 	/*! Display container contents. (Method for debug purposes) */
 	ao2_container_display dump;
 	/*! Display container debug statistics. (Method for debug purposes) */
 	ao2_container_statistics stats;
 	/*! Perform an integrity check on the container. (Method for debug purposes) */
 	ao2_container_integrity integrity;
-#endif	/* defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 };
 
 /*!
@@ -268,12 +303,12 @@
 	uint32_t options;
 	/*! Number of elements in the container. */
 	int elements;
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 	/*! Number of nodes in the container. */
 	int nodes;
 	/*! Maximum number of empty nodes in the container. (nodes - elements) */
 	int max_empty_nodes;
-#endif	/* defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 	/*!
 	 * \brief TRUE if the container is being destroyed.
 	 *
@@ -287,10 +322,21 @@
 	unsigned int destroying:1;
 };
 
-#if defined(AST_DEVMODE)
-void hash_ao2_link_node_stat(struct ao2_container *hash, struct ao2_container_node *hash_node);
-void hash_ao2_unlink_node_stat(struct ao2_container *hash, struct ao2_container_node *hash_node);
-#endif	/* defined(AST_DEVMODE) */
+/*!
+ * \internal
+ * \brief Unlink a node from this container.
+ *
+ * \param node Node to operate upon.
+ * \param flags ao2_unlink_node_flags governing behavior.
+ *
+ * \retval 0 on errors.
+ * \retval 1 on success.
+ */
+int __container_unlink_node_debug(struct ao2_container_node *node, uint32_t flags,
+	const char *tag, const char *file, int line, const char *func);
+
+#define __container_unlink_node(node, flags) \
+	__container_unlink_node_debug(node, flags, NULL, NULL, 0, NULL)
 
 void container_destruct(void *_c);
 void container_destruct_debug(void *_c);

Modified: trunk/main/astobj2_hash.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/astobj2_hash.c?view=diff&rev=416807&r1=416806&r2=416807
==============================================================================
--- trunk/main/astobj2_hash.c (original)
+++ trunk/main/astobj2_hash.c Fri Jun 20 10:27:43 2014
@@ -51,12 +51,12 @@
 struct hash_bucket {
 	/*! List of objects held in the bucket. */
 	AST_DLLIST_HEAD_NOLOCK(, hash_bucket_node) list;
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 	/*! Number of elements currently in the bucket. */
 	int elements;
 	/*! Maximum number of elements in the bucket. */
 	int max_elements;
-#endif	/* defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 };
 
 /*!
@@ -188,18 +188,12 @@
 		my_container = (struct ao2_container_hash *) doomed->common.my_container;
 		__adjust_lock(my_container, AO2_LOCK_REQ_WRLOCK, 1);
 
-#if defined(AO2_DEBUG) && defined(AST_DEVMODE)
-		/*
-		 * XXX chan_iax2 plays games with the hash function so we cannot
-		 * routinely do an integrity check on this type of container.
-		 * chan_iax2 should be changed to not abuse the hash function.
-		 */
+#if defined(AO2_DEBUG)
 		if (!my_container->common.destroying
-			&& my_container->common.sort_fn
 			&& ao2_container_check(doomed->common.my_container, OBJ_NOLOCK)) {
 			ast_log(LOG_ERROR, "Container integrity failed before node deletion.\n");
 		}
-#endif	/* defined(AO2_DEBUG) && defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 		bucket = &my_container->buckets[doomed->my_bucket];
 		AST_DLLIST_REMOVE(&bucket->list, doomed, links);
 		AO2_DEVMODE_STAT(--my_container->common.nodes);
@@ -210,8 +204,7 @@
 	 * destroyed or the node had not been linked in yet.
 	 */
 	if (doomed->common.obj) {
-		ao2_t_ref(doomed->common.obj, -1, "Container node destruction");
-		doomed->common.obj = NULL;
+		__container_unlink_node(&doomed->common, AO2_UNLINK_NODE_UNLINK_OBJECT);
 	}
 }
 
@@ -265,7 +258,8 @@
  *
  * \return enum ao2_container_insert value.
  */
-static enum ao2_container_insert hash_ao2_insert_node(struct ao2_container_hash *self, struct hash_bucket_node *node)
+static enum ao2_container_insert hash_ao2_insert_node(struct ao2_container_hash *self,
+	struct hash_bucket_node *node)
 {
 	int cmp;
 	struct hash_bucket *bucket;
@@ -303,6 +297,7 @@
 					break;
 				case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
 					SWAP(cur->common.obj, node->common.obj);
+					ao2_t_ref(node, -1, "Discard the new node.");
 					return AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED;
 				}
 			}
@@ -335,6 +330,7 @@
 					break;
 				case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
 					SWAP(cur->common.obj, node->common.obj);
+					ao2_t_ref(node, -1, "Discard the new node.");
 					return AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED;
 				}
 			}
@@ -708,7 +704,7 @@
 	return NULL;
 }
 
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 /*!
  * \internal
  * \brief Increment the hash container linked object statistic.
@@ -719,7 +715,7 @@
  *
  * \return Nothing
  */
-void hash_ao2_link_node_stat(struct ao2_container *hash, struct ao2_container_node *hash_node)
+static void hash_ao2_link_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;
@@ -730,9 +726,9 @@
 		self->buckets[i].max_elements = self->buckets[i].elements;
 	}
 }
-#endif	/* defined(AST_DEVMODE) */
-
-#if defined(AST_DEVMODE)
+#endif	/* defined(AO2_DEBUG) */
+
+#if defined(AO2_DEBUG)
 /*!
  * \internal
  * \brief Decrement the hash container linked object statistic.
@@ -743,14 +739,14 @@
  *
  * \return Nothing
  */
-void hash_ao2_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;
 
 	--self->buckets[node->my_bucket].elements;
 }
-#endif	/* defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 
 /*!
  * \internal
@@ -776,7 +772,7 @@
 	}
 }
 
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 /*!
  * \internal
  * \brief Display contents of the specified container.
@@ -828,9 +824,9 @@
 #undef FORMAT
 #undef FORMAT2
 }
-#endif	/* defined(AST_DEVMODE) */
-
-#if defined(AST_DEVMODE)
+#endif	/* defined(AO2_DEBUG) */
+
+#if defined(AO2_DEBUG)
 /*!
  * \internal
  * \brief Display statistics of the specified container.
@@ -869,9 +865,9 @@
 #undef FORMAT
 #undef FORMAT2
 }
-#endif	/* defined(AST_DEVMODE) */
-
-#if defined(AST_DEVMODE)
+#endif	/* defined(AO2_DEBUG) */
+
+#if defined(AO2_DEBUG)
 /*!
  * \internal
  * \brief Perform an integrity check on the specified container.
@@ -1034,11 +1030,10 @@
 
 	return 0;
 }
-#endif	/* defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 
 /*! Hash container virtual method table. */
 static const struct ao2_container_methods v_table_hash = {
-	.type = AO2_CONTAINER_RTTI_HASH,
 	.alloc_empty_clone = (ao2_container_alloc_empty_clone_fn) hash_ao2_alloc_empty_clone,
 	.alloc_empty_clone_debug =
 		(ao2_container_alloc_empty_clone_debug_fn) hash_ao2_alloc_empty_clone_debug,
@@ -1048,11 +1043,13 @@
 	.traverse_next = (ao2_container_find_next_fn) hash_ao2_find_next,
 	.iterator_next = (ao2_iterator_next_fn) hash_ao2_iterator_next,
 	.destroy = (ao2_container_destroy_fn) hash_ao2_destroy,
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
+	.link_stat = hash_ao2_link_node_stat,
+	.unlink_stat = hash_ao2_unlink_node_stat,
 	.dump = (ao2_container_display) hash_ao2_dump,
 	.stats = (ao2_container_statistics) hash_ao2_stats,
 	.integrity = (ao2_container_integrity) hash_ao2_integrity,
-#endif	/* defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 };
 
 /*!
@@ -1098,7 +1095,7 @@
 
 #ifdef AO2_DEBUG
 	ast_atomic_fetchadd_int(&ao2.total_containers, 1);
-#endif
+#endif	/* defined(AO2_DEBUG) */
 
 	return (struct ao2_container *) self;
 }

Modified: trunk/main/astobj2_private.h
URL: http://svnview.digium.com/svn/asterisk/trunk/main/astobj2_private.h?view=diff&rev=416807&r1=416806&r2=416807
==============================================================================
--- trunk/main/astobj2_private.h (original)
+++ trunk/main/astobj2_private.h Fri Jun 20 10:27:43 2014
@@ -26,16 +26,11 @@
 
 #include "asterisk/astobj2.h"
 
-#if defined(TEST_FRAMEWORK)
-/* We are building with the test framework enabled so enable AO2 debug tests as well. */
-#define AO2_DEBUG 1
-#endif	/* defined(TEST_FRAMEWORK) */
-
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 #define AO2_DEVMODE_STAT(stat)	stat
 #else
 #define AO2_DEVMODE_STAT(stat)
-#endif	/* defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 
 #ifdef AO2_DEBUG
 struct ao2_stats {
@@ -46,7 +41,7 @@
 	volatile int total_locked;
 };
 extern struct ao2_stats ao2;
-#endif
+#endif	/* defined(AO2_DEBUG) */
 
 int is_ao2_object(void *user_data);
 enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger);

Modified: trunk/main/astobj2_rbtree.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/astobj2_rbtree.c?view=diff&rev=416807&r1=416806&r2=416807
==============================================================================
--- trunk/main/astobj2_rbtree.c (original)
+++ trunk/main/astobj2_rbtree.c Fri Jun 20 10:27:43 2014
@@ -79,7 +79,7 @@
 	struct ao2_container common;
 	/*! Root node of the tree.  NULL if the tree is empty. */
 	struct rbtree_node *root;
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 	struct {
 		/*! Fixup insert left cases 1-3 */
 		int fixup_insert_left[3];
@@ -92,7 +92,7 @@
 		/*! Deletion of node with number of children (0-2). */
 		int delete_children[3];
 	} stats;
-#endif	/* defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 };
 
 enum equal_node_bias {
@@ -880,19 +880,19 @@
 		my_container = (struct ao2_container_rbtree *) doomed->common.my_container;
 		__adjust_lock(my_container, AO2_LOCK_REQ_WRLOCK, 1);
 
-#if defined(AO2_DEBUG) && defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 		if (!my_container->common.destroying
 			&& ao2_container_check(doomed->common.my_container, OBJ_NOLOCK)) {
 			ast_log(LOG_ERROR, "Container integrity failed before node deletion.\n");
 		}
-#endif	/* defined(AO2_DEBUG) && defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 		rb_delete_node(my_container, doomed);
-#if defined(AO2_DEBUG) && defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 		if (!my_container->common.destroying
 			&& ao2_container_check(doomed->common.my_container, OBJ_NOLOCK)) {
 			ast_log(LOG_ERROR, "Container integrity failed after node deletion.\n");
 		}
-#endif	/* defined(AO2_DEBUG) && defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 	}
 
 	/*
@@ -900,8 +900,7 @@
 	 * destroyed or the node had not been linked in yet.
 	 */
 	if (doomed->common.obj) {
-		ao2_t_ref(doomed->common.obj, -1, "Container node destruction");
-		doomed->common.obj = NULL;
+		__container_unlink_node(&doomed->common, AO2_UNLINK_NODE_UNLINK_OBJECT);
 	}
 }
 
@@ -1266,6 +1265,7 @@
 		break;
 	case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
 		SWAP(cur->common.obj, node->common.obj);
+		ao2_t_ref(node, -1, "Don't need the new node.");
 		return AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED;
 	}
 
@@ -1707,7 +1707,7 @@
 	}
 }
 
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 /*!
  * \internal
  * \brief Display contents of the specified container.
@@ -1745,9 +1745,9 @@
 #undef FORMAT
 #undef FORMAT2
 }
-#endif	/* defined(AST_DEVMODE) */
-
-#if defined(AST_DEVMODE)
+#endif	/* defined(AO2_DEBUG) */
+
+#if defined(AO2_DEBUG)
 /*!
  * \internal
  * \brief Display statistics of the specified container.
@@ -1787,9 +1787,9 @@
 			self->stats.fixup_delete_right[idx]);
 	}
 }
-#endif	/* defined(AST_DEVMODE) */
-
-#if defined(AST_DEVMODE)
+#endif	/* defined(AO2_DEBUG) */
+
+#if defined(AO2_DEBUG)
 /*!
  * \internal
  * \brief Check the black height of the given node.
@@ -1831,9 +1831,9 @@
 	return height_left;
 }
 
-#endif	/* defined(AST_DEVMODE) */
-
-#if defined(AST_DEVMODE)
+#endif	/* defined(AO2_DEBUG) */
+
+#if defined(AO2_DEBUG)
 /*!
  * \internal
  * \brief Perform an integrity check on the specified container.
@@ -2011,11 +2011,10 @@
 
 	return res;
 }
-#endif	/* defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 
 /*! rbtree container virtual method table. */
 static const struct ao2_container_methods v_table_rbtree = {
-	.type = AO2_CONTAINER_RTTI_RBTREE,
 	.alloc_empty_clone = (ao2_container_alloc_empty_clone_fn) rb_ao2_alloc_empty_clone,
 	.alloc_empty_clone_debug =
 		(ao2_container_alloc_empty_clone_debug_fn) rb_ao2_alloc_empty_clone_debug,
@@ -2025,11 +2024,11 @@
 	.traverse_next = (ao2_container_find_next_fn) rb_ao2_find_next,
 	.iterator_next = (ao2_iterator_next_fn) rb_ao2_iterator_next,
 	.destroy = (ao2_container_destroy_fn) rb_ao2_destroy,
-#if defined(AST_DEVMODE)
+#if defined(AO2_DEBUG)
 	.dump = (ao2_container_display) rb_ao2_dump,
 	.stats = (ao2_container_statistics) rb_ao2_stats,
 	.integrity = (ao2_container_integrity) rb_ao2_integrity,
-#endif	/* defined(AST_DEVMODE) */
+#endif	/* defined(AO2_DEBUG) */
 };
 
 /*!
@@ -2056,7 +2055,7 @@
 
 #ifdef AO2_DEBUG
 	ast_atomic_fetchadd_int(&ao2.total_containers, 1);
-#endif
+#endif	/* defined(AO2_DEBUG) */
 
 	return (struct ao2_container *) self;
 }

Modified: trunk/tests/test_astobj2.c
URL: http://svnview.digium.com/svn/asterisk/trunk/tests/test_astobj2.c?view=diff&rev=416807&r1=416806&r2=416807
==============================================================================
--- trunk/tests/test_astobj2.c (original)
+++ trunk/tests/test_astobj2.c Fri Jun 20 10:27:43 2014
@@ -1927,7 +1927,10 @@
 static enum ast_test_result_state test_performance(struct ast_test *test,
 	enum test_container_type type, unsigned int copt)
 {
-#define OBJS 256
+/*!
+ * \brief The number of objects inserted and searched for in the container under test.
+ */
+#define OBJS 73
 	int res = AST_TEST_PASS;
 	struct ao2_container *c1 = NULL;
 	struct test_obj *tobj[OBJS];
@@ -1989,47 +1992,58 @@
 }
 
 static enum ast_test_result_state testloop(struct ast_test *test,
-	enum test_container_type type, int copt)
-{
-#define ITERATIONS 2500
+	enum test_container_type type, int copt, int iterations)
+{
 	int res = AST_TEST_PASS;
 	int i;
 	struct timeval start;
 
 	start = ast_tvnow();
-	for (i = 1 ; i <= ITERATIONS && res == AST_TEST_PASS ; i++) {
+	for (i = 1 ; i <= iterations && res == AST_TEST_PASS ; i++) {
 		res = test_performance(test, type, copt);
 	}
-	ast_test_status_update(test, "%dK traversals, %9s : %5lu ms\n",
-		ITERATIONS / 1000, test_container2str(type), (unsigned long)ast_tvdiff_ms(ast_tvnow(), start));
+	ast_test_status_update(test, "%5.2fK traversals, %9s : %5lu ms\n",
+		iterations / 1000.0, test_container2str(type), (unsigned long)ast_tvdiff_ms(ast_tvnow(), start));
 	return res;
 }
 
 AST_TEST_DEFINE(astobj2_test_perf)
 {
+/*!
+ * \brief The number of iteration of testloop to be performed.
+ * \note
+ * In order to keep the elapsed time sane, if AO2_DEBUG is defined in menuselect,
+ * only 25000 iterations are performed.   Otherwise 100000.
+ */
+#ifdef AO2_DEBUG
+#define ITERATIONS 25000
+#else
+#define ITERATIONS 100000
+#endif
+
 	int res = AST_TEST_PASS;
 
 	switch (cmd) {
 	case TEST_INIT:
 		info->name = "astobj2_test_perf";
-		info->category = "/main/astobj2/";
+		info->category = "/main/astobj2/perf";
 		info->summary = "Test container performance";
 		info->description =
-			"Runs 100000 container traversal tests.";
+			"Runs container traversal tests.";
 		return AST_TEST_NOT_RUN;
 	case TEST_EXECUTE:
 		break;
 	}
 
-	res = testloop(test, TEST_CONTAINER_LIST, 0);
+	res = testloop(test, TEST_CONTAINER_LIST, 0, ITERATIONS);
 	if (!res) {
 		return res;
 	}
-	res = testloop(test, TEST_CONTAINER_HASH, 0);
+	res = testloop(test, TEST_CONTAINER_HASH, 0, ITERATIONS);
 	if (!res) {
 		return res;
 	}
-	res = testloop(test, TEST_CONTAINER_RBTREE, 0);
+	res = testloop(test, TEST_CONTAINER_RBTREE, 0, ITERATIONS);
 
 	return res;
 }




More information about the asterisk-commits mailing list