[svn-commits] rmudgett: branch rmudgett/ao2_enhancements r371326 - in /team/rmudgett/ao2_en...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Wed Aug 15 19:13:11 CDT 2012


Author: rmudgett
Date: Wed Aug 15 19:13:07 2012
New Revision: 371326

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=371326
Log:
Prevent automatically restarting an iteration after an iteration completes.

The new iterators would restart from the beginning automatically if you
completed an iteration and continued trying to iterate.  The previous
iterator implementation would not automatically restart.

*  Added ao2_iterator_restart() to allow manually restarting an iteration at
any time during an iteration.

* Changed the astobj2 tests to require an iteration to not automatically
restart after it completed.

Modified:
    team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h
    team/rmudgett/ao2_enhancements/main/astobj2.c
    team/rmudgett/ao2_enhancements/tests/test_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=371326&r1=371325&r2=371326
==============================================================================
--- team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h (original)
+++ team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h Wed Aug 15 19:13:07 2012
@@ -1601,32 +1601,24 @@
  * ao2_iterator to keep track of the current position.
  *
  * Because the navigation is typically done without holding the
- * lock on the container across the loop, objects can be inserted or deleted
- * or moved while we work. As a consequence, there is no guarantee that
- * we manage to touch all the elements in the container, and it is possible
- * that we touch the same object multiple times.
- *
- * However, within the current hash table container, the following is true:
- *  - It is not possible to miss an object in the container while iterating
- *    unless it gets added after the iteration begins and is added to a bucket
- *    that is before the one the current object is in.  In this case, even if
- *    you locked the container around the entire iteration loop, you still would
- *    not see this object, because it would still be waiting on the container
- *    lock so that it can be added.
- *  - It would be extremely rare to see an object twice.  The only way this can
- *    happen is if an object got unlinked from the container and added again
- *    during the same iteration.  Furthermore, when the object gets added back,
- *    it has to be in the current or later bucket for it to be seen again.
- *
- * An iterator must be first initialized with ao2_iterator_init(),
- * then we can use o = ao2_iterator_next() to move from one
- * element to the next. Remember that the object returned by
- * ao2_iterator_next() has its refcount incremented,
- * and the reference must be explicitly released when done with it.
- *
- * In addition, ao2_iterator_init() will hold a reference to the container
- * being iterated, which will be freed when ao2_iterator_destroy() is called
- * to free up the resources used by the iterator (if any).
+ * lock on the container across the loop, objects can be
+ * inserted or deleted or moved while we work.  As a
+ * consequence, there is no guarantee that we manage to touch
+ * all the elements in the container, and it is possible that we
+ * touch the same object multiple times.
+ *
+ * An iterator must be first initialized with
+ * ao2_iterator_init(), then we can use o = ao2_iterator_next()
+ * to move from one element to the next.  Remember that the
+ * object returned by ao2_iterator_next() has its refcount
+ * incremented, and the reference must be explicitly released
+ * when done with it.
+ *
+ * In addition, ao2_iterator_init() will hold a reference to the
+ * container being iterated and the last container node found.
+ * Thes objects will be unreffed when ao2_iterator_destroy() is
+ * called to free up the resources used by the iterator (if
+ * any).
  *
  * Example:
  *
@@ -1638,6 +1630,12 @@
  *
  *  i = ao2_iterator_init(c, flags);
  *
+ *  while ((o = ao2_iterator_next(&i))) {
+ *     ... do something on o ...
+ *     ao2_ref(o, -1);
+ *  }
+ *
+ *  ao2_iterator_restart(&i);
  *  while ((o = ao2_iterator_next(&i))) {
  *     ... do something on o ...
  *     ao2_ref(o, -1);
@@ -1669,7 +1667,9 @@
 	struct ao2_container *c;
 	/*! Last container node (Has a reference) */
 	void *last_node;
-	/*! operation flags */
+	/*! Nonzero if the iteration has completed. */
+	int complete;
+	/*! operation flags (enum ao2_iterator_flags) */
 	int flags;
 };
 
@@ -1688,7 +1688,10 @@
 	 * to the original locked state.
 	 *
 	 * \note Only use this flag if the ao2_container is manually
-	 * locked already.
+	 * locked already.  You should hold the lock until after
+	 * ao2_iterator_destroy().  If you must release the lock then
+	 * you must at least hold the lock whenever you call an
+	 * ao2_iterator_xxx function with this iterator.
 	 */
 	AO2_ITERATOR_DONTLOCK = (1 << 0),
 	/*!
@@ -1720,7 +1723,7 @@
  * \brief Create an iterator for a container
  *
  * \param c the container
- * \param flags one or more flags from ao2_iterator_flags
+ * \param flags one or more flags from ao2_iterator_flags.
  *
  * \retval the constructed iterator
  *
@@ -1730,7 +1733,6 @@
  *       allocated on the stack or on the heap.
  *
  * This function will take a reference on the container being iterated.
- *
  */
 struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags);
 
@@ -1743,7 +1745,6 @@
  *
  * This function will release the container reference held by the iterator
  * and any other resources it may be holding.
- *
  */
 #if defined(TEST_FRAMEWORK)
 void ao2_iterator_destroy(struct ao2_iterator *iter) __attribute__((noinline));
@@ -1765,6 +1766,19 @@
 
 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);
+
+/*!
+ * \brief Restart an iteration.
+ *
+ * \param iter the iterator to restart
+ *
+ * \note A restart is not going to have any effect if the
+ * iterator was created with the AO2_ITERATOR_UNLINK flag.  Any
+ * previous objects returned were removed from the container.
+ *
+ * \retval none
+ */
+void ao2_iterator_restart(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=371326&r1=371325&r2=371326
==============================================================================
--- team/rmudgett/ao2_enhancements/main/astobj2.c (original)
+++ team/rmudgett/ao2_enhancements/main/astobj2.c Wed Aug 15 19:13:07 2012
@@ -1342,10 +1342,7 @@
 	return a;
 }
 
-/*!
- * destroy an iterator
- */
-void ao2_iterator_destroy(struct ao2_iterator *iter)
+void ao2_iterator_restart(struct ao2_iterator *iter)
 {
 	/* Release the last container node reference if we have one. */
 	if (iter->last_node) {
@@ -1373,6 +1370,15 @@
 		}
 	}
 
+	/* The iteration is no longer complete. */
+	iter->complete = 0;
+}
+
+void ao2_iterator_destroy(struct ao2_iterator *iter)
+{
+	/* Release any last container node reference. */
+	ao2_iterator_restart(iter);
+
 	/* Release the iterated container reference. */
 	ao2_ref(iter->c, -1);
 	iter->c = NULL;
@@ -1400,6 +1406,11 @@
 
 	if (!INTERNAL_OBJ(iter->c) || !iter->c->v_table || !iter->c->v_table->iterator_next) {
 		/* Sanity checks. */
+		return NULL;
+	}
+
+	if (iter->complete) {
+		/* Don't return any more nodes. */
 		return NULL;
 	}
 
@@ -1419,6 +1430,10 @@
 	}
 
 	ret = iter->c->v_table->iterator_next(iter->c, iter, tag, file, line, func);
+	if (!ret) {
+		/* The iteration has completed. */
+		iter->complete = 1;
+	}
 
 	if (iter->flags & AO2_ITERATOR_DONTLOCK) {
 		adjust_lock(iter->c, orig_lock, 0);

Modified: team/rmudgett/ao2_enhancements/tests/test_astobj2.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/ao2_enhancements/tests/test_astobj2.c?view=diff&rev=371326&r1=371325&r2=371326
==============================================================================
--- team/rmudgett/ao2_enhancements/tests/test_astobj2.c (original)
+++ team/rmudgett/ao2_enhancements/tests/test_astobj2.c Wed Aug 15 19:13:07 2012
@@ -1248,7 +1248,7 @@
 	const int *vector, int count, const char *prefix, struct ast_test *test)
 {
 	struct ao2_iterator iter;
-	struct test_obj *obj = NULL;
+	struct test_obj *obj;
 	int idx;
 
 	if (ao2_container_count(container) != count) {
@@ -1274,14 +1274,12 @@
 		}
 		ao2_ref(obj, -1); /* remove ref from iterator */
 	}
+	obj = ao2_iterator_next(&iter);
 	if (obj) {
-		obj = ao2_iterator_next(&iter);
-		if (obj) {
-			ast_test_status_update(test, "%s: Too many objects found.  Object %d\n",
-				prefix, obj->i);
-			ao2_ref(obj, -1); /* remove ref from iterator */
-			res = AST_TEST_FAIL;
-		}
+		ast_test_status_update(test, "%s: Too many objects found.  Object %d\n",
+			prefix, obj->i);
+		ao2_ref(obj, -1); /* remove ref from iterator */
+		res = AST_TEST_FAIL;
 	}
 
 	ao2_iterator_destroy(&iter);
@@ -1311,7 +1309,7 @@
 	const int *vector, int count, const char *prefix, struct ast_test *test)
 {
 	struct ao2_iterator *mult_iter;
-	struct test_obj *obj = NULL;
+	struct test_obj *obj;
 	int idx;
 
 	mult_iter = ao2_callback(container, flags | OBJ_MULTIPLE, cmp_fn, arg);
@@ -1335,14 +1333,12 @@
 		}
 		ao2_ref(obj, -1); /* remove ref from iterator */
 	}
+	obj = ao2_iterator_next(mult_iter);
 	if (obj) {
-		obj = ao2_iterator_next(mult_iter);
-		if (obj) {
-			ast_test_status_update(test, "%s: Too many objects found.  Object %d\n",
-				prefix, obj->i);
-			ao2_ref(obj, -1); /* remove ref from iterator */
-			res = AST_TEST_FAIL;
-		}
+		ast_test_status_update(test, "%s: Too many objects found.  Object %d\n",
+			prefix, obj->i);
+		ao2_ref(obj, -1); /* remove ref from iterator */
+		res = AST_TEST_FAIL;
 	}
 	ao2_iterator_destroy(mult_iter);
 
@@ -1370,7 +1366,7 @@
 	const int *vector, int count, const char *prefix, struct ast_test *test)
 {
 	struct ao2_iterator *mult_iter;
-	struct test_obj *obj = NULL;
+	struct test_obj *obj;
 	int idx;
 
 	mult_iter = ao2_find(container, &number, flags | OBJ_MULTIPLE | OBJ_KEY);
@@ -1399,15 +1395,13 @@
 		}
 		ao2_ref(obj, -1); /* remove ref from iterator */
 	}
+	obj = ao2_iterator_next(mult_iter);
 	if (obj) {
-		obj = ao2_iterator_next(mult_iter);
-		if (obj) {
-			ast_test_status_update(test,
-				"%s: Too many objects found.  Object %d, dup id %d\n",
-				prefix, obj->i, obj->dup_number);
-			ao2_ref(obj, -1); /* remove ref from iterator */
-			res = AST_TEST_FAIL;
-		}
+		ast_test_status_update(test,
+			"%s: Too many objects found.  Object %d, dup id %d\n",
+			prefix, obj->i, obj->dup_number);
+		ao2_ref(obj, -1); /* remove ref from iterator */
+		res = AST_TEST_FAIL;
 	}
 	ao2_iterator_destroy(mult_iter);
 




More information about the svn-commits mailing list