BuildSystem: Remove unused variables.
[asterisk/asterisk.git] / main / sorcery.c
index 51b0b22..c79675c 100644 (file)
@@ -207,6 +207,13 @@ struct ast_sorcery_object_field {
        intptr_t args[];
 };
 
+/*! \brief Proxy object for sorcery */
+struct sorcery_proxy {
+       AO2_WEAKPROXY();
+       /*! \brief The name of the module owning this sorcery instance */
+       char module_name[0];
+};
+
 /*! \brief Full structure for sorcery */
 struct ast_sorcery {
        /*! \brief Container for known object types */
@@ -215,8 +222,8 @@ struct ast_sorcery {
        /*! \brief Observers */
        struct ao2_container *observers;
 
-       /*! \brief The name of the module owning this sorcery instance */
-       char module_name[0];
+       /*! \brief Pointer to module_name in the associated sorcery_proxy. */
+       char *module_name;
 };
 
 /*! \brief Structure for passing load/reload details */
@@ -336,102 +343,12 @@ static sorcery_field_handler sorcery_field_default_handler(enum aco_option_type
        return NULL;
 }
 
-/*! \brief Hashing function for sorcery wizards */
-static int sorcery_wizard_hash(const void *obj, const int flags)
-{
-       const struct ast_sorcery_internal_wizard *object;
-       const char *key;
-
-       switch (flags & OBJ_SEARCH_MASK) {
-       case OBJ_SEARCH_KEY:
-               key = obj;
-               break;
-       case OBJ_SEARCH_OBJECT:
-               object = obj;
-               key = object->callbacks.name;
-               break;
-       default:
-               ast_assert(0);
-               return 0;
-       }
-       return ast_str_hash(key);
-}
-
-/*! \brief Comparator function for sorcery wizards */
-static int sorcery_wizard_cmp(void *obj, void *arg, int flags)
-{
-       const struct ast_sorcery_internal_wizard *object_left = obj;
-       const struct ast_sorcery_internal_wizard *object_right = arg;
-       const char *right_key = arg;
-       int cmp;
-
-       switch (flags & OBJ_SEARCH_MASK) {
-       case OBJ_SEARCH_OBJECT:
-               right_key = object_right->callbacks.name;
-               /* Fall through */
-       case OBJ_SEARCH_KEY:
-               cmp = strcmp(object_left->callbacks.name, right_key);
-               break;
-       case OBJ_SEARCH_PARTIAL_KEY:
-               cmp = strncmp(object_left->callbacks.name, right_key, strlen(right_key));
-               break;
-       default:
-               cmp = 0;
-               break;
-       }
-       if (cmp) {
-               return 0;
-       }
-       return CMP_MATCH;
-}
-
-/*! \brief Hashing function for sorcery wizards */
-static int object_type_field_hash(const void *obj, const int flags)
-{
-       const struct ast_sorcery_object_field *object_field;
-       const char *key;
-
-       switch (flags & OBJ_SEARCH_MASK) {
-       case OBJ_SEARCH_KEY:
-               key = obj;
-               break;
-       case OBJ_SEARCH_OBJECT:
-               object_field = obj;
-               key = object_field->name;
-               break;
-       default:
-               ast_assert(0);
-               return 0;
-       }
-       return ast_str_hash(key);
-}
-
-static int object_type_field_cmp(void *obj, void *arg, int flags)
-{
-       const struct ast_sorcery_object_field *field_left = obj;
-       const struct ast_sorcery_object_field *field_right = arg;
-       const char *right_key = arg;
-       int cmp;
+/*! \brief Hashing and comparison functions for sorcery wizards */
+AO2_STRING_FIELD_HASH_FN(ast_sorcery_internal_wizard, callbacks.name)
+AO2_STRING_FIELD_CMP_FN(ast_sorcery_internal_wizard, callbacks.name)
 
-       switch (flags & OBJ_SEARCH_MASK) {
-       case OBJ_SEARCH_OBJECT:
-               right_key = field_right->name;
-               /* Fall through */
-       case OBJ_SEARCH_KEY:
-               cmp = strcmp(field_left->name, right_key);
-               break;
-       case OBJ_SEARCH_PARTIAL_KEY:
-               cmp = strncmp(field_left->name, right_key, strlen(right_key));
-               break;
-       default:
-               cmp = 0;
-               break;
-       }
-       if (cmp) {
-               return 0;
-       }
-       return CMP_MATCH;
-}
+AO2_STRING_FIELD_HASH_FN(ast_sorcery_object_field, name)
+AO2_STRING_FIELD_CMP_FN(ast_sorcery_object_field, name)
 
 /*! \brief Cleanup function for graceful shutdowns */
 static void sorcery_cleanup(void)
@@ -447,53 +364,10 @@ static void sorcery_cleanup(void)
 }
 
 /*! \brief Compare function for sorcery instances */
-static int sorcery_instance_cmp(void *obj, void *arg, int flags)
-{
-       const struct ast_sorcery *object_left = obj;
-       const struct ast_sorcery *object_right = arg;
-       const char *right_key = arg;
-       int cmp;
-
-       switch (flags & OBJ_SEARCH_MASK) {
-       case OBJ_SEARCH_OBJECT:
-               right_key = object_right->module_name;
-               /* Fall through */
-       case OBJ_SEARCH_KEY:
-               cmp = strcmp(object_left->module_name, right_key);
-               break;
-       case OBJ_SEARCH_PARTIAL_KEY:
-               cmp = strncmp(object_left->module_name, right_key, strlen(right_key));
-               break;
-       default:
-               cmp = 0;
-               break;
-       }
-       if (cmp) {
-               return 0;
-       }
-       return CMP_MATCH;
-}
+AO2_STRING_FIELD_CMP_FN(sorcery_proxy, module_name)
 
 /*! \brief Hashing function for sorcery instances */
-static int sorcery_instance_hash(const void *obj, const int flags)
-{
-       const struct ast_sorcery *object;
-       const char *key;
-
-       switch (flags & OBJ_SEARCH_MASK) {
-       case OBJ_SEARCH_KEY:
-               key = obj;
-               break;
-       case OBJ_SEARCH_OBJECT:
-               object = obj;
-               key = object->module_name;
-               break;
-       default:
-               ast_assert(0);
-               return 0;
-       }
-       return ast_str_hash(key);
-}
+AO2_STRING_FIELD_HASH_FN(sorcery_proxy, module_name)
 
 int ast_sorcery_init(void)
 {
@@ -512,7 +386,7 @@ int ast_sorcery_init(void)
        }
 
        wizards = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, WIZARD_BUCKETS,
-               sorcery_wizard_hash, NULL, sorcery_wizard_cmp);
+               ast_sorcery_internal_wizard_hash_fn, NULL, ast_sorcery_internal_wizard_cmp_fn);
        if (!wizards) {
                sorcery_cleanup();
                return -1;
@@ -525,7 +399,7 @@ int ast_sorcery_init(void)
        }
 
        instances = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, INSTANCE_BUCKETS,
-               sorcery_instance_hash, NULL, sorcery_instance_cmp);
+               sorcery_proxy_hash_fn, NULL, sorcery_proxy_cmp_fn);
        if (!instances) {
                sorcery_cleanup();
                return -1;
@@ -704,103 +578,88 @@ static void sorcery_destructor(void *obj)
 }
 
 /*! \brief Hashing function for sorcery types */
-static int sorcery_type_hash(const void *obj, const int flags)
-{
-       const struct ast_sorcery_object_type *object;
-       const char *key;
+AO2_STRING_FIELD_HASH_FN(ast_sorcery_object_type, name)
+AO2_STRING_FIELD_CMP_FN(ast_sorcery_object_type, name)
 
-       switch (flags & OBJ_SEARCH_MASK) {
-       case OBJ_SEARCH_KEY:
-               key = obj;
-               break;
-       case OBJ_SEARCH_OBJECT:
-               object = obj;
-               key = object->name;
-               break;
-       default:
-               ast_assert(0);
-               return 0;
-       }
-       return ast_str_hash(key);
-}
-
-/*! \brief Comparator function for sorcery types */
-static int sorcery_type_cmp(void *obj, void *arg, int flags)
+static void sorcery_proxy_cb(void *weakproxy, void *data)
 {
-       const struct ast_sorcery_object_type *object_left = obj;
-       const struct ast_sorcery_object_type *object_right = arg;
-       const char *right_key = arg;
-       int cmp;
-
-       switch (flags & OBJ_SEARCH_MASK) {
-       case OBJ_SEARCH_OBJECT:
-               right_key = object_right->name;
-               /* Fall through */
-       case OBJ_SEARCH_KEY:
-               cmp = strcmp(object_left->name, right_key);
-               break;
-       case OBJ_SEARCH_PARTIAL_KEY:
-               cmp = strncmp(object_left->name, right_key, strlen(right_key));
-               break;
-       default:
-               cmp = 0;
-               break;
-       }
-       if (cmp) {
-               return 0;
-       }
-       return CMP_MATCH;
+       ao2_unlink(instances, weakproxy);
 }
 
-struct ast_sorcery *__ast_sorcery_open(const char *module_name)
+struct ast_sorcery *__ast_sorcery_open(const char *module_name, const char *file, int line, const char *func)
 {
+       struct sorcery_proxy *proxy;
        struct ast_sorcery *sorcery;
 
        ast_assert(module_name != NULL);
 
        ao2_wrlock(instances);
-       if ((sorcery = ao2_find(instances, module_name, OBJ_SEARCH_KEY | OBJ_NOLOCK))) {
-               goto done;
+       sorcery = __ao2_weakproxy_find(instances, module_name, OBJ_SEARCH_KEY | OBJ_NOLOCK,
+               __PRETTY_FUNCTION__, file, line, func);
+       if (sorcery) {
+               ao2_unlock(instances);
+
+               return sorcery;
        }
 
-       if (!(sorcery = ao2_alloc(sizeof(*sorcery) + strlen(module_name) + 1, sorcery_destructor))) {
-               goto done;
+       proxy = ao2_t_weakproxy_alloc(sizeof(*proxy) + strlen(module_name) + 1, NULL, module_name);
+       if (!proxy) {
+               goto failure_cleanup;
        }
+       strcpy(proxy->module_name, module_name); /* Safe */
 
-       if (!(sorcery->types = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, TYPE_BUCKETS, sorcery_type_hash, sorcery_type_cmp))) {
-               ao2_ref(sorcery, -1);
-               sorcery = NULL;
-               goto done;
+       sorcery = __ao2_alloc(sizeof(*sorcery), sorcery_destructor, AO2_ALLOC_OPT_LOCK_MUTEX, module_name, file, line, func);
+       if (!sorcery) {
+               goto failure_cleanup;
        }
 
-       if (!(sorcery->observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL))) {
-               ao2_ref(sorcery, -1);
-               sorcery = NULL;
-               goto done;
+       sorcery->module_name = proxy->module_name;
+
+       /* We have exclusive access to proxy and sorcery, no need for locking here. */
+       if (ao2_t_weakproxy_set_object(proxy, sorcery, OBJ_NOLOCK, "weakproxy link")) {
+               goto failure_cleanup;
        }
 
-       strcpy(sorcery->module_name, module_name); /* Safe */
+       if (ao2_weakproxy_subscribe(proxy, sorcery_proxy_cb, NULL, OBJ_NOLOCK)) {
+               goto failure_cleanup;
+       }
+
+       sorcery->types = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, TYPE_BUCKETS,
+               ast_sorcery_object_type_hash_fn, ast_sorcery_object_type_cmp_fn);
+       if (!sorcery->types) {
+               goto failure_cleanup;
+       }
+
+       if (!(sorcery->observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL))) {
+               goto failure_cleanup;
+       }
 
        if (__ast_sorcery_apply_config(sorcery, module_name, module_name) == AST_SORCERY_APPLY_FAIL) {
                ast_log(LOG_ERROR, "Error attempting to apply configuration %s to sorcery.\n", module_name);
-               ao2_cleanup(sorcery);
-               sorcery = NULL;
-               goto done;
+               goto failure_cleanup;
        }
 
-       ao2_link_flags(instances, sorcery, OBJ_NOLOCK);
+       ao2_link_flags(instances, proxy, OBJ_NOLOCK);
+       ao2_ref(proxy, -1);
 
        NOTIFY_GLOBAL_OBSERVERS(observers, instance_created, module_name, sorcery);
 
-done:
        ao2_unlock(instances);
        return sorcery;
+
+failure_cleanup:
+       /* cleanup of sorcery may result in locking instances, so make sure we unlock first. */
+       ao2_unlock(instances);
+       ao2_cleanup(sorcery);
+       ao2_cleanup(proxy);
+
+       return NULL;
 }
 
 /*! \brief Search function for sorcery instances */
 struct ast_sorcery *ast_sorcery_retrieve_by_module_name(const char *module_name)
 {
-       return ao2_find(instances, module_name, OBJ_SEARCH_KEY);
+       return ao2_weakproxy_find(instances, module_name, OBJ_SEARCH_KEY, "");
 }
 
 /*! \brief Destructor function for object types */
@@ -843,7 +702,7 @@ static struct ast_sorcery_object_type *sorcery_object_type_alloc(const char *typ
        }
 
        object_type->fields = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
-               OBJECT_FIELD_BUCKETS, object_type_field_hash, NULL, object_type_field_cmp);
+               OBJECT_FIELD_BUCKETS, ast_sorcery_object_field_hash_fn, NULL, ast_sorcery_object_field_cmp_fn);
        if (!object_type->fields) {
                ao2_ref(object_type, -1);
                return NULL;
@@ -976,16 +835,19 @@ enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sor
        RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, ao2_alloc(sizeof(*object_wizard), sorcery_object_wizard_destructor), ao2_cleanup);
        int created = 0;
 
-       if (!wizard) {
+       if (!object_wizard) {
+               return AST_SORCERY_APPLY_FAIL;
+       }
+
+       if (!wizard || wizard->callbacks.module != ast_module_running_ref(wizard->callbacks.module)) {
                ast_log(LOG_ERROR, "Wizard '%s' could not be applied to object type '%s' as it was not found\n",
                        name, type);
                return AST_SORCERY_APPLY_FAIL;
-       } else if (!object_wizard) {
-               return AST_SORCERY_APPLY_FAIL;
        }
 
        if (!object_type) {
                if (!(object_type = sorcery_object_type_alloc(type, module))) {
+                       ast_module_unref(wizard->callbacks.module);
                        return AST_SORCERY_APPLY_FAIL;
                }
                created = 1;
@@ -1002,6 +864,7 @@ enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sor
                        ast_debug(1, "Wizard %s already applied to object type %s\n",
                                        wizard->callbacks.name, object_type->name);
                        AST_VECTOR_RW_UNLOCK(&object_type->wizards);
+                       ast_module_unref(wizard->callbacks.module);
                        return AST_SORCERY_APPLY_DUPLICATE;
                }
        }
@@ -1012,11 +875,10 @@ enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sor
                ast_log(LOG_WARNING, "Wizard '%s' failed to open mapping for object type '%s' with data: %s\n",
                        name, object_type->name, S_OR(data, ""));
                AST_VECTOR_RW_UNLOCK(&object_type->wizards);
+               ast_module_unref(wizard->callbacks.module);
                return AST_SORCERY_APPLY_FAIL;
        }
 
-       ast_module_ref(wizard->callbacks.module);
-
        object_wizard->wizard = ao2_bump(wizard);
        object_wizard->caching = caching;
 
@@ -1598,6 +1460,7 @@ struct ast_json *ast_sorcery_objectset_json_create(const struct ast_sorcery *sor
        int res = 0;
 
        if (!object_type || !json) {
+               ast_json_unref(json);
                return NULL;
        }
 
@@ -1877,12 +1740,17 @@ static int sorcery_cache_create(void *obj, void *arg, int flags)
 
 void *ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
 {
-       RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
+       struct ast_sorcery_object_type *object_type;
        void *object = NULL;
        int i;
        unsigned int cached = 0;
 
-       if (!object_type || ast_strlen_zero(id)) {
+       if (ast_strlen_zero(id)) {
+               return NULL;
+       }
+
+       object_type = ao2_find(sorcery->types, type, OBJ_SEARCH_KEY);
+       if (!object_type) {
                return NULL;
        }
 
@@ -1910,6 +1778,7 @@ void *ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *
        }
        AST_VECTOR_RW_UNLOCK(&object_type->wizards);
 
+       ao2_ref(object_type, -1);
        return object;
 }
 
@@ -1994,6 +1863,36 @@ struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *so
        return objects;
 }
 
+struct ao2_container *ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len)
+{
+       RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
+       struct ao2_container *objects;
+       int i;
+
+       if (!object_type || !(objects = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
+               return NULL;
+       }
+
+       AST_VECTOR_RW_RDLOCK(&object_type->wizards);
+       for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
+               struct ast_sorcery_object_wizard *wizard =
+                       AST_VECTOR_GET(&object_type->wizards, i);
+
+               if (!wizard->wizard->callbacks.retrieve_prefix) {
+                       continue;
+               }
+
+               wizard->wizard->callbacks.retrieve_prefix(sorcery, wizard->data, object_type->name, objects, prefix, prefix_len);
+
+               if (wizard->caching && ao2_container_count(objects)) {
+                       break;
+               }
+       }
+       AST_VECTOR_RW_UNLOCK(&object_type->wizards);
+
+       return objects;
+}
+
 /*! \brief Internal function which returns if the wizard has created the object */
 static int sorcery_wizard_create(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details)
 {
@@ -2287,18 +2186,6 @@ int ast_sorcery_is_stale(const struct ast_sorcery *sorcery, void *object)
        return res;
 }
 
-void ast_sorcery_unref(struct ast_sorcery *sorcery)
-{
-       if (sorcery) {
-               /* One ref for what we just released, the other for the instances container. */
-               ao2_wrlock(instances);
-               if (ao2_ref(sorcery, -1) == 2) {
-                       ao2_unlink_flags(instances, sorcery, OBJ_NOLOCK);
-               }
-               ao2_unlock(instances);
-       }
-}
-
 const char *ast_sorcery_object_get_id(const void *object)
 {
        const struct ast_sorcery_object_details *details = object;