[Asterisk-code-review] astobj2: Create function to copy weak proxied objects from c... (asterisk[master])

Joshua Colp asteriskteam at digium.com
Mon Nov 26 13:48:01 CST 2018


Joshua Colp has submitted this change and it was merged. ( https://gerrit.asterisk.org/10638 )

Change subject: astobj2: Create function to copy weak proxied objects from container.
......................................................................

astobj2: Create function to copy weak proxied objects from container.

Create ao2_container_dup_weakproxy_objs to perform a similar function to
ao2_container_dup.  This function expects the source container to have
weakproxy objects, inserts the associated non-weak objects into the
destination container.  Orphaned weakproxy objects are ignored.

Create test for this new function and for ao2_weakproxy_find.

Change-Id: I898387f058057e08696fe9070f8cd94ef3a27482
---
M include/asterisk/astobj2.h
M main/astobj2_container.c
M tests/test_astobj2_weaken.c
3 files changed, 233 insertions(+), 0 deletions(-)

Approvals:
  Richard Mudgett: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved
  Joshua Colp: Approved for Submit



diff --git a/include/asterisk/astobj2.h b/include/asterisk/astobj2.h
index 39933c7..03ef947 100644
--- a/include/asterisk/astobj2.h
+++ b/include/asterisk/astobj2.h
@@ -1420,6 +1420,28 @@
 int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags);
 
 /*!
+ * \brief Copy object references associated with src container weakproxies into the dest container.
+ *
+ * \param dest Container to copy src strong object references into.
+ * \param src Container to copy all weak object references from.
+ * \param flags OBJ_NOLOCK if a lock is already held on both containers.
+ *    Otherwise, the src container is locked first.
+ *
+ * \pre The dest container must be empty.  If the duplication fails, the
+ * dest container will be returned empty.
+ *
+ * \note This can potentially be expensive because a malloc is
+ * needed for every object in the src container.
+ *
+ * \note Every object inside the container is locked by \ref ao2_weakproxy_get_object.
+ *       Any weakproxy in \ref src with no associated object is ignored.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int ao2_container_dup_weakproxy_objs(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags);
+
+/*!
  * \brief Create a clone/copy of the given container.
  * \since 11.0
  *
diff --git a/main/astobj2_container.c b/main/astobj2_container.c
index 5197867..9a837bd 100644
--- a/main/astobj2_container.c
+++ b/main/astobj2_container.c
@@ -697,6 +697,59 @@
 	return res;
 }
 
+/*!
+ * \brief Copy obj associated with a weakproxy into the arg container.
+ *
+ * \param proxy pointer to the weakproxy.
+ * \param arg callback argument from ao2_callback()
+ * \param flags flags from ao2_callback()
+ *
+ * \retval 0 on success.
+ * \retval CMP_STOP|CMP_MATCH on error.
+ */
+static int dup_weakproxy_cb(void *proxy, void *arg, int flags)
+{
+	void *obj = ao2_weakproxy_get_object(proxy, 0);
+	struct ao2_container *dest = arg;
+	int ret;
+
+	if (!obj) {
+		return 0;
+	}
+
+	ret = ao2_t_link_flags(dest, obj, OBJ_NOLOCK, NULL) ? 0 : (CMP_MATCH | CMP_STOP);
+	ao2_ref(obj, -1);
+
+	return ret;
+}
+
+int ao2_container_dup_weakproxy_objs(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
+{
+	void *obj;
+	int res = 0;
+
+	if (!(flags & OBJ_NOLOCK)) {
+		ao2_rdlock(src);
+		ao2_wrlock(dest);
+	}
+	obj = ao2_callback(src, OBJ_NOLOCK, dup_weakproxy_cb, dest);
+	if (obj) {
+		/* Failed to put this obj into the dest container. */
+		ao2_t_ref(obj, -1, "Failed to put this object into the dest container.");
+
+		/* Remove all items from the dest container. */
+		ao2_t_callback(dest, OBJ_NOLOCK | OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL,
+			NULL, NULL);
+		res = -1;
+	}
+	if (!(flags & OBJ_NOLOCK)) {
+		ao2_unlock(dest);
+		ao2_unlock(src);
+	}
+
+	return res;
+}
+
 struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum search_flags flags, const char *tag, const char *file, int line, const char *func)
 {
 	struct ao2_container *clone;
diff --git a/tests/test_astobj2_weaken.c b/tests/test_astobj2_weaken.c
index 2755b6e..13f48ac 100644
--- a/tests/test_astobj2_weaken.c
+++ b/tests/test_astobj2_weaken.c
@@ -262,9 +262,166 @@
 	return AST_TEST_FAIL;
 }
 
+struct strong_str {
+	char *value;
+};
+
+struct weakproxy_str {
+	AO2_WEAKPROXY();
+	char value[0];
+};
+
+static struct strong_str *alloc_str(struct ao2_container *weakcontainer, const char *value)
+{
+	struct strong_str *strong = ao2_t_alloc(sizeof(*strong), NULL, value);
+	struct weakproxy_str *weak = ao2_weakproxy_alloc(sizeof(*weak) + strlen(value) + 1, NULL);
+
+	if (!weak || !strong) {
+		goto error_return;
+	}
+
+	strcpy(weak->value, value); /*SAFE*/
+	strong->value = weak->value;
+
+	if (ao2_weakproxy_set_object(weak, strong, 0)) {
+		goto error_return;
+	}
+
+	if (!ao2_link(weakcontainer, weak)) {
+		goto error_return;
+	}
+
+	ao2_ref(weak, -1);
+	return strong;
+
+error_return:
+	ao2_cleanup(weak);
+	ao2_cleanup(strong);
+
+	return NULL;
+}
+
+AO2_STRING_FIELD_HASH_FN(weakproxy_str, value);
+AO2_STRING_FIELD_CMP_FN(weakproxy_str, value);
+AO2_STRING_FIELD_SORT_FN(strong_str, value);
+
+#define ITERATOR_CHECK_NEXT(iter, var, expected) \
+	do { \
+		var = ao2_iterator_next(iter); \
+		ast_test_validate_cleanup(test, var == expected, ret, cleanup); \
+		ao2_cleanup(var); \
+	} while (0)
+
+#define WEAKFIND_CHECK(c, key, var, expected) \
+	do { \
+		var = ao2_weakproxy_find(c, key, OBJ_SEARCH_KEY, ""); \
+		ast_test_validate_cleanup(test, var == expected, ret, cleanup); \
+		ao2_cleanup(var); \
+	} while (0)
+
+AST_TEST_DEFINE(astobj2_weak_container)
+{
+	int ret = AST_TEST_FAIL;
+
+	struct strong_str *strong1 = NULL;
+	struct strong_str *strong2 = NULL;
+	struct strong_str *strong3 = NULL;
+
+	struct strong_str *strong = NULL;
+
+	struct ao2_container *weakcontainer = NULL;
+	struct ao2_container *dupcontainer = NULL;
+
+	struct ao2_iterator iter;
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "astobj2_weak_container";
+		info->category = "/main/astobj2/";
+		info->summary = "Test ao2 weak containers";
+		info->description = "Test ao2 weak containers.";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	weakcontainer = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 7,
+		weakproxy_str_hash_fn, NULL, weakproxy_str_cmp_fn);
+	dupcontainer = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+		strong_str_sort_fn, NULL);
+
+	if (!weakcontainer || !dupcontainer) {
+		goto cleanup;
+	}
+
+	strong1 = alloc_str(weakcontainer, "obj1");
+	strong2 = alloc_str(weakcontainer, "obj2");
+	strong3 = alloc_str(weakcontainer, "obj3");
+
+	if (!strong1 || !strong2 || !strong3) {
+		goto cleanup;
+	}
+
+	if (ao2_container_dup_weakproxy_objs(dupcontainer, weakcontainer, 0)) {
+		goto cleanup;
+	}
+
+	iter = ao2_iterator_init(dupcontainer, 0);
+	ITERATOR_CHECK_NEXT(&iter, strong, strong1);
+	ITERATOR_CHECK_NEXT(&iter, strong, strong2);
+	ITERATOR_CHECK_NEXT(&iter, strong, strong3);
+	ITERATOR_CHECK_NEXT(&iter, strong, NULL);
+	ao2_iterator_cleanup(&iter);
+
+	ao2_callback(dupcontainer, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, NULL, NULL);
+
+	WEAKFIND_CHECK(weakcontainer, "obj1", strong, strong1);
+	WEAKFIND_CHECK(weakcontainer, "obj2", strong, strong2);
+	WEAKFIND_CHECK(weakcontainer, "obj3", strong, strong3);
+	WEAKFIND_CHECK(weakcontainer, "unknown", strong, NULL);
+
+	/* This will orphan "obj2" in weakcontainer. */
+	ao2_replace(strong2, NULL);
+
+	if (ao2_container_dup_weakproxy_objs(dupcontainer, weakcontainer, 0)) {
+		goto cleanup;
+	}
+
+	ast_test_validate_cleanup(test,
+		ao2_container_count(weakcontainer) == ao2_container_count(dupcontainer) + 1,
+		ret,
+		cleanup);
+
+	iter = ao2_iterator_init(dupcontainer, 0);
+	ITERATOR_CHECK_NEXT(&iter, strong, strong1);
+	ITERATOR_CHECK_NEXT(&iter, strong, strong3);
+	ITERATOR_CHECK_NEXT(&iter, strong, NULL);
+	ao2_iterator_cleanup(&iter);
+
+	WEAKFIND_CHECK(weakcontainer, "obj1", strong, strong1);
+	WEAKFIND_CHECK(weakcontainer, "obj2", strong, NULL);
+	WEAKFIND_CHECK(weakcontainer, "obj3", strong, strong3);
+	WEAKFIND_CHECK(weakcontainer, "unknown", strong, NULL);
+
+	ret = AST_TEST_PASS;
+
+cleanup:
+	ao2_cleanup(strong1);
+	ao2_cleanup(strong2);
+	ao2_cleanup(strong3);
+
+	ao2_cleanup(weakcontainer);
+	ao2_cleanup(dupcontainer);
+
+	ao2_cleanup(strong);
+
+	return ret;
+}
+
 static int unload_module(void)
 {
 	AST_TEST_UNREGISTER(astobj2_weak1);
+	AST_TEST_UNREGISTER(astobj2_weak_container);
 
 	return 0;
 }
@@ -272,6 +429,7 @@
 static int load_module(void)
 {
 	AST_TEST_REGISTER(astobj2_weak1);
+	AST_TEST_REGISTER(astobj2_weak_container);
 
 	return AST_MODULE_LOAD_SUCCESS;
 }

-- 
To view, visit https://gerrit.asterisk.org/10638
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-MessageType: merged
Gerrit-Change-Id: I898387f058057e08696fe9070f8cd94ef3a27482
Gerrit-Change-Number: 10638
Gerrit-PatchSet: 2
Gerrit-Owner: Corey Farrell <git at cfware.com>
Gerrit-Reviewer: Corey Farrell <git at cfware.com>
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Jenkins2 (1000185)
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Kevin Harwell <kharwell at digium.com>
Gerrit-Reviewer: Richard Mudgett <rmudgett at digium.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20181126/0af38b41/attachment-0001.html>


More information about the asterisk-code-review mailing list