diff options
Diffstat (limited to 'main/sorcery.c')
-rw-r--r-- | main/sorcery.c | 273 |
1 files changed, 201 insertions, 72 deletions
diff --git a/main/sorcery.c b/main/sorcery.c index 1a4b3a072..c77954897 100644 --- a/main/sorcery.c +++ b/main/sorcery.c @@ -43,6 +43,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/taskprocessor.h" #include "asterisk/threadpool.h" #include "asterisk/json.h" +#include "asterisk/vector.h" /* To prevent DEBUG_FD_LEAKS from interfering with things we undef open and close */ #undef open @@ -86,6 +87,35 @@ ASTERISK_REGISTER_FILE() /*! \brief Thread pool for observers */ static struct ast_threadpool *threadpool; +/*! \brief Structure for an internal wizard instance */ +struct ast_sorcery_internal_wizard { + /*! + * \brief Wizard interface itself + * \warning Callbacks must always be declared first in this structure + * so an ao2_ref on &callbacks will adjust the ref count on + * internal_wizard. + */ + struct ast_sorcery_wizard callbacks; + + /*! \brief Observers */ + struct ao2_container *observers; +}; + +/*! \brief Structure for a wizard instance which operates on objects */ +struct ast_sorcery_object_wizard { + /*! \brief Wizard interface itself */ + struct ast_sorcery_internal_wizard *wizard; + + /*! \brief Unique data for the wizard */ + void *data; + + /*! \brief Wizard is acting as an object cache */ + unsigned int caching:1; +}; + +/*! \brief Interface for a sorcery object type wizards */ +AST_VECTOR_RW(ast_sorcery_object_wizards, struct ast_sorcery_object_wizard *); + /*! \brief Structure for internal sorcery object information */ struct ast_sorcery_object { /*! \brief Unique identifier of this object */ @@ -119,7 +149,7 @@ struct ast_sorcery_object_type { sorcery_diff_handler diff; /*! \brief Wizard instances */ - struct ao2_container *wizards; + struct ast_sorcery_object_wizards wizards; /*! \brief Object fields */ struct ao2_container *fields; @@ -176,27 +206,6 @@ struct ast_sorcery_object_field { intptr_t args[]; }; -/*! \brief Structure for an internal wizard instance */ -struct ast_sorcery_internal_wizard { - /*! \brief Wizard interface itself */ - struct ast_sorcery_wizard callbacks; - - /*! \brief Observers */ - struct ao2_container *observers; -}; - -/*! \brief Structure for a wizard instance which operates on objects */ -struct ast_sorcery_object_wizard { - /*! \brief Wizard interface itself */ - struct ast_sorcery_internal_wizard *wizard; - - /*! \brief Unique data for the wizard */ - void *data; - - /*! \brief Wizard is acting as an object cache */ - unsigned int caching:1; -}; - /*! \brief Full structure for sorcery */ struct ast_sorcery { /*! \brief Container for known object types */ @@ -789,7 +798,10 @@ static void sorcery_object_type_destructor(void *obj) { struct ast_sorcery_object_type *object_type = obj; - ao2_cleanup(object_type->wizards); + AST_VECTOR_RW_WRLOCK(&object_type->wizards); + AST_VECTOR_CALLBACK_VOID(&object_type->wizards, ao2_cleanup); + AST_VECTOR_RW_UNLOCK(&object_type->wizards); + AST_VECTOR_RW_FREE(&object_type->wizards); ao2_cleanup(object_type->fields); ao2_cleanup(object_type->observers); @@ -806,6 +818,7 @@ static void sorcery_object_type_destructor(void *obj) /*! \brief Internal function which allocates an object type structure */ static struct ast_sorcery_object_type *sorcery_object_type_alloc(const char *type, const char *module) { +#define INITIAL_WIZARD_VECTOR_SIZE 5 struct ast_sorcery_object_type *object_type; char uuid[AST_UUID_STR_LEN]; @@ -814,7 +827,7 @@ static struct ast_sorcery_object_type *sorcery_object_type_alloc(const char *typ } /* Order matters for object wizards */ - if (!(object_type->wizards = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, sorcery_wizard_cmp))) { + if (AST_VECTOR_RW_INIT(&object_type->wizards, INITIAL_WIZARD_VECTOR_SIZE) != 0) { ao2_ref(object_type, -1); return NULL; } @@ -864,7 +877,7 @@ static void sorcery_object_wizard_destructor(void *obj) { struct ast_sorcery_object_wizard *object_wizard = obj; - if (object_wizard->data) { + if (object_wizard->data && object_wizard->wizard->callbacks.close) { object_wizard->wizard->callbacks.close(object_wizard->data); } @@ -875,9 +888,73 @@ static void sorcery_object_wizard_destructor(void *obj) ao2_cleanup(object_wizard->wizard); } -/*! \brief Internal function which creates an object type and adds a wizard mapping */ -enum ast_sorcery_apply_result __ast_sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery, - const char *type, const char *module, const char *name, const char *data, unsigned int caching) +/*! \brief Return the number of wizards mapped to an object type */ +int ast_sorcery_get_wizard_mapping_count(struct ast_sorcery *sorcery, + const char *type) +{ + RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup); + + if (!object_type) { + return -1; + } + + return AST_VECTOR_SIZE(&object_type->wizards); +} + +int ast_sorcery_get_wizard_mapping(struct ast_sorcery *sorcery, + const char *type, int index, struct ast_sorcery_wizard **wizard, void **data) +{ + RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup); + struct ast_sorcery_object_wizard *owizard; + + if (!object_type) { + return -1; + } + + if (index < 0 || index >= AST_VECTOR_SIZE(&object_type->wizards)) { + return -1; + } + + owizard = AST_VECTOR_GET(&object_type->wizards, index); + + if (wizard != NULL) { + *wizard = &(owizard->wizard->callbacks); + ao2_bump(owizard->wizard); + } else { + return -1; + } + + if (data != NULL) { + *data = owizard->data; + } + + return 0; +} + +/*! \brief Internal function removes a wizard mapping */ +int __ast_sorcery_remove_wizard_mapping(struct ast_sorcery *sorcery, + const char *type, const char *module, const char *name) +{ + RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup); + int res; + + if (!object_type) { + return -1; + } + + AST_VECTOR_RW_WRLOCK(&object_type->wizards); +#define WIZARD_NAME_COMPARE(a, b) (strcmp((a)->wizard->callbacks.name, (b)) == 0) + res = AST_VECTOR_REMOVE_CMP_ORDERED(&object_type->wizards, name, WIZARD_NAME_COMPARE, ao2_cleanup); +#undef WIZARD_NAME_COMPARE + AST_VECTOR_RW_UNLOCK(&object_type->wizards); + + return res; +} + +/*! \brief Internal function which creates an object type and inserts a wizard mapping */ +enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sorcery *sorcery, + const char *type, const char *module, const char *name, const char *data, + unsigned int caching, int position) { RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup); RAII_VAR(struct ast_sorcery_internal_wizard *, wizard, ao2_find(wizards, name, OBJ_KEY), ao2_cleanup); @@ -899,19 +976,23 @@ enum ast_sorcery_apply_result __ast_sorcery_apply_wizard_mapping(struct ast_sorc created = 1; } + AST_VECTOR_RW_WRLOCK(&object_type->wizards); if (!created) { - struct ast_sorcery_wizard *found; + struct ast_sorcery_object_wizard *found; - found = ao2_find(object_type->wizards, wizard, OBJ_SEARCH_OBJECT); +#define WIZARD_COMPARE(a, b) ((a)->wizard == (b)) + found = AST_VECTOR_GET_CMP(&object_type->wizards, wizard, WIZARD_COMPARE); +#undef WIZARD_COMPARE if (found) { ast_debug(1, "Wizard %s already applied to object type %s\n", wizard->callbacks.name, object_type->name); - ao2_cleanup(found); + AST_VECTOR_RW_UNLOCK(&object_type->wizards); return AST_SORCERY_APPLY_DUPLICATE; } } if (wizard->callbacks.open && !(object_wizard->data = wizard->callbacks.open(data))) { + AST_VECTOR_RW_UNLOCK(&object_type->wizards); return AST_SORCERY_APPLY_FAIL; } @@ -920,7 +1001,16 @@ enum ast_sorcery_apply_result __ast_sorcery_apply_wizard_mapping(struct ast_sorc object_wizard->wizard = ao2_bump(wizard); object_wizard->caching = caching; - ao2_link(object_type->wizards, object_wizard); + if (position == AST_SORCERY_WIZARD_POSITION_LAST) { + position = AST_VECTOR_SIZE(&object_type->wizards); + } + + if (AST_VECTOR_INSERT_AT(&object_type->wizards, position, object_wizard) != 0) { + AST_VECTOR_RW_UNLOCK(&object_type->wizards); + return AST_SORCERY_APPLY_FAIL; + } + AST_VECTOR_RW_UNLOCK(&object_type->wizards); + ao2_bump(object_wizard); if (created) { ao2_link(sorcery->types, object_type); @@ -932,6 +1022,14 @@ enum ast_sorcery_apply_result __ast_sorcery_apply_wizard_mapping(struct ast_sorc return AST_SORCERY_APPLY_SUCCESS; } +/*! \brief Internal function which creates an object type and adds a wizard mapping */ +enum ast_sorcery_apply_result __ast_sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery, + const char *type, const char *module, const char *name, const char *data, unsigned int caching) +{ + return __ast_sorcery_insert_wizard_mapping(sorcery, type, module, name, data, + caching, AST_SORCERY_WIZARD_POSITION_LAST); +} + enum ast_sorcery_apply_result __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, const char *module) { struct ast_flags flags = { 0 }; @@ -1260,7 +1358,9 @@ static int sorcery_object_load(void *obj, void *arg, int flags) NOTIFY_INSTANCE_OBSERVERS(details->sorcery->observers, object_type_loading, details->sorcery->module_name, details->sorcery, type->name, details->reload); - ao2_callback(type->wizards, OBJ_NODATA, sorcery_wizard_load, details); + AST_VECTOR_RW_RDLOCK(&type->wizards); + AST_VECTOR_CALLBACK(&type->wizards, sorcery_wizard_load, NULL, details, 0); + AST_VECTOR_RW_UNLOCK(&type->wizards); NOTIFY_INSTANCE_OBSERVERS(details->sorcery->observers, object_type_loaded, details->sorcery->module_name, details->sorcery, type->name, details->reload); @@ -1700,31 +1800,31 @@ void *ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char * { RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup); void *object = NULL; - struct ao2_iterator i; - struct ast_sorcery_object_wizard *wizard; + int i; unsigned int cached = 0; if (!object_type || ast_strlen_zero(id)) { return NULL; } - i = ao2_iterator_init(object_type->wizards, 0); - for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) { + 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_id && !(object = wizard->wizard->callbacks.retrieve_id(sorcery, wizard->data, object_type->name, id))) { continue; } cached = wizard->caching; - - ao2_ref(wizard, -1); break; } - ao2_iterator_destroy(&i); if (!cached && object) { - ao2_callback(object_type->wizards, 0, sorcery_cache_create, object); + AST_VECTOR_CALLBACK(&object_type->wizards, sorcery_cache_create, NULL, object, 0); } + AST_VECTOR_RW_UNLOCK(&object_type->wizards); return object; } @@ -1733,8 +1833,7 @@ void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const ch { RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup); void *object = NULL; - struct ao2_iterator i; - struct ast_sorcery_object_wizard *wizard; + int i; unsigned int cached = 0; if (!object_type) { @@ -1748,9 +1847,11 @@ void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const ch } } - /* Inquire with the available wizards for retrieval */ - i = ao2_iterator_init(object_type->wizards, 0); - for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) { + 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 ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) { if (wizard->wizard->callbacks.retrieve_multiple) { wizard->wizard->callbacks.retrieve_multiple(sorcery, wizard->data, object_type->name, object, fields); @@ -1767,15 +1868,14 @@ void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const ch cached = wizard->caching; - ao2_ref(wizard, -1); break; } - ao2_iterator_destroy(&i); /* If we are returning a single object and it came from a non-cache source create it in any caches */ if (!(flags & AST_RETRIEVE_FLAG_MULTIPLE) && !cached && object) { - ao2_callback(object_type->wizards, 0, sorcery_cache_create, object); + AST_VECTOR_CALLBACK(&object_type->wizards, sorcery_cache_create, NULL, object, 0); } + AST_VECTOR_RW_UNLOCK(&object_type->wizards); return object; } @@ -1784,22 +1884,24 @@ struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *so { RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup); struct ao2_container *objects; - struct ao2_iterator i; - struct ast_sorcery_object_wizard *wizard; + int i; if (!object_type || !(objects = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) { return NULL; } - i = ao2_iterator_init(object_type->wizards, 0); - for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) { + 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_regex) { continue; } wizard->wizard->callbacks.retrieve_regex(sorcery, wizard->data, object_type->name, objects, regex); } - ao2_iterator_destroy(&i); + AST_VECTOR_RW_UNLOCK(&object_type->wizards); return objects; } @@ -1846,7 +1948,9 @@ int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object) { const struct ast_sorcery_object_details *details = object; RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup); - RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup); + struct ast_sorcery_object_wizard *object_wizard = NULL; + struct ast_sorcery_object_wizard *found_wizard; + int i; struct sorcery_details sdetails = { .sorcery = sorcery, .obj = object, @@ -1856,14 +1960,21 @@ int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object) return -1; } - if ((object_wizard = ao2_callback(object_type->wizards, 0, sorcery_wizard_create, &sdetails)) && - ao2_container_count(object_type->observers)) { - struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object); + AST_VECTOR_RW_RDLOCK(&object_type->wizards); + for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) { + found_wizard = AST_VECTOR_GET(&object_type->wizards, i); + if (sorcery_wizard_create(found_wizard, &sdetails, 0) == (CMP_MATCH | CMP_STOP)) { + object_wizard = found_wizard; + if(ao2_container_count(object_type->observers)) { + struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object); - if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_create, invocation)) { - ao2_cleanup(invocation); + if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_create, invocation)) { + ao2_cleanup(invocation); + } + } } } + AST_VECTOR_RW_UNLOCK(&object_type->wizards); return object_wizard ? 0 : -1; } @@ -1905,7 +2016,9 @@ int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object) { const struct ast_sorcery_object_details *details = object; RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup); - RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup); + struct ast_sorcery_object_wizard *object_wizard = NULL; + struct ast_sorcery_object_wizard *found_wizard; + int i; struct sorcery_details sdetails = { .sorcery = sorcery, .obj = object, @@ -1915,14 +2028,21 @@ int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object) return -1; } - if ((object_wizard = ao2_callback(object_type->wizards, 0, sorcery_wizard_update, &sdetails)) && - ao2_container_count(object_type->observers)) { - struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object); + AST_VECTOR_RW_RDLOCK(&object_type->wizards); + for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) { + found_wizard = AST_VECTOR_GET(&object_type->wizards, i); + if (sorcery_wizard_update(found_wizard, &sdetails, 0) == (CMP_MATCH | CMP_STOP)) { + object_wizard = found_wizard; + if (ao2_container_count(object_type->observers)) { + struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object); - if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_update, invocation)) { - ao2_cleanup(invocation); + if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_update, invocation)) { + ao2_cleanup(invocation); + } + } } } + AST_VECTOR_RW_UNLOCK(&object_type->wizards); return object_wizard ? 0 : -1; } @@ -1964,7 +2084,9 @@ int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object) { const struct ast_sorcery_object_details *details = object; RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup); - RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup); + struct ast_sorcery_object_wizard *object_wizard = NULL; + struct ast_sorcery_object_wizard *found_wizard; + int i; struct sorcery_details sdetails = { .sorcery = sorcery, .obj = object, @@ -1974,14 +2096,21 @@ int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object) return -1; } - if ((object_wizard = ao2_callback(object_type->wizards, 0, sorcery_wizard_delete, &sdetails)) && - ao2_container_count(object_type->observers)) { - struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object); + AST_VECTOR_RW_RDLOCK(&object_type->wizards); + for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) { + found_wizard = AST_VECTOR_GET(&object_type->wizards, i); + if (sorcery_wizard_delete(found_wizard, &sdetails, 0) == (CMP_MATCH | CMP_STOP)) { + object_wizard = found_wizard; + if (ao2_container_count(object_type->observers)) { + struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object); - if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_delete, invocation)) { - ao2_cleanup(invocation); + if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_delete, invocation)) { + ao2_cleanup(invocation); + } + } } } + AST_VECTOR_RW_UNLOCK(&object_type->wizards); return object_wizard ? 0 : -1; } |