Merge "Astobj2: Fix initialization order of refdebug and AO2_DEBUG."
authorMatt Jordan <mjordan@digium.com>
Sat, 2 May 2015 15:17:31 +0000 (10:17 -0500)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Sat, 2 May 2015 15:17:31 +0000 (10:17 -0500)
main/pbx.c

index fee4191..45909f5 100644 (file)
@@ -72,6 +72,7 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/astobj2.h"
 #include "asterisk/stasis_channels.h"
 #include "asterisk/dial.h"
+#include "asterisk/vector.h"
 
 /*!
  * \note I M P O R T A N T :
@@ -1046,8 +1047,9 @@ struct ast_hint {
 
        char context_name[AST_MAX_CONTEXT];/*!< Context of destroyed hint extension. */
        char exten_name[AST_MAX_EXTENSION];/*!< Extension of destroyed hint extension. */
-};
 
+       AST_VECTOR(, char *) devices; /*!< Devices associated with the hint */
+};
 
 #define HINTDEVICE_DATA_LENGTH 16
 AST_THREADSTORAGE(hintdevice_data);
@@ -1077,15 +1079,28 @@ struct ast_hintdevice {
        char hintdevice[1];
 };
 
-
 /*!
  * \note Using the device for hash
  */
 static int hintdevice_hash_cb(const void *obj, const int flags)
 {
-       const struct ast_hintdevice *ext = obj;
+       const struct ast_hintdevice *ext;
+       const char *key;
 
-       return ast_str_case_hash(ext->hintdevice);
+       switch (flags & OBJ_SEARCH_MASK) {
+       case OBJ_SEARCH_KEY:
+               key = obj;
+               break;
+       case OBJ_SEARCH_OBJECT:
+               ext = obj;
+               key = ext->hintdevice;
+               break;
+       default:
+               ast_assert(0);
+               return 0;
+       }
+
+       return ast_str_case_hash(key);
 }
 /*!
  * \note Devices on hints are not unique so no CMP_STOP is returned
@@ -1094,29 +1109,58 @@ static int hintdevice_hash_cb(const void *obj, const int flags)
  */
 static int hintdevice_cmp_multiple(void *obj, void *arg, int flags)
 {
-       struct ast_hintdevice *ext = obj, *ext2 = arg;
+       struct ast_hintdevice *left = obj;
+       struct ast_hintdevice *right = arg;
+       const char *right_key = arg;
+       int cmp;
 
-       return !strcasecmp(ext->hintdevice, ext2->hintdevice) ? CMP_MATCH  : 0;
+       switch (flags & OBJ_SEARCH_MASK) {
+       case OBJ_SEARCH_OBJECT:
+               right_key = right->hintdevice;
+               /* Fall through */
+       case OBJ_SEARCH_KEY:
+               cmp = strcmp(left->hintdevice, right_key);
+               break;
+       case OBJ_SEARCH_PARTIAL_KEY:
+               /*
+               * We could also use a partial key struct containing a length
+               * so strlen() does not get called for every comparison instead.
+               */
+               cmp = strncmp(left->hintdevice, right_key, strlen(right_key));
+               break;
+       default:
+               ast_assert(0);
+               cmp = 0;
+               break;
+       }
+       return cmp ? 0 : CMP_MATCH;
 }
 
-/*
- * \details This is used with ao2_callback to remove old devices
- * when they are linked to the hint
-*/
-static int hintdevice_remove_cb(void *deviceobj, void *arg, int flags)
+/*! \internal \brief \c ao2_callback function to remove hintdevices */
+static int hintdevice_remove_cb(void *obj, void *arg, void *data, int flags)
 {
-       struct ast_hintdevice *device = deviceobj;
-       struct ast_hint *hint = arg;
+       struct ast_hintdevice *candidate = obj;
+       char *device = arg;
+       struct ast_hint *hint = data;
 
-       return (device->hint == hint) ? CMP_MATCH : 0;
+       if (!strcmp(candidate->hintdevice, device)
+               && candidate->hint == hint) {
+               return CMP_MATCH;
+       }
+       return 0;
 }
 
 static int remove_hintdevice(struct ast_hint *hint)
 {
-       /* iterate through all devices and remove the devices which are linked to this hint */
-       ao2_t_callback(hintdevices, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK,
-               hintdevice_remove_cb, hint,
-               "callback to remove all devices which are linked to a hint");
+       while (AST_VECTOR_SIZE(&hint->devices) > 0) {
+               char *device = AST_VECTOR_GET(&hint->devices, 0);
+
+               ao2_t_callback_data(hintdevices, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA,
+                       hintdevice_remove_cb, device, hint, "Remove device from container");
+               AST_VECTOR_REMOVE_UNORDERED(&hint->devices, 0);
+               ast_free(device);
+       }
+
        return 0;
 }
 
@@ -1161,18 +1205,32 @@ static int add_hintdevice(struct ast_hint *hint, const char *devicelist)
 
        /* Spit on '&' and ',' to handle presence hints as well */
        while ((cur = strsep(&parse, "&,"))) {
+               char *device_name;
+
                devicelength = strlen(cur);
                if (!devicelength) {
                        continue;
                }
+
+               device_name = ast_strdup(cur);
+               if (!device_name) {
+                       return -1;
+               }
+
                device = ao2_t_alloc(sizeof(*device) + devicelength, hintdevice_destroy,
                        "allocating a hintdevice structure");
                if (!device) {
+                       ast_free(device_name);
                        return -1;
                }
                strcpy(device->hintdevice, cur);
                ao2_ref(hint, +1);
                device->hint = hint;
+               if (AST_VECTOR_APPEND(&hint->devices, device_name)) {
+                       ast_free(device_name);
+                       ao2_ref(device, -1);
+                       return -1;
+               }
                ao2_t_link(hintdevices, device, "Linking device into hintdevice container.");
                ao2_t_ref(device, -1, "hintdevice is linked so we can unref");
        }
@@ -5385,7 +5443,7 @@ static void device_state_cb(void *unused, struct stasis_subscription *sub, struc
 
        ast_mutex_lock(&context_merge_lock);/* Hold off ast_merge_contexts_and_delete */
        dev_iter = ao2_t_callback(hintdevices,
-               OBJ_POINTER | OBJ_MULTIPLE,
+               OBJ_SEARCH_OBJECT | OBJ_MULTIPLE,
                hintdevice_cmp_multiple,
                cmpdevice,
                "find devices in container");
@@ -5697,6 +5755,7 @@ static int hint_id_cmp(void *obj, void *arg, int flags)
 static void destroy_hint(void *obj)
 {
        struct ast_hint *hint = obj;
+       int i;
 
        if (hint->callbacks) {
                struct ast_state_cb *state_cb;
@@ -5726,6 +5785,12 @@ static void destroy_hint(void *obj)
                }
                ao2_ref(hint->callbacks, -1);
        }
+
+       for (i = 0; i < AST_VECTOR_SIZE(&hint->devices); i++) {
+               char *device = AST_VECTOR_GET(&hint->devices, i);
+               ast_free(device);
+       }
+       AST_VECTOR_FREE(&hint->devices);
        ast_free(hint->last_presence_subtype);
        ast_free(hint->last_presence_message);
 }
@@ -5787,6 +5852,7 @@ static int ast_add_hint(struct ast_exten *e)
        if (!hint_new) {
                return -1;
        }
+       AST_VECTOR_INIT(&hint_new->devices, 8);
 
        /* Initialize new hint. */
        hint_new->callbacks = ao2_container_alloc(1, NULL, hint_id_cmp);
@@ -12526,14 +12592,17 @@ static int statecbs_cmp(void *obj, void *arg, int flags)
 static void pbx_shutdown(void)
 {
        if (hints) {
+               ao2_container_unregister("hints");
                ao2_ref(hints, -1);
                hints = NULL;
        }
        if (hintdevices) {
+               ao2_container_unregister("hintdevices");
                ao2_ref(hintdevices, -1);
                hintdevices = NULL;
        }
        if (statecbs) {
+               ao2_container_unregister("statecbs");
                ao2_ref(statecbs, -1);
                statecbs = NULL;
        }
@@ -12543,11 +12612,53 @@ static void pbx_shutdown(void)
        pbx_builtin_clear_globals();
 }
 
+static void print_hints_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
+{
+       struct ast_hint *hint = v_obj;
+
+       if (!hint) {
+               return;
+       }
+       prnt(where, "%s@%s", ast_get_extension_name(hint->exten),
+               ast_get_context_name(ast_get_extension_context(hint->exten)));
+}
+
+static void print_hintdevices_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
+{
+       struct ast_hintdevice *hintdevice = v_obj;
+
+       if (!hintdevice) {
+               return;
+       }
+       prnt(where, "%s => %s@%s", hintdevice->hintdevice,
+               ast_get_extension_name(hintdevice->hint->exten),
+               ast_get_context_name(ast_get_extension_context(hintdevice->hint->exten)));
+}
+
+static void print_statecbs_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
+{
+       struct ast_state_cb *state_cb = v_obj;
+
+       if (!state_cb) {
+               return;
+       }
+       prnt(where, "%d", state_cb->id);
+}
+
 int ast_pbx_init(void)
 {
        hints = ao2_container_alloc(HASH_EXTENHINT_SIZE, hint_hash, hint_cmp);
+       if (hints) {
+               ao2_container_register("hints", hints, print_hints_key);
+       }
        hintdevices = ao2_container_alloc(HASH_EXTENHINT_SIZE, hintdevice_hash_cb, hintdevice_cmp_multiple);
+       if (hintdevices) {
+               ao2_container_register("hintdevices", hintdevices, print_hintdevices_key);
+       }
        statecbs = ao2_container_alloc(1, NULL, statecbs_cmp);
+       if (statecbs) {
+               ao2_container_register("statecbs", statecbs, print_statecbs_key);
+       }
 
        ast_register_cleanup(pbx_shutdown);