summaryrefslogtreecommitdiff
path: root/main/sorcery.c
diff options
context:
space:
mode:
authorGeorge Joseph <george.joseph@fairview5.com>2015-05-05 14:32:08 -0600
committerGeorge Joseph <george.joseph@fairview5.com>2015-05-12 11:04:02 -0500
commit52407088f8574ae8fcca21a3dad83055ebf34a75 (patch)
tree92f4796e5d3c6669348b61d6eb5c964a78424b06 /main/sorcery.c
parent58d0db347eaccdb60538c73b7b6f8e035539a69e (diff)
sorcery: Add API to insert/remove a wizard to/from an object type's list
Currently you can 'apply' a wizard to an object type but the wizard always goes at the end of the object type's wizard list. This patch adds a new ast_sorcery_insert_wizard_mapping function that allows you to insert a wizard anyplace in the list. I.E. You could add a caching wizard to an object type and place it before all wizards. ast_sorcery_get_wizard_mapping_count and ast_sorcery_get_wizard_mapping were added to allow examination of the mapping list. ast_sorcery_remove_mapping was added to remove a mapping by name. As part of this patch, the object type's wizard list was converted from an ao2_container to an AST_VECTOR_RW. A new test was added to test_sorcery for this capability. ASTERISK-25044 #close Change-Id: I9d2469a9296b2698082c0989e25e6848dc403b57
Diffstat (limited to 'main/sorcery.c')
-rw-r--r--main/sorcery.c273
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;
}