astobj2: Add ao2_weakproxy_find function.
[asterisk/asterisk.git] / main / astobj2_container.c
index c00da9f..c75dff9 100644 (file)
@@ -22,8 +22,6 @@
 
 #include "asterisk.h"
 
-ASTERISK_REGISTER_FILE()
-
 #include "asterisk/_private.h"
 #include "asterisk/astobj2.h"
 #include "astobj2_private.h"
@@ -101,10 +99,13 @@ int __ao2_link(struct ao2_container *self, void *obj_new, int flags,
        struct ao2_container_node *node;
 
        if (!__is_ao2_object(obj_new, file, line, func)
-               || !__is_ao2_object(self, file, line, func)
-               || !self->v_table || !self->v_table->new_node || !self->v_table->insert) {
+               || !__is_ao2_object(self, file, line, func)) {
+               return 0;
+       }
+
+       if (!self->v_table || !self->v_table->new_node || !self->v_table->insert) {
                /* Sanity checks. */
-               ast_assert(0);
+               __ast_assert_failed(0, "invalid container v_table", file, line, func);
                return 0;
        }
 
@@ -176,7 +177,6 @@ void *__ao2_unlink(struct ao2_container *c, void *user_data, int flags,
 {
        if (!__is_ao2_object(user_data, file, line, func)) {
                /* Sanity checks. */
-               ast_assert(0);
                return NULL;
        }
 
@@ -241,10 +241,14 @@ static void *internal_ao2_traverse(struct ao2_container *self, enum search_flags
        struct ao2_container *multi_container = NULL;
        struct ao2_iterator *multi_iterator = NULL;
 
-       if (!__is_ao2_object(self, file, line, func) || !self->v_table
+       if (!__is_ao2_object(self, file, line, func)) {
+               return NULL;
+       }
+
+       if (!self->v_table
                || !self->v_table->traverse_first || !self->v_table->traverse_next) {
                /* Sanity checks. */
-               ast_assert(0);
+               __ast_assert_failed(0, "invalid container v_table", file, line, func);
                return NULL;
        }
 
@@ -433,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
  */
@@ -451,8 +497,7 @@ struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
 void ao2_iterator_restart(struct ao2_iterator *iter)
 {
        if (!is_ao2_object(iter->c)) {
-               ast_log(LOG_ERROR, "Iterator container is not valid.\n");
-               ast_assert(0);
+               /* Sanity check. */
                return;
        }
 
@@ -460,12 +505,6 @@ void ao2_iterator_restart(struct ao2_iterator *iter)
        if (iter->last_node) {
                enum ao2_lock_req orig_lock;
 
-               if (!is_ao2_object(iter->c)) {
-                       /* Sanity check. */
-                       ast_assert(0);
-                       return;
-               }
-
                /*
                 * Do a read lock in case the container node unref does not
                 * destroy the node.  If the container node is destroyed then
@@ -521,10 +560,13 @@ void *__ao2_iterator_next(struct ao2_iterator *iter,
        struct ao2_container_node *node;
        void *ret;
 
-       if (!__is_ao2_object(iter->c, file, line, func)
-               || !iter->c->v_table || !iter->c->v_table->iterator_next) {
+       if (!__is_ao2_object(iter->c, file, line, func)) {
+               return NULL;
+       }
+
+       if (!iter->c->v_table || !iter->c->v_table->iterator_next) {
                /* Sanity checks. */
-               ast_assert(0);
+               __ast_assert_failed(0, "invalid iterator container v_table", file, line, func);
                return NULL;
        }
 
@@ -661,12 +703,16 @@ struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum sea
        int failed;
 
        /* Create the clone container with the same properties as the original. */
-       if (!__is_ao2_object(orig, file, line, func)
-               || !orig->v_table || !orig->v_table->alloc_empty_clone) {
+       if (!__is_ao2_object(orig, file, line, func)) {
+               return NULL;
+       }
+
+       if (!orig->v_table || !orig->v_table->alloc_empty_clone) {
                /* Sanity checks. */
-               ast_assert(0);
+               __ast_assert_failed(0, "invalid container v_table", file, line, func);
                return NULL;
        }
+
        clone = orig->v_table->alloc_empty_clone(orig, tag, file, line, func);
        if (!clone) {
                return NULL;