mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-23 21:19:09 +00:00
Found a few places where queue refcounts were counted incorrectly. Also add debug statements.
(closes issue #15982, closes issue #15984) Reported by: atis Patches: 20091111__issue15982.diff.txt uploaded by tilghman (license 14) Tested by: atis git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@231134 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
157
apps/app_queue.c
157
apps/app_queue.c
@@ -97,6 +97,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||||||
#include "asterisk/callerid.h"
|
#include "asterisk/callerid.h"
|
||||||
#include "asterisk/cel.h"
|
#include "asterisk/cel.h"
|
||||||
|
|
||||||
|
/* Define, to debug reference counts on queues, without debugging reference counts on queue members */
|
||||||
|
/* #define REF_DEBUG_ONLY_QUEUES */
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \par Please read before modifying this file.
|
* \par Please read before modifying this file.
|
||||||
* There are three locks which are regularly used
|
* There are three locks which are regularly used
|
||||||
@@ -1039,6 +1042,18 @@ static int queue_cmp_cb(void *obj, void *arg, int flags)
|
|||||||
return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
|
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)
|
static inline struct call_queue *queue_ref(struct call_queue *q)
|
||||||
{
|
{
|
||||||
ao2_ref(q, 1);
|
ao2_ref(q, 1);
|
||||||
@@ -1050,6 +1065,7 @@ static inline struct call_queue *queue_unref(struct call_queue *q)
|
|||||||
ao2_ref(q, -1);
|
ao2_ref(q, -1);
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*! \brief Set variables of queue */
|
/*! \brief Set variables of queue */
|
||||||
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
|
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
|
||||||
@@ -1201,7 +1217,7 @@ static int handle_statechange(void *datap)
|
|||||||
int found = 0;
|
int found = 0;
|
||||||
|
|
||||||
qiter = ao2_iterator_init(queues, 0);
|
qiter = ao2_iterator_init(queues, 0);
|
||||||
while ((q = ao2_iterator_next(&qiter))) {
|
while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
|
||||||
ao2_lock(q);
|
ao2_lock(q);
|
||||||
|
|
||||||
miter = ao2_iterator_init(q->members, 0);
|
miter = ao2_iterator_init(q->members, 0);
|
||||||
@@ -1222,7 +1238,7 @@ static int handle_statechange(void *datap)
|
|||||||
ao2_iterator_destroy(&miter);
|
ao2_iterator_destroy(&miter);
|
||||||
|
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
ao2_ref(q, -1);
|
queue_t_unref(q, "Done with iterator");
|
||||||
}
|
}
|
||||||
ao2_iterator_destroy(&qiter);
|
ao2_iterator_destroy(&qiter);
|
||||||
|
|
||||||
@@ -1301,7 +1317,7 @@ static int extension_state_cb(char *context, char *exten, enum ast_extension_sta
|
|||||||
int found = 0, device_state = extensionstate2devicestate(state);
|
int found = 0, device_state = extensionstate2devicestate(state);
|
||||||
|
|
||||||
qiter = ao2_iterator_init(queues, 0);
|
qiter = ao2_iterator_init(queues, 0);
|
||||||
while ((q = ao2_iterator_next(&qiter))) {
|
while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
|
||||||
ao2_lock(q);
|
ao2_lock(q);
|
||||||
|
|
||||||
miter = ao2_iterator_init(q->members, 0);
|
miter = ao2_iterator_init(q->members, 0);
|
||||||
@@ -1316,7 +1332,7 @@ static int extension_state_cb(char *context, char *exten, enum ast_extension_sta
|
|||||||
ao2_iterator_destroy(&miter);
|
ao2_iterator_destroy(&miter);
|
||||||
|
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
ao2_ref(q, -1);
|
queue_t_unref(q, "Done with iterator");
|
||||||
}
|
}
|
||||||
ao2_iterator_destroy(&qiter);
|
ao2_iterator_destroy(&qiter);
|
||||||
|
|
||||||
@@ -1900,9 +1916,9 @@ static struct call_queue *alloc_queue(const char *queuename)
|
|||||||
{
|
{
|
||||||
struct call_queue *q;
|
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)) {
|
if (ast_string_field_init(q, 64)) {
|
||||||
ao2_ref(q, -1);
|
queue_t_unref(q, "String field allocation failed");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ast_string_field_set(q, name, queuename);
|
ast_string_field_set(q, name, queuename);
|
||||||
@@ -1934,12 +1950,12 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as
|
|||||||
char tmpbuf[64]; /* Must be longer than the longest queue param name. */
|
char tmpbuf[64]; /* Must be longer than the longest queue param name. */
|
||||||
|
|
||||||
/* Static queues override realtime. */
|
/* 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);
|
ao2_lock(q);
|
||||||
if (!q->realtime) {
|
if (!q->realtime) {
|
||||||
if (q->dead) {
|
if (q->dead) {
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Queue is dead; can't return it");
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
|
ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
|
||||||
@@ -1947,7 +1963,6 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as
|
|||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
queue_unref(q);
|
|
||||||
} else if (!member_config)
|
} else if (!member_config)
|
||||||
/* Not found in the list, and it's not realtime ... */
|
/* Not found in the list, and it's not realtime ... */
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1963,9 +1978,9 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as
|
|||||||
|
|
||||||
q->dead = 1;
|
q->dead = 1;
|
||||||
/* Delete if unused (else will be deleted when last caller leaves). */
|
/* 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);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Queue is dead; can't return it");
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1996,7 +2011,7 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as
|
|||||||
/* We traversed all variables and didn't find a strategy */
|
/* We traversed all variables and didn't find a strategy */
|
||||||
if (!tmpvar)
|
if (!tmpvar)
|
||||||
q->strategy = QUEUE_STRATEGY_RINGALL;
|
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. */
|
init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
|
||||||
|
|
||||||
@@ -2065,7 +2080,7 @@ static struct call_queue *load_realtime_queue(const char *queuename)
|
|||||||
int prev_weight = 0;
|
int prev_weight = 0;
|
||||||
|
|
||||||
/* Find the queue in the in-core list first. */
|
/* 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) {
|
if (!q || q->realtime) {
|
||||||
/*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
|
/*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
|
||||||
@@ -2488,7 +2503,7 @@ static void leave_queue(struct queue_ent *qe)
|
|||||||
|
|
||||||
if (!(q = qe->parent))
|
if (!(q = qe->parent))
|
||||||
return;
|
return;
|
||||||
queue_ref(q);
|
queue_t_ref(q, "Copy queue pointer from queue entry");
|
||||||
ao2_lock(q);
|
ao2_lock(q);
|
||||||
|
|
||||||
prev = NULL;
|
prev = NULL;
|
||||||
@@ -2532,10 +2547,10 @@ static void leave_queue(struct queue_ent *qe)
|
|||||||
|
|
||||||
if (q->dead) {
|
if (q->dead) {
|
||||||
/* It's dead and nobody is in it, so kill it */
|
/* 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 */
|
/* 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 */
|
/*! \brief Hang up a list of outgoing calls */
|
||||||
@@ -2620,9 +2635,9 @@ static int compare_weight(struct call_queue *rq, struct member *member)
|
|||||||
/* q's lock and rq's lock already set by try_calling()
|
/* q's lock and rq's lock already set by try_calling()
|
||||||
* to solve deadlock */
|
* to solve deadlock */
|
||||||
queue_iter = ao2_iterator_init(queues, 0);
|
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 */
|
if (q == rq) { /* don't check myself, could deadlock */
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with iterator");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ao2_lock(q);
|
ao2_lock(q);
|
||||||
@@ -2637,7 +2652,7 @@ static int compare_weight(struct call_queue *rq, struct member *member)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with iterator");
|
||||||
if (found) {
|
if (found) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3631,7 +3646,7 @@ static int update_queue(struct call_queue *q, struct member *member, int callcom
|
|||||||
|
|
||||||
if (shared_lastcall) {
|
if (shared_lastcall) {
|
||||||
queue_iter = ao2_iterator_init(queues, 0);
|
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);
|
ao2_lock(qtmp);
|
||||||
if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
|
if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
|
||||||
time(&mem->lastcall);
|
time(&mem->lastcall);
|
||||||
@@ -3640,7 +3655,7 @@ static int update_queue(struct call_queue *q, struct member *member, int callcom
|
|||||||
ao2_ref(mem, -1);
|
ao2_ref(mem, -1);
|
||||||
}
|
}
|
||||||
ao2_unlock(qtmp);
|
ao2_unlock(qtmp);
|
||||||
ao2_ref(qtmp, -1);
|
queue_t_unref(qtmp, "Done with iterator");
|
||||||
}
|
}
|
||||||
ao2_iterator_destroy(&queue_iter);
|
ao2_iterator_destroy(&queue_iter);
|
||||||
} else {
|
} else {
|
||||||
@@ -3888,7 +3903,7 @@ static void end_bridge_callback(void *data)
|
|||||||
set_queue_variables(q, chan);
|
set_queue_variables(q, chan);
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
/* This unrefs the reference we made in try_calling when we allocated qeb */
|
/* This unrefs the reference we made in try_calling when we allocated qeb */
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Expire bridge_config reference");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4634,7 +4649,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
|||||||
* to make sure to increase the refcount of this queue so it cannot be freed until we
|
* 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.
|
* 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);
|
time(&callstart);
|
||||||
@@ -4777,7 +4792,7 @@ static int remove_from_queue(const char *queuename, const char *interface)
|
|||||||
int res = RES_NOSUCHQUEUE;
|
int res = RES_NOSUCHQUEUE;
|
||||||
|
|
||||||
ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
|
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(queues);
|
||||||
ao2_lock(q);
|
ao2_lock(q);
|
||||||
if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
|
if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
|
||||||
@@ -4785,7 +4800,7 @@ static int remove_from_queue(const char *queuename, const char *interface)
|
|||||||
if (!mem->dynamic) {
|
if (!mem->dynamic) {
|
||||||
ao2_ref(mem, -1);
|
ao2_ref(mem, -1);
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
|
||||||
ao2_unlock(queues);
|
ao2_unlock(queues);
|
||||||
return RES_NOT_DYNAMIC;
|
return RES_NOT_DYNAMIC;
|
||||||
}
|
}
|
||||||
@@ -4807,7 +4822,7 @@ static int remove_from_queue(const char *queuename, const char *interface)
|
|||||||
}
|
}
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
ao2_unlock(queues);
|
ao2_unlock(queues);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Expiring temporary reference");
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -4888,7 +4903,7 @@ static int set_member_paused(const char *queuename, const char *interface, const
|
|||||||
ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
|
ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
|
||||||
|
|
||||||
queue_iter = ao2_iterator_init(queues, 0);
|
queue_iter = ao2_iterator_init(queues, 0);
|
||||||
while ((q = ao2_iterator_next(&queue_iter))) {
|
while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
|
||||||
ao2_lock(q);
|
ao2_lock(q);
|
||||||
if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
|
if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
|
||||||
if ((mem = interface_exists(q, interface))) {
|
if ((mem = interface_exists(q, interface))) {
|
||||||
@@ -4905,6 +4920,7 @@ static int set_member_paused(const char *queuename, const char *interface, const
|
|||||||
ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface);
|
ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface);
|
||||||
ao2_ref(mem, -1);
|
ao2_ref(mem, -1);
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
|
queue_t_unref(q, "Done with iterator");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
found++;
|
found++;
|
||||||
@@ -4937,12 +4953,12 @@ static int set_member_paused(const char *queuename, const char *interface, const
|
|||||||
|
|
||||||
if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) {
|
if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) {
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with iterator");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with iterator");
|
||||||
}
|
}
|
||||||
ao2_iterator_destroy(&queue_iter);
|
ao2_iterator_destroy(&queue_iter);
|
||||||
|
|
||||||
@@ -4963,7 +4979,7 @@ static int set_member_penalty(const char *queuename, const char *interface, int
|
|||||||
}
|
}
|
||||||
|
|
||||||
queue_iter = ao2_iterator_init(queues, 0);
|
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);
|
ao2_lock(q);
|
||||||
if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
|
if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
|
||||||
foundqueue++;
|
foundqueue++;
|
||||||
@@ -4981,7 +4997,7 @@ static int set_member_penalty(const char *queuename, const char *interface, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with iterator");
|
||||||
}
|
}
|
||||||
ao2_iterator_destroy(&queue_iter);
|
ao2_iterator_destroy(&queue_iter);
|
||||||
|
|
||||||
@@ -5007,18 +5023,18 @@ static int get_member_penalty(char *queuename, char *interface)
|
|||||||
};
|
};
|
||||||
struct member *mem;
|
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;
|
foundqueue = 1;
|
||||||
ao2_lock(q);
|
ao2_lock(q);
|
||||||
if ((mem = interface_exists(q, interface))) {
|
if ((mem = interface_exists(q, interface))) {
|
||||||
penalty = mem->penalty;
|
penalty = mem->penalty;
|
||||||
ao2_ref(mem, -1);
|
ao2_ref(mem, -1);
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Search complete");
|
||||||
return penalty;
|
return penalty;
|
||||||
}
|
}
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Search complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* some useful debuging */
|
/* some useful debuging */
|
||||||
@@ -5060,7 +5076,7 @@ static void reload_queue_members(void)
|
|||||||
struct call_queue tmpq = {
|
struct call_queue tmpq = {
|
||||||
.name = queue_name,
|
.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)
|
if (!cur_queue)
|
||||||
@@ -5075,7 +5091,7 @@ static void reload_queue_members(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5117,7 +5133,7 @@ static void reload_queue_members(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
queue_unref(cur_queue);
|
queue_t_unref(cur_queue, "Expire reload reference");
|
||||||
}
|
}
|
||||||
|
|
||||||
ao2_unlock(queues);
|
ao2_unlock(queues);
|
||||||
@@ -5700,7 +5716,7 @@ static int queue_function_var(struct ast_channel *chan, const char *cmd, char *d
|
|||||||
return -1;
|
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);
|
ao2_lock(q);
|
||||||
if (q->setqueuevar) {
|
if (q->setqueuevar) {
|
||||||
sl = 0;
|
sl = 0;
|
||||||
@@ -5718,7 +5734,7 @@ static int queue_function_var(struct ast_channel *chan, const char *cmd, char *d
|
|||||||
}
|
}
|
||||||
|
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with QUEUE() function");
|
||||||
} else {
|
} else {
|
||||||
ast_log(LOG_WARNING, "queue %s was not found\n", data);
|
ast_log(LOG_WARNING, "queue %s was not found\n", data);
|
||||||
}
|
}
|
||||||
@@ -5775,7 +5791,7 @@ static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *d
|
|||||||
} else /* must be "count" */
|
} else /* must be "count" */
|
||||||
count = q->membercount;
|
count = q->membercount;
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
|
||||||
} else
|
} else
|
||||||
ast_log(LOG_WARNING, "queue %s was not found\n", data);
|
ast_log(LOG_WARNING, "queue %s was not found\n", data);
|
||||||
|
|
||||||
@@ -5819,7 +5835,7 @@ static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, cha
|
|||||||
}
|
}
|
||||||
ao2_iterator_destroy(&mem_iter);
|
ao2_iterator_destroy(&mem_iter);
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT");
|
||||||
} else
|
} else
|
||||||
ast_log(LOG_WARNING, "queue %s was not found\n", data);
|
ast_log(LOG_WARNING, "queue %s was not found\n", data);
|
||||||
|
|
||||||
@@ -5844,11 +5860,11 @@ static int queue_function_queuewaitingcount(struct ast_channel *chan, const char
|
|||||||
return -1;
|
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);
|
ao2_lock(q);
|
||||||
count = q->count;
|
count = q->count;
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
|
||||||
} else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
|
} else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
|
||||||
/* if the queue is realtime but was not found in memory, this
|
/* if the queue is realtime but was not found in memory, this
|
||||||
* means that the queue had been deleted from memory since it was
|
* means that the queue had been deleted from memory since it was
|
||||||
@@ -5880,7 +5896,7 @@ static int queue_function_queuememberlist(struct ast_channel *chan, const char *
|
|||||||
return -1;
|
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;
|
int buflen = 0, count = 0;
|
||||||
struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
|
struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
|
||||||
|
|
||||||
@@ -5903,7 +5919,7 @@ static int queue_function_queuememberlist(struct ast_channel *chan, const char *
|
|||||||
}
|
}
|
||||||
ao2_iterator_destroy(&mem_iter);
|
ao2_iterator_destroy(&mem_iter);
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
|
||||||
} else
|
} else
|
||||||
ast_log(LOG_WARNING, "queue %s was not found\n", data);
|
ast_log(LOG_WARNING, "queue %s was not found\n", data);
|
||||||
|
|
||||||
@@ -6215,7 +6231,7 @@ static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask,
|
|||||||
const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
|
const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
|
||||||
int prev_weight = 0;
|
int prev_weight = 0;
|
||||||
struct ast_variable *var;
|
struct ast_variable *var;
|
||||||
if (!(q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
|
if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
|
||||||
if (queue_reload) {
|
if (queue_reload) {
|
||||||
/* Make one then */
|
/* Make one then */
|
||||||
if (!(q = alloc_queue(queuename))) {
|
if (!(q = alloc_queue(queuename))) {
|
||||||
@@ -6243,7 +6259,7 @@ static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask,
|
|||||||
/* It should be impossible to *not* hit this case*/
|
/* It should be impossible to *not* hit this case*/
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
}
|
}
|
||||||
queue_unref(q);
|
queue_t_unref(q, "We exist! Expiring temporary pointer");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Due to the fact that the "linear" strategy will have a different allocation
|
/* Due to the fact that the "linear" strategy will have a different allocation
|
||||||
@@ -6291,11 +6307,11 @@ static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (new) {
|
if (new) {
|
||||||
ao2_link(queues, q);
|
queues_t_link(queues, q, "Add queue to container");
|
||||||
} else {
|
} else {
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
}
|
}
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Expiring creation reference");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mark_dead_and_unfound(void *obj, void *arg, int flags)
|
static int mark_dead_and_unfound(void *obj, void *arg, int flags)
|
||||||
@@ -6396,11 +6412,12 @@ static int clear_stats(const char *queuename)
|
|||||||
{
|
{
|
||||||
struct call_queue *q;
|
struct call_queue *q;
|
||||||
struct ao2_iterator queue_iter = ao2_iterator_init(queues, 0);
|
struct ao2_iterator 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);
|
ao2_lock(q);
|
||||||
if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
|
if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
|
||||||
clear_queue(q);
|
clear_queue(q);
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
|
queue_t_unref(q, "Done with iterator");
|
||||||
}
|
}
|
||||||
ao2_iterator_destroy(&queue_iter);
|
ao2_iterator_destroy(&queue_iter);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -6464,7 +6481,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
|
|||||||
|
|
||||||
if (argc == 3) { /* specific queue */
|
if (argc == 3) { /* specific queue */
|
||||||
if ((q = load_realtime_queue(argv[2]))) {
|
if ((q = load_realtime_queue(argv[2]))) {
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with temporary pointer");
|
||||||
}
|
}
|
||||||
} else if (ast_check_realtime("queues")) {
|
} else if (ast_check_realtime("queues")) {
|
||||||
/* This block is to find any queues which are defined in realtime but
|
/* This block is to find any queues which are defined in realtime but
|
||||||
@@ -6475,7 +6492,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
|
|||||||
if (cfg) {
|
if (cfg) {
|
||||||
for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
|
for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
|
||||||
if ((q = load_realtime_queue(queuename))) {
|
if ((q = load_realtime_queue(queuename))) {
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with temporary pointer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast_config_destroy(cfg);
|
ast_config_destroy(cfg);
|
||||||
@@ -6484,7 +6501,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
|
|||||||
|
|
||||||
queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK);
|
queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK);
|
||||||
ao2_lock(queues);
|
ao2_lock(queues);
|
||||||
while ((q = ao2_iterator_next(&queue_iter))) {
|
while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
|
||||||
float sl;
|
float sl;
|
||||||
struct call_queue *realtime_queue = NULL;
|
struct call_queue *realtime_queue = NULL;
|
||||||
|
|
||||||
@@ -6495,14 +6512,14 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
|
|||||||
*/
|
*/
|
||||||
if (q->realtime && !(realtime_queue = load_realtime_queue(q->name))) {
|
if (q->realtime && !(realtime_queue = load_realtime_queue(q->name))) {
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with iterator");
|
||||||
continue;
|
continue;
|
||||||
} else if (q->realtime) {
|
} else if (q->realtime) {
|
||||||
queue_unref(realtime_queue);
|
queue_t_unref(realtime_queue, "Queue is already in memory");
|
||||||
}
|
}
|
||||||
if (argc == 3 && strcasecmp(q->name, argv[2])) {
|
if (argc == 3 && strcasecmp(q->name, argv[2])) {
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with iterator");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
found = 1;
|
found = 1;
|
||||||
@@ -6564,7 +6581,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
|
|||||||
}
|
}
|
||||||
do_print(s, fd, ""); /* blank line between entries */
|
do_print(s, fd, ""); /* blank line between entries */
|
||||||
ao2_unlock(q);
|
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_iterator_destroy(&queue_iter);
|
||||||
ao2_unlock(queues);
|
ao2_unlock(queues);
|
||||||
@@ -6587,13 +6604,13 @@ static char *complete_queue(const char *line, const char *word, int pos, int sta
|
|||||||
struct ao2_iterator queue_iter;
|
struct ao2_iterator queue_iter;
|
||||||
|
|
||||||
queue_iter = ao2_iterator_init(queues, 0);
|
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) {
|
if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
|
||||||
ret = ast_strdup(q->name);
|
ret = ast_strdup(q->name);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with iterator");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with iterator");
|
||||||
}
|
}
|
||||||
ao2_iterator_destroy(&queue_iter);
|
ao2_iterator_destroy(&queue_iter);
|
||||||
|
|
||||||
@@ -6682,7 +6699,7 @@ static int manager_queues_summary(struct mansession *s, const struct message *m)
|
|||||||
if (!ast_strlen_zero(id))
|
if (!ast_strlen_zero(id))
|
||||||
snprintf(idText, 256, "ActionID: %s\r\n", id);
|
snprintf(idText, 256, "ActionID: %s\r\n", id);
|
||||||
queue_iter = ao2_iterator_init(queues, 0);
|
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);
|
ao2_lock(q);
|
||||||
|
|
||||||
/* List queue properties */
|
/* List queue properties */
|
||||||
@@ -6724,7 +6741,7 @@ static int manager_queues_summary(struct mansession *s, const struct message *m)
|
|||||||
q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
|
q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
|
||||||
}
|
}
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with iterator");
|
||||||
}
|
}
|
||||||
ao2_iterator_destroy(&queue_iter);
|
ao2_iterator_destroy(&queue_iter);
|
||||||
astman_append(s,
|
astman_append(s,
|
||||||
@@ -6757,7 +6774,7 @@ static int manager_queues_status(struct mansession *s, const struct message *m)
|
|||||||
snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
|
snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
|
||||||
|
|
||||||
queue_iter = ao2_iterator_init(queues, 0);
|
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);
|
ao2_lock(q);
|
||||||
|
|
||||||
/* List queue properties */
|
/* List queue properties */
|
||||||
@@ -6821,7 +6838,7 @@ static int manager_queues_status(struct mansession *s, const struct message *m)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with iterator");
|
||||||
}
|
}
|
||||||
ao2_iterator_destroy(&queue_iter);
|
ao2_iterator_destroy(&queue_iter);
|
||||||
|
|
||||||
@@ -7160,7 +7177,7 @@ static char *complete_queue_remove_member(const char *line, const char *word, in
|
|||||||
|
|
||||||
/* here is the case for 3, <member> */
|
/* here is the case for 3, <member> */
|
||||||
queue_iter = ao2_iterator_init(queues, 0);
|
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);
|
ao2_lock(q);
|
||||||
mem_iter = ao2_iterator_init(q->members, 0);
|
mem_iter = ao2_iterator_init(q->members, 0);
|
||||||
while ((m = ao2_iterator_next(&mem_iter))) {
|
while ((m = ao2_iterator_next(&mem_iter))) {
|
||||||
@@ -7169,7 +7186,7 @@ static char *complete_queue_remove_member(const char *line, const char *word, in
|
|||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
tmp = ast_strdup(m->interface);
|
tmp = ast_strdup(m->interface);
|
||||||
ao2_ref(m, -1);
|
ao2_ref(m, -1);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with iterator, returning interface name");
|
||||||
ao2_iterator_destroy(&mem_iter);
|
ao2_iterator_destroy(&mem_iter);
|
||||||
ao2_iterator_destroy(&queue_iter);
|
ao2_iterator_destroy(&queue_iter);
|
||||||
return tmp;
|
return tmp;
|
||||||
@@ -7178,7 +7195,7 @@ static char *complete_queue_remove_member(const char *line, const char *word, in
|
|||||||
}
|
}
|
||||||
ao2_iterator_destroy(&mem_iter);
|
ao2_iterator_destroy(&mem_iter);
|
||||||
ao2_unlock(q);
|
ao2_unlock(q);
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with iterator");
|
||||||
}
|
}
|
||||||
ao2_iterator_destroy(&queue_iter);
|
ao2_iterator_destroy(&queue_iter);
|
||||||
|
|
||||||
@@ -7578,9 +7595,9 @@ static int unload_module(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
q_iter = ao2_iterator_init(queues, 0);
|
q_iter = ao2_iterator_init(queues, 0);
|
||||||
while ((q = ao2_iterator_next(&q_iter))) {
|
while ((q = ao2_t_iterator_next(&q_iter, "Iterate through queues"))) {
|
||||||
ao2_unlink(queues, q);
|
queues_t_unlink(queues, q, "Remove queue from container due to unload");
|
||||||
queue_unref(q);
|
queue_t_unref(q, "Done with iterator");
|
||||||
}
|
}
|
||||||
ao2_iterator_destroy(&q_iter);
|
ao2_iterator_destroy(&q_iter);
|
||||||
ao2_ref(queues, -1);
|
ao2_ref(queues, -1);
|
||||||
|
|||||||
Reference in New Issue
Block a user