[asterisk-commits] rmudgett: branch rmudgett/ao2_enhancements r371505 - /team/rmudgett/ao2_enhan...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Aug 17 17:53:22 CDT 2012


Author: rmudgett
Date: Fri Aug 17 17:53:18 2012
New Revision: 371505

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=371505
Log:
Refactored hash_ao2_link 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=371505&r1=371504&r2=371505
==============================================================================
--- team/rmudgett/ao2_enhancements/main/astobj2.c (original)
+++ team/rmudgett/ao2_enhancements/main/astobj2.c Fri Aug 17 17:53:18 2012
@@ -792,20 +792,29 @@
 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.
+ * \brief Create a new container node.
  *
  * \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 obj_new Object to put into the node.
  * \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);
+ * \retval initialized-node on success.
+ * \retval NULL on error.
+ */
+typedef struct ao2_container_node *(*ao2_container_new_node_fn)(struct ao2_container *self, void *obj_new, const char *tag, const char *file, int line, const char *func);
+
+/*!
+ * \brief Insert a node into this container.
+ *
+ * \param self Container to operate upon.
+ * \param node Container node to insert into the container.
+ *
+ * \return enum ao2_container_insert value.
+ */
+typedef enum ao2_container_insert (*ao2_container_insert_fn)(struct ao2_container *self, struct ao2_container_node *node);
 
 /*!
  * \brief Find the first container node in a traversal.
@@ -894,8 +903,10 @@
 	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;
+	/*! Create a new container node. */
+	ao2_container_new_node_fn new_node;
+	/*! Insert a node into this container. */
+	ao2_container_insert_fn insert;
 	/*! Traverse the container, find the first node. */
 	ao2_container_find_first_fn traverse_first;
 	/*! Traverse the container, find the next node. */
@@ -959,22 +970,87 @@
 	return c->elements;
 }
 
-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) {
+#if defined(AST_DEVMODE)
+static void hash_ao2_link_node_stat(struct ao2_container *hash, struct ao2_container_node *hash_node);
+#endif	/* defined(AST_DEVMODE) */
+
+/*!
+ * \internal
+ * \brief Link an object into this container.  (internal)
+ *
+ * \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.
+ */
+static int internal_ao2_link(struct ao2_container *self, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func)
+{
+	int res;
+	enum ao2_lock_req orig_lock;
+	struct ao2_container_node *node;
+
+	if (!INTERNAL_OBJ(obj_new) || !INTERNAL_OBJ(self)
+		|| !self->v_table || !self->v_table->new_node || !self->v_table->insert) {
 		/* Sanity checks. */
 		return 0;
 	}
-	return c->v_table->link(c, obj_new, flags, tag, file, line, func);
+
+	if (flags & OBJ_NOLOCK) {
+		orig_lock = adjust_lock(self, AO2_LOCK_REQ_WRLOCK, 1);
+	} else {
+		ao2_wrlock(self);
+		orig_lock = AO2_LOCK_REQ_MUTEX;
+	}
+
+	res = 0;
+	node = self->v_table->new_node(self, obj_new, tag, file, line, func);
+	if (node) {
+		/* Insert the new node. */
+		switch (self->v_table->insert(self, node)) {
+		case AO2_CONTAINER_INSERT_NODE_INSERTED:
+#if defined(AST_DEVMODE)
+			switch (self->v_table->type) {
+			case AO2_CONTAINER_RTTI_HASH:
+				hash_ao2_link_node_stat(self, node);
+				break;
+			}
+#endif	/* defined(AST_DEVMODE) */
+			ast_atomic_fetchadd_int(&self->elements, 1);
+
+			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 (flags & OBJ_NOLOCK) {
+		adjust_lock(self, orig_lock, 0);
+	} else {
+		ao2_unlock(self);
+	}
+
+	return res;
+}
+
+int __ao2_link_debug(struct ao2_container *c, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func)
+{
+	return internal_ao2_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__);
+	return internal_ao2_link(c, obj_new, flags, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__);
 }
 
 /*!
@@ -1042,7 +1118,6 @@
 /*!
  * \internal
  * \brief Traverse the container.  (internal)
- * \since 12.0
  *
  * \param self Container to operate upon.
  * \param flags search_flags to control traversing the container
@@ -1668,6 +1743,8 @@
 	AST_DLLIST_ENTRY(hash_bucket_node) links;
 	/*! Hash bucket holding the node. */
 	int my_bucket;
+	/*! TRUE if the node is linked into the container. */
+	unsigned int is_linked:1;
 };
 
 struct hash_bucket {
@@ -1774,11 +1851,11 @@
 static void hash_ao2_node_destructor(void *v_doomed)
 {
 	struct hash_bucket_node *doomed = v_doomed;
-	struct hash_bucket *bucket;
-	struct ao2_container_hash *my_container;
-
-	my_container = (struct ao2_container_hash *) doomed->common.my_container;
-	if (my_container) {
+
+	if (doomed->is_linked) {
+		struct ao2_container_hash *my_container;
+		struct hash_bucket *bucket;
+
 		/*
 		 * Promote to write lock if not already there.  Since
 		 * adjust_lock() can potentially release and block waiting for a
@@ -1792,6 +1869,7 @@
 		 * negative reference and the destructor called twice for the
 		 * same node.
 		 */
+		my_container = (struct ao2_container_hash *) doomed->common.my_container;
 		adjust_lock(my_container, AO2_LOCK_REQ_WRLOCK, 1);
 
 		bucket = &my_container->buckets[doomed->my_bucket];
@@ -1810,22 +1888,63 @@
 
 /*!
  * \internal
- * \brief Insert the given node into the specified bucket in the container.
+ * \brief Create a new container node.
  * \since 12.0
  *
  * \param self Container to operate upon.
- * \param bucket Hash bucket to insert the node.
- * \param node What to put in the bucket list.
+ * \param obj_new Object to put into the node.
+ * \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 initialized-node on success.
+ * \retval NULL on error.
+ */
+static struct hash_bucket_node *hash_ao2_new_node(struct ao2_container_hash *self, void *obj_new, const char *tag, const char *file, int line, const char *func)
+{
+	struct hash_bucket_node *node;
+	int i;
+
+	node = __ao2_alloc(sizeof(*node), hash_ao2_node_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
+	if (!node) {
+		return NULL;
+	}
+
+	i = abs(self->hash_fn(obj_new, OBJ_POINTER));
+	i %= self->n_buckets;
+
+	if (tag) {
+		__ao2_ref_debug(obj_new, +1, tag, file, line, func);
+	} else {
+		__ao2_ref(obj_new, +1);
+	}
+	node->common.obj = obj_new;
+	node->common.my_container = (struct ao2_container *) self;
+	node->my_bucket = i;
+
+	return node;
+}
+
+/*!
+ * \internal
+ * \brief Insert a node into this container.
+ * \since 12.0
+ *
+ * \param self Container to operate upon.
+ * \param node Container node to insert into the container.
  *
  * \return enum ao2_container_insert value.
  */
-static enum ao2_container_insert hash_ao2_link_insert(struct ao2_container_hash *self, struct hash_bucket *bucket, 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;
 	struct hash_bucket_node *cur;
 	ao2_sort_fn *sort_fn;
 	uint32_t options;
 
+	bucket = &self->buckets[node->my_bucket];
 	sort_fn = self->common.sort_fn;
 	options = self->common.options;
 
@@ -1838,6 +1957,7 @@
 				}
 				if (cmp < 0) {
 					AST_DLLIST_INSERT_AFTER_CURRENT(node, links);
+					node->is_linked = 1;
 					return AO2_CONTAINER_INSERT_NODE_INSERTED;
 				}
 				switch (options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
@@ -1870,6 +1990,7 @@
 				}
 				if (cmp > 0) {
 					AST_DLLIST_INSERT_BEFORE_CURRENT(node, links);
+					node->is_linked = 1;
 					return AO2_CONTAINER_INSERT_NODE_INSERTED;
 				}
 				switch (options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
@@ -1894,86 +2015,8 @@
 		}
 		AST_DLLIST_INSERT_TAIL(&bucket->list, node, links);
 	}
+	node->is_linked = 1;
 	return AO2_CONTAINER_INSERT_NODE_INSERTED;
-}
-
-/*!
- * \internal
- * \brief Link an object into this container.
- * \since 12.0
- *
- * \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.
- */
-static int hash_ao2_link(struct ao2_container_hash *self, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func)
-{
-	int i;
-	int res;
-	enum ao2_lock_req orig_lock;
-	struct hash_bucket_node *node;
-
-	node = __ao2_alloc(sizeof(*node), hash_ao2_node_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!node) {
-		return 0;
-	}
-
-	i = abs(self->hash_fn(obj_new, OBJ_POINTER));
-	i %= self->n_buckets;
-
-	if (flags & OBJ_NOLOCK) {
-		orig_lock = adjust_lock(self, AO2_LOCK_REQ_WRLOCK, 1);
-	} else {
-		ao2_wrlock(self);
-		orig_lock = AO2_LOCK_REQ_MUTEX;
-	}
-
-	if (tag) {
-		__ao2_ref_debug(obj_new, +1, tag, file, line, func);
-	} else {
-		__ao2_ref(obj_new, +1);
-	}
-	node->common.obj = obj_new;
-	node->common.my_container = (struct ao2_container *) self;
-	node->my_bucket = i;
-
-	/* Insert the new node. */
-	res = 0;
-	switch (hash_ao2_link_insert(self, &self->buckets[i], node)) {
-	case AO2_CONTAINER_INSERT_NODE_INSERTED:
-#if defined(AST_DEVMODE)
-		++self->buckets[i].elements;
-		if (self->buckets[i].max_elements < self->buckets[i].elements) {
-			self->buckets[i].max_elements = self->buckets[i].elements;
-		}
-#endif	/* defined(AST_DEVMODE) */
-		ast_atomic_fetchadd_int(&self->common.elements, 1);
-
-		res = 1;
-		break;
-	case AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED:
-		res = 1;
-		/* Fall through */
-	case AO2_CONTAINER_INSERT_NODE_REJECTED:
-		node->common.my_container = NULL;
-		ao2_ref(node, -1);
-		break;
-	}
-
-	if (flags & OBJ_NOLOCK) {
-		adjust_lock(self, orig_lock, 0);
-	} else {
-		ao2_unlock(self);
-	}
-
-	return res;
 }
 
 /*! Traversal state to restart a hash container traversal. */
@@ -2535,6 +2578,30 @@
 #if defined(AST_DEVMODE)
 /*!
  * \internal
+ * \brief Increment the hash container linked object statistic.
+ * \since 12.0
+ *
+ * \param hash Container to operate upon.
+ * \param hash_node Container node linking object to.
+ *
+ * \return Nothing
+ */
+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;
+	int i = node->my_bucket;
+
+	++self->buckets[i].elements;
+	if (self->buckets[i].max_elements < self->buckets[i].elements) {
+		self->buckets[i].max_elements = self->buckets[i].elements;
+	}
+}
+#endif	/* defined(AST_DEVMODE) */
+
+#if defined(AST_DEVMODE)
+/*!
+ * \internal
  * \brief Decrement the hash container linked object statistic.
  * \since 12.0
  *
@@ -2758,7 +2825,8 @@
 	.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,
-	.link = (ao2_container_link_fn) hash_ao2_link,
+	.new_node = (ao2_container_new_node_fn) hash_ao2_new_node,
+	.insert = (ao2_container_insert_fn) hash_ao2_insert_node,
 	.traverse_first = (ao2_container_find_first_fn) hash_ao2_find_first,
 	.traverse_next = (ao2_container_find_next_fn) hash_ao2_find_next,
 	.traverse_cleanup = (ao2_container_find_cleanup_fn) hash_ao2_find_cleanup,




More information about the asterisk-commits mailing list