Index: apps/app_queue.c =================================================================== --- apps/app_queue.c (revision 229361) +++ apps/app_queue.c (working copy) @@ -95,6 +95,8 @@ #include "asterisk/global_datastores.h" #include "asterisk/taskprocessor.h" +#define REF_DEBUG_ONLY_QUEUES + /*! * \par Please read before modifying this file. * There are three locks which are regularly used @@ -600,6 +602,18 @@ return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0; } +#ifdef REF_DEBUG_ONLY_QUEUES +#define queue_ref(a) _ao2_ref_debug(a,1,"",__FILE__,__LINE__,__PRETTY_FUNCTION__) +#define queue_unref(a) _ao2_ref_debug(a,-1,"",__FILE__,__LINE__,__PRETTY_FUNCTION__) +#define queue_t_ref(a,b) _ao2_ref_debug(a,1,b,__FILE__,__LINE__,__PRETTY_FUNCTION__) +#define queue_t_unref(a,b) _ao2_ref_debug(a,-1,b,__FILE__,__LINE__,__PRETTY_FUNCTION__) +#define queues_t_link(c,q,tag) _ao2_link_debug(c,q,tag,__FILE__,__LINE__,__PRETTY_FUNCTION__) +#define queues_t_unlink(c,q,tag) _ao2_unlink_debug(c,q,tag,__FILE__,__LINE__,__PRETTY_FUNCTION__) +#else +#define queue_t_ref(a,b) queue_ref(a) +#define queue_t_unref(a,b) queue_unref(a) +#define queues_t_link(c,q,tag) ao2_t_link(c,q,tag) +#define queues_t_unlink(c,q,tag) ao2_t_unlink(c,q,tag) static inline struct call_queue *queue_ref(struct call_queue *q) { ao2_ref(q, 1); @@ -611,6 +625,7 @@ ao2_ref(q, -1); return q; } +#endif /*! \brief Set variables of queue */ static void set_queue_variables(struct call_queue *q, struct ast_channel *chan) @@ -721,7 +736,7 @@ char tmp_interface[80]; queue_iter = ao2_iterator_init(queues, 0); - while ((q = ao2_iterator_next(&queue_iter))) { + while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { ao2_lock(q); mem_iter = ao2_iterator_init(q->members, 0); while ((cur = ao2_iterator_next(&mem_iter))) { @@ -758,7 +773,7 @@ } ao2_ref(cur, -1); } - queue_unref(q); + queue_t_unref(q, "Done with iterator"); ao2_unlock(q); } @@ -995,7 +1010,7 @@ ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); queue_iter = ao2_iterator_init(queues, lock_queue_container ? 0 : AO2_ITERATOR_DONTLOCK); - while ((q = ao2_iterator_next(&queue_iter))) { + while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { ao2_lock(q); mem_iter = ao2_iterator_init(q->members, 0); while ((mem = ao2_iterator_next(&mem_iter))) { @@ -1007,7 +1022,7 @@ } ao2_iterator_destroy(&mem_iter); ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Done with iterator"); } ao2_iterator_destroy(&queue_iter); @@ -1442,9 +1457,9 @@ { struct call_queue *q; - if ((q = ao2_alloc(sizeof(*q), destroy_queue))) { + if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) { if (ast_string_field_init(q, 64)) { - ao2_ref(q, -1); + ao2_t_ref(q, -1, "String field allocation failed"); return NULL; } ast_string_field_set(q, name, queuename); @@ -1476,12 +1491,12 @@ char tmpbuf[64]; /* Must be longer than the longest queue param name. */ /* Static queues override realtime. */ - if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { + if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) { ao2_lock(q); if (!q->realtime) { if (q->dead) { ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Queue is dead; can't return it"); return NULL; } else { ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name); @@ -1489,7 +1504,6 @@ return q; } } - queue_unref(q); } else if (!member_config) /* Not found in the list, and it's not realtime ... */ return NULL; @@ -1505,9 +1519,9 @@ q->dead = 1; /* Delete if unused (else will be deleted when last caller leaves). */ - ao2_unlink(queues, q); + queues_t_unlink(queues, q, "Unused, removing from container"); ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Queue is dead; can't return it"); } return NULL; } @@ -1537,7 +1551,7 @@ /* We traversed all variables and didn't find a strategy */ if (!tmpvar) q->strategy = QUEUE_STRATEGY_RINGALL; - ao2_link(queues, q); + queues_t_link(queues, q, "Add queue to container"); } init_queue(q); /* Ensure defaults for all parameters not set explicitly. */ @@ -1606,7 +1620,7 @@ }; /* Find the queue in the in-core list first. */ - q = ao2_find(queues, &tmpq, OBJ_POINTER); + q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first"); if (!q || q->realtime) { /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all @@ -2016,7 +2030,7 @@ if (!(q = qe->parent)) return; - queue_ref(q); + queue_t_ref(q, "Copy queue pointer from queue entry"); ao2_lock(q); prev = NULL; @@ -2057,10 +2071,10 @@ if (q->dead) { /* It's dead and nobody is in it, so kill it */ - ao2_unlink(queues, q); + queues_t_unlink(queues, q, "Queue is now dead; remove it from the container"); } /* unref the explicit ref earlier in the function */ - queue_unref(q); + queue_t_unref(q, "Expire copied reference"); } /*! \brief Hang up a list of outgoing calls */ @@ -2141,9 +2155,9 @@ /* q's lock and rq's lock already set by try_calling() * to solve deadlock */ queue_iter = ao2_iterator_init(queues, 0); - while ((q = ao2_iterator_next(&queue_iter))) { + while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { if (q == rq) { /* don't check myself, could deadlock */ - queue_unref(q); + queue_t_unref(q, "Done with iterator"); continue; } ao2_lock(q); @@ -2158,7 +2172,7 @@ } } ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Done with iterator"); if (found) { break; } @@ -3064,7 +3078,7 @@ if (shared_lastcall) { queue_iter = ao2_iterator_init(queues, 0); - while ((qtmp = ao2_iterator_next(&queue_iter))) { + while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { ao2_lock(qtmp); if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) { time(&mem->lastcall); @@ -3318,7 +3332,7 @@ set_queue_variables(q, chan); ao2_unlock(q); /* This unrefs the reference we made in try_calling when we allocated qeb */ - queue_unref(q); + queue_t_unref(q, "Expire bridge_config reference"); } } @@ -4041,7 +4055,7 @@ * to make sure to increase the refcount of this queue so it cannot be freed until we * are done with it. We remove this reference in end_bridge_callback. */ - queue_ref(qe->parent); + queue_t_ref(qe->parent, "For bridge_config reference"); } time(&callstart); @@ -4184,7 +4198,7 @@ int res = RES_NOSUCHQUEUE; ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); - if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { + if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) { ao2_lock(queues); ao2_lock(q); if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) { @@ -4192,7 +4206,7 @@ if (!mem->dynamic) { ao2_ref(mem, -1); ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference"); ao2_unlock(queues); return RES_NOT_DYNAMIC; } @@ -4215,7 +4229,7 @@ } ao2_unlock(q); ao2_unlock(queues); - queue_unref(q); + queue_t_unref(q, "Expiring temporary reference"); } return res; @@ -4297,7 +4311,7 @@ ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); queue_iter = ao2_iterator_init(queues, 0); - while ((q = ao2_iterator_next(&queue_iter))) { + while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { ao2_lock(q); if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { if ((mem = interface_exists(q, interface))) { @@ -4314,6 +4328,7 @@ ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface); ao2_ref(mem, -1); ao2_unlock(q); + queue_t_unref(q, "Done with iterator"); continue; } found++; @@ -4346,12 +4361,12 @@ if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) { ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Done with iterator"); break; } ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Done with iterator"); } ao2_iterator_destroy(&queue_iter); @@ -4372,7 +4387,7 @@ } queue_iter = ao2_iterator_init(queues, 0); - while ((q = ao2_iterator_next(&queue_iter))) { + while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { ao2_lock(q); if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { foundqueue++; @@ -4390,7 +4405,7 @@ } } ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Done with iterator"); } ao2_iterator_destroy(&queue_iter); @@ -4416,18 +4431,18 @@ }; struct member *mem; - if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { + if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Search for queue"))) { foundqueue = 1; ao2_lock(q); if ((mem = interface_exists(q, interface))) { penalty = mem->penalty; ao2_ref(mem, -1); ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Search complete"); return penalty; } ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Search complete"); } /* some useful debuging */ @@ -4469,7 +4484,7 @@ struct call_queue tmpq = { .name = queue_name, }; - cur_queue = ao2_find(queues, &tmpq, OBJ_POINTER); + cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members"); } if (!cur_queue) @@ -4484,7 +4499,7 @@ } if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) { - queue_unref(cur_queue); + queue_t_unref(cur_queue, "Expire reload reference"); continue; } @@ -4526,7 +4541,7 @@ break; } } - queue_unref(cur_queue); + queue_t_unref(cur_queue, "Expire reload reference"); } ao2_unlock(queues); @@ -5128,7 +5143,7 @@ return -1; } - if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { + if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE() function"))) { ao2_lock(q); if (q->setqueuevar) { sl = 0; @@ -5146,7 +5161,7 @@ } ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Done with temporary reference in QUEUE() function"); } else { ast_log(LOG_WARNING, "queue %s was not found\n", data); } @@ -5203,7 +5218,7 @@ } else /* must be "count" */ count = q->membercount; ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()"); } else ast_log(LOG_WARNING, "queue %s was not found\n", data); @@ -5247,7 +5262,7 @@ } ao2_iterator_destroy(&mem_iter); ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT"); } else ast_log(LOG_WARNING, "queue %s was not found\n", data); @@ -5272,11 +5287,11 @@ return -1; } - if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { + if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) { ao2_lock(q); count = q->count; ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Done with find for QUEUE_WAITING_COUNT"); } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) { /* if the queue is realtime but was not found in memory, this * means that the queue had been deleted from memory since it was @@ -5308,7 +5323,7 @@ return -1; } - if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { + if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_MEMBER_LIST()"))) { int buflen = 0, count = 0; struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); @@ -5331,7 +5346,7 @@ } ao2_iterator_destroy(&mem_iter); ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Done with find for QUEUE_MEMBER_LIST()"); } else ast_log(LOG_WARNING, "queue %s was not found\n", data); @@ -5560,12 +5575,12 @@ use_weight=0; /* Mark all queues as dead for the moment */ queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK); - while ((q = ao2_iterator_next(&queue_iter))) { + while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { if (!q->realtime) { q->dead = 1; q->found = 0; } - queue_unref(q); + queue_t_unref(q, "Done with iterator"); } /* Chug through config file */ @@ -5598,7 +5613,7 @@ struct call_queue tmpq = { .name = cat, }; - if (!(q = ao2_find(queues, &tmpq, OBJ_POINTER))) { + if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Verify whether we exist or not"))) { /* Make one then */ if (!(q = alloc_queue(cat))) { /* TODO: Handle memory allocation failure */ @@ -5615,7 +5630,7 @@ ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat); if (!new) { ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "We exist! Expiring temporary pointer"); } continue; } @@ -5720,18 +5735,18 @@ } if (new) { - ao2_link(queues, q); + queues_t_link(queues, q, "Add queue to container"); } else ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Added queue to container, deleting creation pointer"); } } } ast_config_destroy(cfg); queue_iter = ao2_iterator_init(queues, 0); - while ((q = ao2_iterator_next(&queue_iter))) { + while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { if (q->dead) { - ao2_unlink(queues, q); + queues_t_unlink(queues, q, "Remove queue from container because marked as dead"); } else { ao2_lock(q); mem_iter = ao2_iterator_init(q->members, 0); @@ -5743,7 +5758,7 @@ } ao2_unlock(q); } - queue_unref(q); + queue_t_unref(q, "Done with iterator"); } ao2_unlock(queues); return 1; @@ -5778,7 +5793,7 @@ if (argc == 3) { /* specific queue */ if ((q = load_realtime_queue(argv[2]))) { - queue_unref(q); + queue_t_unref(q, "Expiring queue loaded from realtime"); } } else if (ast_check_realtime("queues")) { /* This block is to find any queues which are defined in realtime but @@ -5789,7 +5804,7 @@ if (cfg) { for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) { if ((q = load_realtime_queue(queuename))) { - queue_unref(q); + queue_t_unref(q, "Expiring queue loaded from realtime"); } } ast_config_destroy(cfg); @@ -5798,7 +5813,7 @@ queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK); ao2_lock(queues); - while ((q = ao2_iterator_next(&queue_iter))) { + while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { float sl; struct call_queue *realtime_queue = NULL; @@ -5809,14 +5824,14 @@ */ if (q->realtime && !(realtime_queue = load_realtime_queue(q->name))) { ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Done with iterator"); continue; } else if (q->realtime) { - queue_unref(realtime_queue); + queue_t_unref(realtime_queue, "Expire queue loaded from realtime"); } if (argc == 3 && strcasecmp(q->name, argv[2])) { ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Done with iterator"); continue; } found = 1; @@ -5878,7 +5893,7 @@ } do_print(s, fd, ""); /* blank line between entries */ ao2_unlock(q); - queue_unref(q); /* Unref the iterator's reference */ + queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */ } ao2_iterator_destroy(&queue_iter); ao2_unlock(queues); @@ -5901,13 +5916,13 @@ struct ao2_iterator queue_iter; queue_iter = ao2_iterator_init(queues, 0); - while ((q = ao2_iterator_next(&queue_iter))) { + while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { if (!strncasecmp(word, q->name, wordlen) && ++which > state) { ret = ast_strdup(q->name); - queue_unref(q); + queue_t_unref(q, "Done with iterator"); break; } - queue_unref(q); + queue_t_unref(q, "Done with iterator"); } ao2_iterator_destroy(&queue_iter); @@ -5996,7 +6011,7 @@ if (!ast_strlen_zero(id)) snprintf(idText, 256, "ActionID: %s\r\n", id); queue_iter = ao2_iterator_init(queues, 0); - while ((q = ao2_iterator_next(&queue_iter))) { + while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { ao2_lock(q); /* List queue properties */ @@ -6037,7 +6052,7 @@ q->name, qmemcount, qmemavail, qchancount, q->holdtime, qlongestholdtime, idText); } ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Done with iterator"); } ao2_iterator_destroy(&queue_iter); astman_append(s, @@ -6070,7 +6085,7 @@ snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); queue_iter = ao2_iterator_init(queues, 0); - while ((q = ao2_iterator_next(&queue_iter))) { + while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { ao2_lock(q); /* List queue properties */ @@ -6132,7 +6147,7 @@ } } ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Done with iterator"); } ao2_iterator_destroy(&queue_iter); @@ -6424,7 +6439,7 @@ /* here is the case for 3, */ queue_iter = ao2_iterator_init(queues, 0); - while ((q = ao2_iterator_next(&queue_iter))) { + while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { ao2_lock(q); mem_iter = ao2_iterator_init(q->members, 0); while ((m = ao2_iterator_next(&mem_iter))) { @@ -6433,7 +6448,7 @@ ao2_unlock(q); tmp = ast_strdup(m->interface); ao2_ref(m, -1); - queue_unref(q); + queue_t_unref(q, "Done with iterator"); ao2_iterator_destroy(&mem_iter); ao2_iterator_destroy(&queue_iter); return tmp; @@ -6442,7 +6457,7 @@ } ao2_iterator_destroy(&mem_iter); ao2_unlock(q); - queue_unref(q); + queue_t_unref(q, "Done with iterator"); } ao2_iterator_destroy(&queue_iter); @@ -6757,9 +6772,9 @@ clear_and_free_interfaces(); q_iter = ao2_iterator_init(queues, 0); - while ((q = ao2_iterator_next(&q_iter))) { - ao2_unlink(queues, q); - queue_unref(q); + while ((q = ao2_t_iterator_next(&q_iter, "Iterate through queues"))) { + queues_t_unlink(queues, q, "Remove queue from container due to unload"); + queue_t_unref(q, "Done with iterator"); } ao2_iterator_destroy(&q_iter); ao2_ref(queues, -1);