]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
named_locks: Use ao2_weakproxy to deal with cleanup from container. 84/3784/2
authorCorey Farrell <git@cfware.com>
Thu, 18 Aug 2016 18:28:57 +0000 (14:28 -0400)
committerCorey Farrell <git@cfware.com>
Fri, 2 Sep 2016 14:28:01 +0000 (10:28 -0400)
This allows standard ao2 functions to be used to release references to
an ast_named_lock.  This change can cause less frequent locking of the
global named_locks container.  The container is no longer locked when a
named_lock reference is being release except when this causes the
named_lock to be destroyed.

Change-Id: I644e39c6d83a153d71b3fae77ec05599d725e7e6

main/named_locks.c

index 59604838844d9d3450eb7644bf4afaf8ca6a4b92..92b8262c10a03e33ae707266ece46f1574a5e7ee 100644 (file)
@@ -35,13 +35,17 @@ ASTERISK_REGISTER_FILE()
 struct ao2_container *named_locks;
 #define NAMED_LOCKS_BUCKETS 101
 
-struct ast_named_lock {
+struct named_lock_proxy {
+       AO2_WEAKPROXY();
        char key[0];
 };
 
+struct ast_named_lock {
+};
+
 static int named_locks_hash(const void *obj, const int flags)
 {
-       const struct ast_named_lock *lock = obj;
+       const struct named_lock_proxy *lock = obj;
 
        switch (flags & OBJ_SEARCH_MASK) {
        case OBJ_SEARCH_KEY:
@@ -57,8 +61,8 @@ static int named_locks_hash(const void *obj, const int flags)
 
 static int named_locks_cmp(void *obj_left, void *obj_right, int flags)
 {
-       const struct ast_named_lock *object_left = obj_left;
-       const struct ast_named_lock *object_right = obj_right;
+       const struct named_lock_proxy *object_left = obj_left;
+       const struct named_lock_proxy *object_right = obj_right;
        const char *right_key = obj_right;
        int cmp;
 
@@ -98,31 +102,74 @@ int ast_named_locks_init(void)
        return 0;
 }
 
+static void named_lock_proxy_cb(void *weakproxy, void *data)
+{
+       ao2_unlink(named_locks, weakproxy);
+}
+
 struct ast_named_lock *__ast_named_lock_get(const char *filename, int lineno, const char *func,
        enum ast_named_lock_type lock_type, const char *keyspace, const char *key)
 {
+       struct named_lock_proxy *proxy = NULL;
        struct ast_named_lock *lock = NULL;
-       int concat_key_buff_len = strlen(keyspace) + strlen(key) + 2;
-       char *concat_key = ast_alloca(concat_key_buff_len);
+       int keylen = strlen(keyspace) + strlen(key) + 2;
+       char *concat_key = ast_alloca(keylen);
 
        sprintf(concat_key, "%s-%s", keyspace, key); /* Safe */
 
        ao2_lock(named_locks);
-       lock = ao2_find(named_locks, concat_key, OBJ_SEARCH_KEY | OBJ_NOLOCK);
-       if (lock) {
+       proxy = ao2_find(named_locks, concat_key, OBJ_SEARCH_KEY | OBJ_NOLOCK);
+       if (proxy) {
                ao2_unlock(named_locks);
-               ast_assert((ao2_options_get(lock) & AO2_ALLOC_OPT_LOCK_MASK) == lock_type);
-               return lock;
+               lock = __ao2_weakproxy_get_object(proxy, 0, __PRETTY_FUNCTION__, filename, lineno, func);
+
+               if (lock) {
+                       /* We have an existing lock and it's not being destroyed. */
+                       ao2_ref(proxy, -1);
+                       ast_assert((ao2_options_get(lock) & AO2_ALLOC_OPT_LOCK_MASK) == lock_type);
+
+                       return lock;
+               }
+
+               /* the old proxy is being destroyed, clean list before creating/adding new one */
+               ao2_lock(named_locks);
+               ao2_unlink_flags(named_locks, proxy, OBJ_NOLOCK);
+               ao2_ref(proxy, -1);
        }
 
-       lock = ao2_alloc_options(sizeof(*lock) + concat_key_buff_len, NULL, lock_type);
-       if (lock) {
-               strcpy(lock->key, concat_key); /* Safe */
-               ao2_link_flags(named_locks, lock, OBJ_NOLOCK);
+       proxy = ao2_t_weakproxy_alloc(sizeof(*proxy) + keylen, NULL, concat_key);
+       if (!proxy) {
+               goto failure_cleanup;
+       }
+
+       lock = __ao2_alloc(sizeof(*lock) + keylen, NULL, lock_type, concat_key, filename, lineno, func);
+       if (!lock) {
+               goto failure_cleanup;
        }
+
+       /* We have exclusive access to proxy and lock, no need for locking here. */
+       if (ao2_weakproxy_set_object(proxy, lock, OBJ_NOLOCK)) {
+               goto failure_cleanup;
+       }
+
+       if (ao2_weakproxy_subscribe(proxy, named_lock_proxy_cb, NULL, OBJ_NOLOCK)) {
+               goto failure_cleanup;
+       }
+
+       strcpy(proxy->key, concat_key); /* Safe */
+       ao2_link_flags(named_locks, proxy, OBJ_NOLOCK);
        ao2_unlock(named_locks);
+       ao2_t_ref(proxy, -1, "Release allocation reference");
 
        return lock;
+
+failure_cleanup:
+       ao2_unlock(named_locks);
+
+       ao2_cleanup(proxy);
+       ao2_cleanup(lock);
+
+       return NULL;
 }
 
 int __ast_named_lock_put(const char *filename, int lineno, const char *func,
@@ -132,11 +179,7 @@ int __ast_named_lock_put(const char *filename, int lineno, const char *func,
                return -1;
        }
 
-       ao2_lock(named_locks);
-       if (ao2_ref(lock, -1) == 2) {
-               ao2_unlink_flags(named_locks, lock, OBJ_NOLOCK);
-       }
-       ao2_unlock(named_locks);
+       __ao2_ref(lock, -1, __PRETTY_FUNCTION__, filename, lineno, func);
 
        return 0;
 }