From b058f8673aa9d82504bd357dd49f8ec1ba61a47e Mon Sep 17 00:00:00 2001
From: Corey Farrell <git@cfware.com>
Date: Mon, 9 Oct 2017 18:51:05 -0400
Subject: [PATCH] astobj2: Add ao2_weakproxy_find function.

This function finds a weak proxy in an ao2_container and returns the
real object associated with it.

Change-Id: I9da822049747275f5961b5c0a7f14e87157d65d8
---
 include/asterisk/astobj2.h | 11 ++++++++++
 main/astobj2_container.c   | 42 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/include/asterisk/astobj2.h b/include/asterisk/astobj2.h
index 9b5ec123bc..a18f099c09 100644
--- a/include/asterisk/astobj2.h
+++ b/include/asterisk/astobj2.h
@@ -1775,6 +1775,17 @@ void *__ao2_callback_data(struct ao2_container *c, enum search_flags flags,
 void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags flags,
 	const char *tag, const char *file, int line, const char *func);
 
+/*!
+ * \brief Perform an ao2_find on a container with ao2_weakproxy objects, returning the real object.
+ *
+ * \note Only OBJ_SEARCH_* and OBJ_NOLOCK flags are supported by this function.
+ * \see ao2_callback for description of arguments.
+ */
+#define ao2_weakproxy_find(c, arg, flags, tag) \
+	__ao2_weakproxy_find(c, arg, flags, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+void *__ao2_weakproxy_find(struct ao2_container *c, const void *arg, enum search_flags flags,
+	const char *tag, const char *file, int line, const char *func);
+
 /*! \brief
  *
  *
diff --git a/main/astobj2_container.c b/main/astobj2_container.c
index a978db3d46..c75dff991b 100644
--- a/main/astobj2_container.c
+++ b/main/astobj2_container.c
@@ -437,6 +437,48 @@ void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags fla
 	return __ao2_callback(c, flags, c->cmp_fn, arged, tag, file, line, func);
 }
 
+void *__ao2_weakproxy_find(struct ao2_container *c, const void *arg, enum search_flags flags,
+	const char *tag, const char *file, int line, const char *func)
+{
+	void *proxy;
+	void *obj = NULL;
+	enum ao2_lock_req orig_lock;
+
+	ast_assert(!!c);
+	ast_assert(flags & OBJ_SEARCH_MASK);
+	ast_assert(!(flags & ~(OBJ_SEARCH_MASK | OBJ_NOLOCK)));
+
+	if (flags & OBJ_NOLOCK) {
+		orig_lock = __adjust_lock(c, AO2_LOCK_REQ_RDLOCK, 1);
+	} else {
+		orig_lock = AO2_LOCK_REQ_RDLOCK;
+		ao2_rdlock(c);
+	}
+
+	while ((proxy = ao2_find(c, arg, flags | OBJ_NOLOCK))) {
+		obj = __ao2_weakproxy_get_object(proxy, 0, tag ?: __PRETTY_FUNCTION__, file, line, func);
+
+		if (obj) {
+			ao2_ref(proxy, -1);
+			break;
+		}
+
+		/* Upgrade to a write lock */
+		__adjust_lock(c, AO2_LOCK_REQ_WRLOCK, 1);
+		ao2_unlink_flags(c, proxy, OBJ_NOLOCK);
+		ao2_ref(proxy, -1);
+	}
+
+	if (flags & OBJ_NOLOCK) {
+		/* We'll keep any upgraded lock */
+		__adjust_lock(c, orig_lock, 1);
+	} else {
+		ao2_unlock(c);
+	}
+
+	return obj;
+}
+
 /*!
  * initialize an iterator so we start from the first object
  */
-- 
GitLab