diff options
author | dvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-11-30 16:32:58 +0000 |
---|---|---|
committer | dvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-11-30 16:32:58 +0000 |
commit | 79e8d51f2d57d3d525c6670ead57ae22a42f2c1e (patch) | |
tree | db8e9b01140b55bfc2454cae40162d065df0f0ad /apps/app_queue.c | |
parent | 52fb239a9a86356e307bca9c7f025175aa6bbc11 (diff) |
app_queue crashes randomly, often during call-transfers
In app_queue, it is possible for a call_queue to be destroyed
while another object still holds a pointer to it. This patch
converts call_queue objects to ao2 objects allowing them to be
ref counted. This makes it safe for the queue_ent object in
queue_exec() to reference it's parent call_queue even after it
has left the queue.
(closes issue #15686)
Reported by: Hatrix
Patches:
v2_queue_ao2.diff uploaded by dvossel (license 671)
Tested by: dvossel, aragon
Review: https://reviewboard.asterisk.org/r/427/
git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@231437 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'apps/app_queue.c')
-rw-r--r-- | apps/app_queue.c | 214 |
1 files changed, 114 insertions, 100 deletions
diff --git a/apps/app_queue.c b/apps/app_queue.c index 47f59d532..11b4a9b9b 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -385,7 +385,6 @@ static AST_LIST_HEAD_STATIC(interfaces, member_interface); #define QUEUE_EVENT_VARIABLES 3 struct call_queue { - ast_mutex_t lock; char name[80]; /*!< Name */ char moh[80]; /*!< Music On Hold class to be used */ char announce[80]; /*!< Announcement to play when call is answered */ @@ -454,8 +453,8 @@ struct call_queue { static AST_LIST_HEAD_STATIC(queues, call_queue); static int set_member_paused(const char *queuename, const char *interface, int paused); - static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan); +static void free_members(struct call_queue *q, int all); static void rr_dep_warning(void) { @@ -512,6 +511,27 @@ static int strat2int(const char *strategy) return -1; } +/*! + * \brief removes a call_queue from the list of call_queues + */ +static void remove_queue(struct call_queue *q) +{ + AST_LIST_LOCK(&queues); + if (AST_LIST_REMOVE(&queues, q, list)) { + ao2_ref(q, -1); + } + AST_LIST_UNLOCK(&queues); +} + +static void destroy_queue(void *obj) +{ + struct call_queue *q = obj; + if (q->members) { + free_members(q, 1); + ao2_ref(q->members, -1); + } +} + /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */ static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos) { @@ -527,6 +547,11 @@ static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, st q->head = new; } new->next = cur; + + /* every queue_ent must have a reference to it's parent call_queue, this + * reference does not go away until the end of the queue_ent's life, meaning + * that even when the queue_ent leaves the call_queue this ref must remain. */ + ao2_ref(q, +1); new->parent = q; new->pos = ++(*pos); new->opos = *pos; @@ -550,7 +575,7 @@ static enum queue_member_status get_member_status(struct call_queue *q, int max_ struct ao2_iterator mem_iter; enum queue_member_status result = QUEUE_NO_MEMBERS; - ast_mutex_lock(&q->lock); + ao2_lock(q); mem_iter = ao2_iterator_init(q->members, 0); while ((member = ao2_iterator_next(&mem_iter))) { if (max_penalty && (member->penalty > max_penalty)) { @@ -573,13 +598,13 @@ static enum queue_member_status get_member_status(struct call_queue *q, int max_ ao2_ref(member, -1); break; default: - ast_mutex_unlock(&q->lock); + ao2_unlock(q); ao2_ref(member, -1); return QUEUE_NORMAL; } } ao2_iterator_destroy(&mem_iter); - ast_mutex_unlock(&q->lock); + ao2_unlock(q); return result; } @@ -598,7 +623,7 @@ static int update_status(const char *interface, const int status) AST_LIST_LOCK(&queues); AST_LIST_TRAVERSE(&queues, q, list) { - ast_mutex_lock(&q->lock); + ao2_lock(q); mem_iter = ao2_iterator_init(q->members, 0); while ((cur = ao2_iterator_next(&mem_iter))) { char *slash_pos; @@ -635,7 +660,7 @@ static int update_status(const char *interface, const int status) ao2_ref(cur, -1); } ao2_iterator_destroy(&mem_iter); - ast_mutex_unlock(&q->lock); + ao2_unlock(q); } AST_LIST_UNLOCK(&queues); @@ -785,8 +810,7 @@ static struct call_queue *alloc_queue(const char *queuename) { struct call_queue *q; - if ((q = ast_calloc(1, sizeof(*q)))) { - ast_mutex_init(&q->lock); + if ((q = ao2_alloc(sizeof(*q), destroy_queue))) { ast_copy_string(q->name, queuename, sizeof(q->name)); } return q; @@ -915,7 +939,7 @@ static int interface_exists_global(const char *interface) AST_LIST_LOCK(&queues); AST_LIST_TRAVERSE(&queues, q, list) { - ast_mutex_lock(&q->lock); + ao2_lock(q); mem_iter = ao2_iterator_init(q->members, 0); while ((mem = ao2_iterator_next(&mem_iter))) { if (!strcasecmp(mem->state_interface, interface)) { @@ -926,7 +950,7 @@ static int interface_exists_global(const char *interface) ao2_ref(mem, -1); } ao2_iterator_destroy(&mem_iter); - ast_mutex_unlock(&q->lock); + ao2_unlock(q); if (ret) break; } @@ -1187,14 +1211,6 @@ static void free_members(struct call_queue *q, int all) ao2_iterator_destroy(&mem_iter); } -static void destroy_queue(struct call_queue *q) -{ - free_members(q, 1); - ast_mutex_destroy(&q->lock); - ao2_ref(q->members, -1); - free(q); -} - /*!\brief Reload a single queue via realtime. \return Return the queue, or NULL if it doesn't exist. \note Should be called with the global qlock locked. */ @@ -1216,14 +1232,14 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as /* Static queues override realtime. */ if (q) { - ast_mutex_lock(&q->lock); + ao2_lock(q); if (!q->realtime) { if (q->dead) { - ast_mutex_unlock(&q->lock); + ao2_unlock(q); return NULL; } else { ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name); - ast_mutex_unlock(&q->lock); + ao2_unlock(q); return q; } } @@ -1244,11 +1260,10 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as /* Delete if unused (else will be deleted when last caller leaves). */ if (!q->count) { /* Delete. */ - AST_LIST_REMOVE(&queues, q, list); - ast_mutex_unlock(&q->lock); - destroy_queue(q); + ao2_unlock(q); + remove_queue(q); } else - ast_mutex_unlock(&q->lock); + ao2_unlock(q); } return NULL; } @@ -1257,7 +1272,7 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as if (!q) { if (!(q = alloc_queue(queuename))) return NULL; - ast_mutex_lock(&q->lock); + ao2_lock(q); clear_queue(q); q->realtime = 1; AST_LIST_INSERT_HEAD(&queues, q, list); @@ -1309,16 +1324,16 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as while ((m = ao2_iterator_next(&mem_iter))) { if (m->dead) { ao2_unlink(q->members, m); - ast_mutex_unlock(&q->lock); + ao2_unlock(q); remove_from_interfaces(m->state_interface); - ast_mutex_lock(&q->lock); + ao2_lock(q); q->membercount--; } ao2_ref(m, -1); } ao2_iterator_destroy(&mem_iter); - ast_mutex_unlock(&q->lock); + ao2_unlock(q); return q; } @@ -1358,7 +1373,7 @@ static void update_realtime_members(struct call_queue *q) return; } - ast_mutex_lock(&q->lock); + ao2_lock(q); /* Temporarily set realtime members dead so we can detect deleted ones.*/ mem_iter = ao2_iterator_init(q->members, 0); @@ -1382,15 +1397,15 @@ static void update_realtime_members(struct call_queue *q) while ((m = ao2_iterator_next(&mem_iter))) { if (m->dead) { ao2_unlink(q->members, m); - ast_mutex_unlock(&q->lock); + ao2_unlock(q); remove_from_interfaces(m->state_interface); - ast_mutex_lock(&q->lock); + ao2_lock(q); q->membercount--; } ao2_ref(m, -1); } ao2_iterator_destroy(&mem_iter); - ast_mutex_unlock(&q->lock); + ao2_unlock(q); ast_config_destroy(member_config); } @@ -1457,7 +1472,7 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result * return res; AST_LIST_LOCK(&queues); - ast_mutex_lock(&q->lock); + ao2_lock(q); /* This is our one */ stat = get_member_status(q, qe->max_penalty); @@ -1503,7 +1518,7 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result * if (option_debug) ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); } - ast_mutex_unlock(&q->lock); + ao2_unlock(q); AST_LIST_UNLOCK(&queues); return res; @@ -1678,10 +1693,10 @@ static void recalc_holdtime(struct queue_ent *qe, int newholdtime) /* Thanks to SRT for this contribution */ /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */ - ast_mutex_lock(&qe->parent->lock); + ao2_lock(qe->parent); oldvalue = qe->parent->holdtime; qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2; - ast_mutex_unlock(&qe->parent->lock); + ao2_unlock(qe->parent); } @@ -1693,7 +1708,7 @@ static void leave_queue(struct queue_ent *qe) if (!(q = qe->parent)) return; - ast_mutex_lock(&q->lock); + ao2_lock(q); prev = NULL; for (cur = q->head; cur; cur = cur->next) { @@ -1717,14 +1732,11 @@ static void leave_queue(struct queue_ent *qe) prev = cur; } } - ast_mutex_unlock(&q->lock); + ao2_unlock(q); if (q->dead && !q->count) { /* It's dead and nobody is in it, so kill it */ - AST_LIST_LOCK(&queues); - AST_LIST_REMOVE(&queues, q, list); - AST_LIST_UNLOCK(&queues); - destroy_queue(q); + remove_queue(q); } } @@ -1807,7 +1819,7 @@ static int compare_weight(struct call_queue *rq, struct member *member) AST_LIST_TRAVERSE(&queues, q, list) { if (q == rq) /* don't check myself, could deadlock */ continue; - ast_mutex_lock(&q->lock); + ao2_lock(q); if (q->count && q->members) { if ((mem = ao2_find(q->members, member, OBJ_POINTER))) { ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name); @@ -1818,7 +1830,7 @@ static int compare_weight(struct call_queue *rq, struct member *member) ao2_ref(mem, -1); } } - ast_mutex_unlock(&q->lock); + ao2_unlock(q); if (found) break; } @@ -1933,9 +1945,9 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); - ast_mutex_lock(&qe->parent->lock); + ao2_lock(qe->parent); qe->parent->rrpos++; - ast_mutex_unlock(&qe->parent->lock); + ao2_unlock(&qe->parent); (*busies)++; return 0; @@ -2151,7 +2163,7 @@ static int say_periodic_announcement(struct queue_ent *qe) static void record_abandoned(struct queue_ent *qe) { - ast_mutex_lock(&qe->parent->lock); + ao2_lock(qe->parent); manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon", "Queue: %s\r\n" "Uniqueid: %s\r\n" @@ -2161,7 +2173,7 @@ static void record_abandoned(struct queue_ent *qe) qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start)); qe->parent->callsabandoned++; - ast_mutex_unlock(&qe->parent->lock); + ao2_unlock(&qe->parent); } /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */ @@ -2463,7 +2475,7 @@ static int is_our_turn(struct queue_ent *qe) int avl; int idx = 0; /* This needs a lock. How many members are available to be served? */ - ast_mutex_lock(&qe->parent->lock); + ao2_lock(qe->parent); avl = num_available_members(qe->parent); @@ -2479,7 +2491,7 @@ static int is_our_turn(struct queue_ent *qe) ch = ch->next; } - ast_mutex_unlock(&qe->parent->lock); + ao2_unlock(qe->parent); /* If the queue entry is within avl [the number of available members] calls from the top ... */ if (ch && idx < avl) { @@ -2581,13 +2593,13 @@ static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *r static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl) { - ast_mutex_lock(&q->lock); + ao2_lock(q); time(&member->lastcall); member->calls++; q->callscompleted++; if (callcompletedinsl) q->callscompletedinsl++; - ast_mutex_unlock(&q->lock); + ao2_unlock(q); return 0; } @@ -2865,7 +2877,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce /* Hold the lock while we setup the outgoing calls */ if (use_weight) AST_LIST_LOCK(&queues); - ast_mutex_lock(&qe->parent->lock); + ao2_lock(qe->parent); if (option_debug) ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", qe->chan->name); @@ -2883,7 +2895,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce if (!tmp) { ao2_iterator_destroy(&memi); ao2_ref(cur, -1); - ast_mutex_unlock(&qe->parent->lock); + ao2_unlock(qe->parent); if (use_weight) AST_LIST_UNLOCK(&queues); goto out; @@ -2892,7 +2904,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce if (!(datastore = ast_channel_datastore_alloc(&dialed_interface_info, NULL))) { ao2_iterator_destroy(&memi); ao2_ref(cur, -1); - ast_mutex_unlock(&qe->parent->lock); + ao2_unlock(qe->parent); if (use_weight) AST_LIST_UNLOCK(&queues); free(tmp); @@ -2902,7 +2914,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) { ao2_iterator_destroy(&memi); ao2_ref(cur, -1); - ast_mutex_unlock(&qe->parent->lock); + ao2_unlock(qe->parent); if (use_weight) AST_LIST_UNLOCK(&queues); free(tmp); @@ -2940,7 +2952,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) { ao2_iterator_destroy(&memi); ao2_ref(cur, -1); - ast_mutex_unlock(&qe->parent->lock); + ao2_unlock(qe->parent); if (use_weight) AST_LIST_UNLOCK(&queues); free(tmp); @@ -2980,7 +2992,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce else to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1; ++qe->pending; - ast_mutex_unlock(&qe->parent->lock); + ao2_unlock(qe->parent); ring_one(qe, outgoing, &numbusies); if (use_weight) AST_LIST_UNLOCK(&queues); @@ -2996,11 +3008,11 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce ast_channel_datastore_free(datastore); } ast_channel_unlock(qe->chan); - ast_mutex_lock(&qe->parent->lock); + ao2_lock(qe->parent); if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) { store_next(qe, outgoing); } - ast_mutex_unlock(&qe->parent->lock); + ao2_unlock(qe->parent); peer = lpeer ? lpeer->chan : NULL; if (!peer) { qe->pending = 0; @@ -3038,9 +3050,9 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce /* Update parameters for the queue */ time(&now); recalc_holdtime(qe, (now - qe->start)); - ast_mutex_lock(&qe->parent->lock); + ao2_lock(qe->parent); callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel); - ast_mutex_unlock(&qe->parent->lock); + ao2_unlock(qe->parent); member = lpeer->member; /* Increment the refcount for this member, since we're going to be using it for awhile in here. */ ao2_ref(member, 1); @@ -3411,9 +3423,9 @@ static int remove_from_queue(const char *queuename, const char *interface) AST_LIST_LOCK(&queues); AST_LIST_TRAVERSE(&queues, q, list) { - ast_mutex_lock(&q->lock); + ao2_lock(q); if (strcmp(q->name, queuename)) { - ast_mutex_unlock(&q->lock); + ao2_unlock(q); continue; } @@ -3422,7 +3434,7 @@ static int remove_from_queue(const char *queuename, const char *interface) if (!mem->dynamic) { res = RES_NOT_DYNAMIC; ao2_ref(mem, -1); - ast_mutex_unlock(&q->lock); + ao2_unlock(q); break; } q->membercount--; @@ -3442,7 +3454,7 @@ static int remove_from_queue(const char *queuename, const char *interface) } else { res = RES_EXISTS; } - ast_mutex_unlock(&q->lock); + ao2_unlock(q); break; } @@ -3465,7 +3477,7 @@ static int add_to_queue(const char *queuename, const char *interface, const char AST_LIST_LOCK(&queues); - ast_mutex_lock(&q->lock); + ao2_lock(q); if ((old_member = interface_exists(q, interface)) == NULL) { if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) { add_to_interfaces(new_member->state_interface); @@ -3501,7 +3513,7 @@ static int add_to_queue(const char *queuename, const char *interface, const char ao2_ref(old_member, -1); res = RES_EXISTS; } - ast_mutex_unlock(&q->lock); + ao2_unlock(q); AST_LIST_UNLOCK(&queues); return res; @@ -3520,7 +3532,7 @@ static int set_member_paused(const char *queuename, const char *interface, int p AST_LIST_LOCK(&queues); AST_LIST_TRAVERSE(&queues, q, list) { - ast_mutex_lock(&q->lock); + ao2_lock(q); if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { if ((mem = interface_exists(q, interface))) { found++; @@ -3545,7 +3557,7 @@ static int set_member_paused(const char *queuename, const char *interface, int p ao2_ref(mem, -1); } } - ast_mutex_unlock(&q->lock); + ao2_unlock(q); } AST_LIST_UNLOCK(&queues); @@ -3579,10 +3591,10 @@ static void reload_queue_members(void) queue_name = entry->key + strlen(pm_family) + 2; AST_LIST_TRAVERSE(&queues, cur_queue, list) { - ast_mutex_lock(&cur_queue->lock); + ao2_lock(cur_queue); if (!strcmp(queue_name, cur_queue->name)) break; - ast_mutex_unlock(&cur_queue->lock); + ao2_unlock(cur_queue); } if (!cur_queue) @@ -3595,7 +3607,7 @@ static void reload_queue_members(void) ast_db_del(pm_family, queue_name); continue; } else - ast_mutex_unlock(&cur_queue->lock); + ao2_unlock(cur_queue); if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) continue; @@ -3972,7 +3984,7 @@ static int queue_exec(struct ast_channel *chan, void *data) AST_APP_ARG(agi); ); /* Our queue entry */ - struct queue_ent qe; + struct queue_ent qe = { 0 }; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n"); @@ -3985,7 +3997,6 @@ static int queue_exec(struct ast_channel *chan, void *data) lu = ast_module_user_add(chan); /* Setup our queue entry */ - memset(&qe, 0, sizeof(qe)); qe.start = time(NULL); /* set the expire time based on the supplied timeout; */ @@ -4213,6 +4224,12 @@ stop: set_queue_result(chan, reason); res = 0; } + if (qe.parent) { + /* every queue_ent is given a reference to it's parent call_queue when it joins the queue. + * This ref must be taken away right before the queue_ent is destroyed. In this case + * the queue_ent is about to be returned on the stack */ + ao2_ref(qe.parent, -1); + } ast_module_user_remove(lu); return res; @@ -4236,7 +4253,7 @@ static int queue_function_qac(struct ast_channel *chan, char *cmd, char *data, c lu = ast_module_user_add(chan); if ((q = load_realtime_queue(data))) { - ast_mutex_lock(&q->lock); + ao2_lock(q); mem_iter = ao2_iterator_init(q->members, 0); while ((m = ao2_iterator_next(&mem_iter))) { /* Count the agents who are logged in and presently answering calls */ @@ -4246,7 +4263,7 @@ static int queue_function_qac(struct ast_channel *chan, char *cmd, char *data, c ao2_ref(m, -1); } ao2_iterator_destroy(&mem_iter); - ast_mutex_unlock(&q->lock); + ao2_unlock(q); } else ast_log(LOG_WARNING, "queue %s was not found\n", data); @@ -4275,7 +4292,7 @@ static int queue_function_queuewaitingcount(struct ast_channel *chan, char *cmd, AST_LIST_LOCK(&queues); AST_LIST_TRAVERSE(&queues, q, list) { if (!strcasecmp(q->name, data)) { - ast_mutex_lock(&q->lock); + ao2_lock(q); break; } } @@ -4283,7 +4300,7 @@ static int queue_function_queuewaitingcount(struct ast_channel *chan, char *cmd, if (q) { count = q->count; - ast_mutex_unlock(&q->lock); + ao2_unlock(q); } else if ((var = ast_load_realtime("queues", "name", data, NULL))) { /* if the queue is realtime but was not found in memory, this * means that the queue had been deleted from memory since it was @@ -4318,7 +4335,7 @@ static int queue_function_queuememberlist(struct ast_channel *chan, char *cmd, c AST_LIST_LOCK(&queues); AST_LIST_TRAVERSE(&queues, q, list) { if (!strcasecmp(q->name, data)) { - ast_mutex_lock(&q->lock); + ao2_lock(q); break; } } @@ -4345,7 +4362,7 @@ static int queue_function_queuememberlist(struct ast_channel *chan, char *cmd, c ao2_ref(m, -1); } ao2_iterator_destroy(&mem_iter); - ast_mutex_unlock(&q->lock); + ao2_unlock(q); } else ast_log(LOG_WARNING, "queue %s was not found\n", data); @@ -4459,12 +4476,12 @@ static int reload_queues(void) new = 0; if (q) { if (!new) - ast_mutex_lock(&q->lock); + ao2_lock(q); /* Check if a queue with this name already exists */ if (q->found) { ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat); if (!new) - ast_mutex_unlock(&q->lock); + ao2_unlock(q); continue; } /* Re-initialize the queue, and clear statistics */ @@ -4564,7 +4581,7 @@ static int reload_queues(void) if (new) { AST_LIST_INSERT_HEAD(&queues, q, list); } else - ast_mutex_unlock(&q->lock); + ao2_unlock(q); } } } @@ -4572,12 +4589,9 @@ static int reload_queues(void) AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) { if (q->dead) { AST_LIST_REMOVE_CURRENT(&queues, list); - if (!q->count) - destroy_queue(q); - else - ast_log(LOG_DEBUG, "XXX Leaking a little memory :( XXX\n"); + ao2_ref(q, -1); } else { - ast_mutex_lock(&q->lock); + ao2_lock(q); mem_iter = ao2_iterator_init(q->members, 0); while ((cur = ao2_iterator_next(&mem_iter))) { if (cur->dynamic) @@ -4586,7 +4600,7 @@ static int reload_queues(void) ao2_ref(cur, -1); } ao2_iterator_destroy(&mem_iter); - ast_mutex_unlock(&q->lock); + ao2_unlock(q); } } AST_LIST_TRAVERSE_SAFE_END; @@ -4647,10 +4661,10 @@ static int __queues_show(struct mansession *s, int manager, int fd, int argc, ch return RESULT_SUCCESS; } AST_LIST_TRAVERSE(&queues, q, list) { - ast_mutex_lock(&q->lock); + ao2_lock(q); if (queue_show) { if (strcasecmp(q->name, argv[2]) != 0) { - ast_mutex_unlock(&q->lock); + ao2_unlock(q); if (!AST_LIST_NEXT(q, list)) { ast_cli(fd, "No such queue: %s.%s",argv[2], term); break; @@ -4737,7 +4751,7 @@ static int __queues_show(struct mansession *s, int manager, int fd, int argc, ch astman_append(s, "%s", term); else ast_cli(fd, "%s", term); - ast_mutex_unlock(&q->lock); + ao2_unlock(q); if (queue_show) break; } @@ -4811,7 +4825,7 @@ static int manager_queues_status(struct mansession *s, const struct message *m) snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); AST_LIST_TRAVERSE(&queues, q, list) { - ast_mutex_lock(&q->lock); + ao2_lock(q); /* List queue properties */ if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { @@ -4870,7 +4884,7 @@ static int manager_queues_status(struct mansession *s, const struct message *m) (long) (now - qe->start), idText); } } - ast_mutex_unlock(&q->lock); + ao2_unlock(q); } astman_append(s, @@ -5139,13 +5153,13 @@ static char *complete_queue_remove_member(const char *line, const char *word, in /* here is the case for 3, <member> */ if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */ AST_LIST_TRAVERSE(&queues, q, list) { - ast_mutex_lock(&q->lock); + ao2_lock(q); mem_iter = ao2_iterator_init(q->members, 0); while ((m = ao2_iterator_next(&mem_iter))) { if (++which > state) { char *tmp; ao2_iterator_destroy(&mem_iter); - ast_mutex_unlock(&q->lock); + ao2_unlock(q); tmp = ast_strdup(m->interface); ao2_ref(m, -1); return tmp; @@ -5153,7 +5167,7 @@ static char *complete_queue_remove_member(const char *line, const char *word, in ao2_ref(m, -1); } ao2_iterator_destroy(&mem_iter); - ast_mutex_unlock(&q->lock); + ao2_unlock(q); } } |