aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/app_queue.c47
-rw-r--r--channels/chan_console.c8
-rw-r--r--channels/chan_iax2.c13
-rw-r--r--channels/chan_sip.c49
-rw-r--r--funcs/func_dialgroup.c1
-rw-r--r--include/asterisk/astobj2.h68
-rw-r--r--main/astobj2.c17
-rw-r--r--res/res_clialiases.c2
-rw-r--r--res/res_musiconhold.c4
-rw-r--r--res/res_odbc.c7
-rw-r--r--res/res_phoneprov.c6
11 files changed, 179 insertions, 43 deletions
diff --git a/apps/app_queue.c b/apps/app_queue.c
index ad23ae75b..03490ead9 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -973,12 +973,14 @@ static int get_member_status(struct call_queue *q, int max_penalty, int min_pena
} else {
ao2_unlock(q);
ao2_ref(member, -1);
+ ao2_iterator_destroy(&mem_iter);
ast_debug(4, "%s is available.\n", member->membername);
return 0;
}
break;
}
}
+ ao2_iterator_destroy(&mem_iter);
ao2_unlock(q);
return -1;
@@ -1030,7 +1032,6 @@ static int handle_statechange(void *datap)
int found = 0;
qiter = ao2_iterator_init(queues, 0);
-
while ((q = ao2_iterator_next(&qiter))) {
ao2_lock(q);
@@ -1049,10 +1050,12 @@ static int handle_statechange(void *datap)
break;
}
}
+ ao2_iterator_destroy(&miter);
ao2_unlock(q);
ao2_ref(q, -1);
}
+ ao2_iterator_destroy(&qiter);
if (found)
ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state));
@@ -1232,6 +1235,7 @@ static void clear_queue(struct call_queue *q)
mem->calls = 0;
ao2_ref(mem, -1);
}
+ ao2_iterator_destroy(&mem_iter);
}
}
@@ -1590,6 +1594,7 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, const
}
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
/* Create a new member */
if (!found) {
@@ -1620,6 +1625,7 @@ static void free_members(struct call_queue *q, int all)
}
ao2_ref(cur, -1);
}
+ ao2_iterator_destroy(&mem_iter);
}
/*! \brief Free queue's member list then its string fields */
@@ -1768,6 +1774,7 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as
m->dead = 1;
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
while ((interface = ast_category_browse(member_config, interface))) {
rt_handle_member_record(q, interface,
@@ -1788,6 +1795,7 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as
}
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
ao2_unlock(q);
@@ -1893,6 +1901,7 @@ static void update_realtime_members(struct call_queue *q)
m->dead = 1;
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
while ((interface = ast_category_browse(member_config, interface))) {
rt_handle_member_record(q, interface,
@@ -1913,6 +1922,7 @@ static void update_realtime_members(struct call_queue *q)
}
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
ao2_unlock(q);
ao2_unlock(queues);
ast_config_destroy(member_config);
@@ -2326,6 +2336,7 @@ static int num_available_members(struct call_queue *q)
break;
}
}
+ ao2_iterator_destroy(&mem_iter);
return avl;
}
@@ -2364,6 +2375,7 @@ static int compare_weight(struct call_queue *rq, struct member *member)
break;
}
}
+ ao2_iterator_destroy(&queue_iter);
return found;
}
@@ -3250,6 +3262,7 @@ static int update_queue(struct call_queue *q, struct member *member, int callcom
ao2_unlock(qtmp);
ao2_ref(qtmp, -1);
}
+ ao2_iterator_destroy(&queue_iter);
} else {
ao2_lock(q);
time(&member->lastcall);
@@ -3667,6 +3680,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
if (!tmp) {
ao2_ref(cur, -1);
ao2_unlock(qe->parent);
+ ao2_iterator_destroy(&memi);
if (use_weight)
ao2_unlock(queues);
goto out;
@@ -3675,6 +3689,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
ao2_ref(cur, -1);
ao2_unlock(qe->parent);
+ ao2_iterator_destroy(&memi);
if (use_weight)
ao2_unlock(queues);
free(tmp);
@@ -3684,6 +3699,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
ao2_ref(cur, -1);
ao2_unlock(&qe->parent);
+ ao2_iterator_destroy(&memi);
if (use_weight)
ao2_unlock(queues);
free(tmp);
@@ -3721,6 +3737,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_ref(cur, -1);
ao2_unlock(qe->parent);
+ ao2_iterator_destroy(&memi);
if (use_weight)
ao2_unlock(queues);
free(tmp);
@@ -3755,6 +3772,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
ast_free(tmp);
}
}
+ ao2_iterator_destroy(&memi);
if (qe->parent->timeoutpriority == TIMEOUT_PRIORITY_APP) {
/* Application arguments have higher timeout priority (behaviour for <=1.6) */
@@ -4294,10 +4312,13 @@ static struct member *interface_exists(struct call_queue *q, const char *interfa
mem_iter = ao2_iterator_init(q->members, 0);
while ((mem = ao2_iterator_next(&mem_iter))) {
- if (!strcasecmp(interface, mem->interface))
+ if (!strcasecmp(interface, mem->interface)) {
+ ao2_iterator_destroy(&mem_iter);
return mem;
+ }
ao2_ref(mem, -1);
}
+ ao2_iterator_destroy(&mem_iter);
return NULL;
}
@@ -4338,6 +4359,7 @@ static void dump_queue_members(struct call_queue *pm_queue)
}
value_len += res;
}
+ ao2_iterator_destroy(&mem_iter);
if (value_len && !cur_member) {
if (ast_db_put(pm_family, pm_queue->name, value))
@@ -4529,6 +4551,7 @@ static int set_member_paused(const char *queuename, const char *interface, const
ao2_unlock(q);
queue_unref(q);
}
+ ao2_iterator_destroy(&queue_iter);
return found ? RESULT_SUCCESS : RESULT_FAILURE;
}
@@ -4567,6 +4590,7 @@ static int set_member_penalty(char *queuename, char *interface, int penalty)
ao2_unlock(q);
queue_unref(q);
}
+ ao2_iterator_destroy(&queue_iter);
if (foundinterface) {
return RESULT_SUCCESS;
@@ -5334,6 +5358,7 @@ static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *d
}
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
} else if (!strcasecmp(option, "free")) {
mem_iter = ao2_iterator_init(q->members, 0);
while ((m = ao2_iterator_next(&mem_iter))) {
@@ -5343,6 +5368,7 @@ static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *d
}
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
} else /* must be "count" */
count = q->membercount;
ao2_unlock(q);
@@ -5388,6 +5414,7 @@ static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, cha
}
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
ao2_unlock(q);
queue_unref(q);
} else
@@ -5471,6 +5498,7 @@ static int queue_function_queuememberlist(struct ast_channel *chan, const char *
}
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
ao2_unlock(q);
queue_unref(q);
} else
@@ -5971,6 +5999,7 @@ static int clear_stats(const char *queuename)
clear_queue(q);
ao2_unlock(q);
}
+ ao2_iterator_destroy(&queue_iter);
return 0;
}
@@ -6050,7 +6079,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, char **argv)
}
}
- queue_iter = ao2_iterator_init(queues, F_AO2I_DONTLOCK);
+ queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK);
ao2_lock(queues);
while ((q = ao2_iterator_next(&queue_iter))) {
float sl;
@@ -6114,6 +6143,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, char **argv)
do_print(s, fd, ast_str_buffer(out));
ao2_ref(mem, -1);
}
+ ao2_iterator_destroy(&mem_iter);
}
if (!q->head)
do_print(s, fd, " No Callers");
@@ -6133,6 +6163,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, char **argv)
ao2_unlock(q);
queue_unref(q); /* Unref the iterator's reference */
}
+ ao2_iterator_destroy(&queue_iter);
ao2_unlock(queues);
if (!found) {
if (argc == 3)
@@ -6161,6 +6192,7 @@ static char *complete_queue(const char *line, const char *word, int pos, int sta
}
queue_unref(q);
}
+ ao2_iterator_destroy(&queue_iter);
return ret;
}
@@ -6269,6 +6301,7 @@ static int manager_queues_summary(struct mansession *s, const struct message *m)
}
ao2_ref(mem, -1);
}
+ ao2_iterator_destroy(&mem_iter);
for (qe = q->head; qe; qe = qe->next) {
if ((now - qe->start) > qlongestholdtime) {
qlongestholdtime = now - qe->start;
@@ -6290,6 +6323,7 @@ static int manager_queues_summary(struct mansession *s, const struct message *m)
ao2_unlock(q);
queue_unref(q);
}
+ ao2_iterator_destroy(&queue_iter);
astman_append(s,
"Event: QueueSummaryComplete\r\n"
"%s"
@@ -6363,6 +6397,7 @@ static int manager_queues_status(struct mansession *s, const struct message *m)
}
ao2_ref(mem, -1);
}
+ ao2_iterator_destroy(&mem_iter);
/* List Queue Entries */
pos = 1;
for (qe = q->head; qe; qe = qe->next) {
@@ -6385,6 +6420,7 @@ static int manager_queues_status(struct mansession *s, const struct message *m)
ao2_unlock(q);
queue_unref(q);
}
+ ao2_iterator_destroy(&queue_iter);
astman_append(s,
"Event: QueueStatusComplete\r\n"
@@ -6731,13 +6767,17 @@ static char *complete_queue_remove_member(const char *line, const char *word, in
tmp = ast_strdup(m->interface);
ao2_ref(m, -1);
queue_unref(q);
+ ao2_iterator_destroy(&mem_iter);
+ ao2_iterator_destroy(&queue_iter);
return tmp;
}
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
ao2_unlock(q);
queue_unref(q);
}
+ ao2_iterator_destroy(&queue_iter);
return NULL;
}
@@ -7137,6 +7177,7 @@ static int unload_module(void)
ao2_unlink(queues, q);
queue_unref(q);
}
+ ao2_iterator_destroy(&q_iter);
ao2_ref(queues, -1);
devicestate_tps = ast_taskprocessor_unreference(devicestate_tps);
ast_unload_realtime("queue_members");
diff --git a/channels/chan_console.c b/channels/chan_console.c
index 0dec71e66..a1376822b 100644
--- a/channels/chan_console.c
+++ b/channels/chan_console.c
@@ -1020,6 +1020,7 @@ static char *cli_list_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_a
console_pvt_unlock(pvt);
unref_pvt(pvt);
}
+ ao2_iterator_destroy(&i);
ast_cli(a->fd, "=============================================================\n\n");
@@ -1169,9 +1170,12 @@ static char *cli_console_active(struct ast_cli_entry *e, int cmd, struct ast_cli
if (++x > a->n && !strncasecmp(pvt->name, a->word, strlen(a->word)))
res = ast_strdup(pvt->name);
unref_pvt(pvt);
- if (res)
+ if (res) {
+ ao2_iterator_destroy(&i);
return res;
+ }
}
+ ao2_iterator_destroy(&i);
}
return NULL;
}
@@ -1374,6 +1378,7 @@ static void destroy_pvts(void)
}
unref_pvt(pvt);
}
+ ao2_iterator_destroy(&i);
}
/*!
@@ -1447,6 +1452,7 @@ static void stop_streams(void)
stop_stream(pvt);
unref_pvt(pvt);
}
+ ao2_iterator_destroy(&i);
}
static int unload_module(void)
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 0585aa785..e83a1913b 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -1595,6 +1595,7 @@ static int iax2_getpeername(struct sockaddr_in sin, char *host, int len)
}
peer_unref(peer);
}
+ ao2_iterator_destroy(&i);
if (!peer) {
peer = realtime_peer(NULL, &sin);
@@ -2341,6 +2342,7 @@ static char *handle_cli_iax2_show_callno_limits(struct ast_cli_entry *e, int cmd
}
ao2_ref(peercnt, -1);
}
+ ao2_iterator_destroy(&i);
if (a->argc == 4) {
ast_cli(a->fd, "\nNon-CallToken Validation Limit: %d\nNon-CallToken Validated: %d\n", global_maxcallno_nonval, total_nonval_callno_used);
@@ -3598,6 +3600,7 @@ static char *complete_iax2_peers(const char *line, const char *word, int pos, in
}
peer_unref(peer);
}
+ ao2_iterator_destroy(&i);
return res;
}
@@ -5341,6 +5344,7 @@ static int iax2_getpeertrunk(struct sockaddr_in sin)
}
peer_unref(peer);
}
+ ao2_iterator_destroy(&i);
return res;
}
@@ -6245,6 +6249,7 @@ static char *handle_cli_iax2_show_users(struct ast_cli_entry *e, int cmd, struct
user->contexts ? user->contexts->context : DEFAULT_CONTEXT,
user->ha ? "Yes" : "No", pstr);
}
+ ao2_iterator_destroy(&i);
if (havepattern)
regfree(&regexbuf);
@@ -6371,6 +6376,7 @@ static int __iax2_show_peers(int manager, int fd, struct mansession *s, int argc
}
total_peers++;
}
+ ao2_iterator_destroy(&i);
if (!s)
ast_cli(fd,"%d iax2 peers [%d online, %d offline, %d unmonitored]%s", total_peers, online_peers, offline_peers, unmonitored_peers, term);
@@ -6514,6 +6520,7 @@ static char *complete_iax2_unregister(const char *line, const char *word, int po
}
peer_unref(p);
}
+ ao2_iterator_destroy(&i);
}
return res;
@@ -6634,6 +6641,7 @@ static int manager_iax2_show_peer_list(struct mansession *s, const struct messag
astman_append(s, "Status: %s\r\n\r\n", status);
peer_count++;
}
+ ao2_iterator_destroy(&i);
astman_append(s, "Event: PeerlistComplete\r\n%sListItems: %d\r\n\r\n", idtext, peer_count);
return RESULT_SUCCESS;
@@ -7241,6 +7249,7 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
}
user_unref(user);
}
+ ao2_iterator_destroy(&i);
user = best;
if (!user && !ast_strlen_zero(iaxs[callno]->username)) {
user = realtime_user(iaxs[callno]->username, sin);
@@ -7775,6 +7784,7 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin,
}
peer_unref(peer);
}
+ ao2_iterator_destroy(&i);
if (!peer) {
/* We checked our list and didn't find one. It's unlikely, but possible,
that we're trying to authenticate *to* a realtime peer */
@@ -12366,6 +12376,7 @@ static void prune_users(void)
}
user_unref(user);
}
+ ao2_iterator_destroy(&i);
}
/* Prune peers who still are supposed to be deleted */
@@ -12381,6 +12392,7 @@ static void prune_peers(void)
}
peer_unref(peer);
}
+ ao2_iterator_destroy(&i);
}
static void set_config_destroy(void)
@@ -12845,6 +12857,7 @@ static void poke_all_peers(void)
iax2_poke_peer(peer, 0);
peer_unref(peer);
}
+ ao2_iterator_destroy(&i);
}
static int reload_config(void)
{
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 2b74997b2..7f473d9f8 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -13875,7 +13875,6 @@ static char *sip_show_inuse(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
ast_cli(a->fd, FORMAT, "* Peer name", "In use", "Limit");
i = ao2_iterator_init(peers, 0);
-
while ((peer = ao2_t_iterator_next(&i, "iterate thru peer table"))) {
ao2_lock(peer);
if (peer->call_limit)
@@ -13888,6 +13887,7 @@ static char *sip_show_inuse(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
ao2_unlock(peer);
unref_peer(peer, "toss iterator pointer");
}
+ ao2_iterator_destroy(&i);
return CLI_SUCCESS;
#undef FORMAT
@@ -14113,6 +14113,7 @@ static char *sip_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
ao2_unlock(user);
unref_peer(user, "sip show users");
}
+ ao2_iterator_destroy(&user_iter);
if (havepattern)
regfree(&regexbuf);
@@ -14301,6 +14302,7 @@ static char *_sip_show_peers(int fd, int *total, struct mansession *s, const str
peerarray[total_peers++] = peer;
ao2_unlock(peer);
}
+ ao2_iterator_destroy(&i);
qsort(peerarray, total_peers, sizeof(struct sip_peer *), peercomparefunc);
@@ -14681,6 +14683,7 @@ static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli
ao2_unlock(pi);
unref_peer(pi, "toss iterator peer ptr");
}
+ ao2_iterator_destroy(&i);
if (pruned) {
ao2_t_callback(peers, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, peer_is_marked, NULL,
"initiating callback to remove marked peers");
@@ -15178,6 +15181,7 @@ static char *complete_sip_user(const char *word, int state)
ao2_unlock(user);
unref_peer(user, "complete sip user");
}
+ ao2_iterator_destroy(&user_iter);
return result;
}
/*! \brief Support routine for 'sip show user' CLI */
@@ -15850,7 +15854,6 @@ static char *complete_sipch(const char *line, const char *word, int pos, int sta
}
i = ao2_iterator_init(dialogs, 0);
-
while ((cur = ao2_t_iterator_next(&i, "iterate thru dialogs"))) {
sip_pvt_lock(cur);
if (!strncasecmp(word, cur->callid, wordlen) && ++which > state) {
@@ -15862,6 +15865,7 @@ static char *complete_sipch(const char *line, const char *word, int pos, int sta
sip_pvt_unlock(cur);
dialog_unref(cur, "drop ref in iterator loop");
}
+ ao2_iterator_destroy(&i);
return c;
}
@@ -15886,6 +15890,7 @@ static char *complete_sip_peer(const char *word, int state, int flags2)
break;
}
}
+ ao2_iterator_destroy(&i);
return result;
}
@@ -15895,21 +15900,22 @@ static char *complete_sip_registered_peer(const char *word, int state, int flags
char *result = NULL;
int wordlen = strlen(word);
int which = 0;
- struct ao2_iterator i;
- struct sip_peer *peer;
-
- i = ao2_iterator_init(peers, 0);
- while ((peer = ao2_t_iterator_next(&i, "iterate thru peers table"))) {
- if (!strncasecmp(word, peer->name, wordlen) &&
- (!flags2 || ast_test_flag(&peer->flags[1], flags2)) &&
- ++which > state && peer->expire > 0)
- result = ast_strdup(peer->name);
- if (result) {
- unref_peer(peer, "toss iterator peer ptr before break");
- break;
- }
- unref_peer(peer, "toss iterator peer ptr");
+ struct ao2_iterator i;
+ struct sip_peer *peer;
+
+ i = ao2_iterator_init(peers, 0);
+ while ((peer = ao2_t_iterator_next(&i, "iterate thru peers table"))) {
+ if (!strncasecmp(word, peer->name, wordlen) &&
+ (!flags2 || ast_test_flag(&peer->flags[1], flags2)) &&
+ ++which > state && peer->expire > 0)
+ result = ast_strdup(peer->name);
+ if (result) {
+ unref_peer(peer, "toss iterator peer ptr before break");
+ break;
+ }
+ unref_peer(peer, "toss iterator peer ptr");
}
+ ao2_iterator_destroy(&i);
return result;
}
@@ -15995,7 +16001,6 @@ static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_a
len = strlen(a->argv[3]);
i = ao2_iterator_init(dialogs, 0);
-
while ((cur = ao2_t_iterator_next(&i, "iterate thru dialogs"))) {
sip_pvt_lock(cur);
@@ -16075,6 +16080,7 @@ static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_a
ao2_t_ref(cur, -1, "toss dialog ptr set by iterator_next");
}
+ ao2_iterator_destroy(&i);
if (!found)
ast_cli(a->fd, "No such SIP Call ID starting with '%s'\n", a->argv[3]);
@@ -16131,6 +16137,7 @@ static char *sip_show_history(struct ast_cli_entry *e, int cmd, struct ast_cli_a
sip_pvt_unlock(cur);
ao2_t_ref(cur, -1, "toss dialog ptr from iterator_next");
}
+ ao2_iterator_destroy(&i);
if (!found)
ast_cli(a->fd, "No such SIP Call ID starting with '%s'\n", a->argv[3]);
@@ -20979,7 +20986,6 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
ignored (or generate errors)
*/
i = ao2_iterator_init(dialogs, 0);
-
while ((p_old = ao2_t_iterator_next(&i, "iterate thru dialogs"))) {
if (p_old == p) {
ao2_t_ref(p_old, -1, "toss dialog ptr from iterator_next before continue");
@@ -21006,6 +21012,7 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
sip_pvt_unlock(p_old);
ao2_t_ref(p_old, -1, "toss dialog ptr from iterator_next");
}
+ ao2_iterator_destroy(&i);
}
if (!p->expiry) {
pvt_set_needdestroy(p, "forcing expiration");
@@ -25004,11 +25011,10 @@ static void sip_poke_all_peers(void)
struct ao2_iterator i;
struct sip_peer *peer;
- i = ao2_iterator_init(peers, 0);
-
if (!speerobjs) /* No peers, just give up */
return;
+ i = ao2_iterator_init(peers, 0);
while ((peer = ao2_t_iterator_next(&i, "iterate thru peers table"))) {
ao2_lock(peer);
if (num == global_qualify_peers) {
@@ -25024,6 +25030,7 @@ static void sip_poke_all_peers(void)
ao2_unlock(peer);
unref_peer(peer, "toss iterator peer ptr");
}
+ ao2_iterator_destroy(&i);
}
/*! \brief Send all known registrations */
@@ -25320,6 +25327,7 @@ static int unload_module(void)
ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
ao2_t_ref(p, -1, "toss dialog ptr from iterator_next");
}
+ ao2_iterator_destroy(&i);
ast_mutex_lock(&monlock);
if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
@@ -25336,6 +25344,7 @@ static int unload_module(void)
dialog_unlink_all(p, TRUE, TRUE);
ao2_t_ref(p, -1, "throw away iterator result");
}
+ ao2_iterator_destroy(&i);
/* Free memory for local network address mask */
ast_free_ha(localaddr);
diff --git a/funcs/func_dialgroup.c b/funcs/func_dialgroup.c
index 4e4f63389..467bc87fa 100644
--- a/funcs/func_dialgroup.c
+++ b/funcs/func_dialgroup.c
@@ -160,6 +160,7 @@ static int dialgroup_read(struct ast_channel *chan, const char *cmd, char *data,
}
ao2_ref(entry, -1);
}
+ ao2_iterator_destroy(&i);
return res;
}
diff --git a/include/asterisk/astobj2.h b/include/asterisk/astobj2.h
index a9bd61d2f..591e1fa00 100644
--- a/include/asterisk/astobj2.h
+++ b/include/asterisk/astobj2.h
@@ -598,6 +598,8 @@ Operations on container include:
... do something on o ...
ao2_ref(o, -1);
}
+
+ ao2_iterator_destroy(&i);
\endcode
The difference with the callback is that the control
@@ -973,15 +975,15 @@ void *_ao2_find(struct ao2_container *c, void *arg, enum search_flags flags);
/*! \brief
*
*
- * When we need to walk through a container, we use
+ * When we need to walk through a container, we use an
* ao2_iterator to keep track of the current position.
*
* Because the navigation is typically done without holding the
- * lock on the container across the loop,
- * objects can be inserted or deleted or moved
- * while we work. As a consequence, there is no guarantee that
- * the we manage to touch all the elements on the list, or it
- * is possible that we touch the same object multiple times.
+ * lock on the container across the loop, objects can be inserted or deleted
+ * or moved while we work. As a consequence, there is no guarantee that
+ * we manage to touch all the elements in the container, and it is possible
+ * that we touch the same object multiple times.
+ *
* However, within the current hash table container, the following is true:
* - It is not possible to miss an object in the container while iterating
* unless it gets added after the iteration begins and is added to a bucket
@@ -1000,6 +1002,10 @@ void *_ao2_find(struct ao2_container *c, void *arg, enum search_flags flags);
* ao2_iterator_next() has its refcount incremented,
* and the reference must be explicitly released when done with it.
*
+ * In addition, ao2_iterator_init() will hold a reference to the container
+ * being iterated, which will be freed when ao2_iterator_destroy() is called
+ * to free up the resources used by the iterator (if any).
+ *
* Example:
*
* \code
@@ -1015,12 +1021,14 @@ void *_ao2_find(struct ao2_container *c, void *arg, enum search_flags flags);
* ao2_ref(o, -1);
* }
*
+ * ao2_iterator_destroy(&i);
+ *
* \endcode
*
*/
/*! \brief
- * The Astobj2 iterator
+ * The astobj2 iterator
*
* \note You are not supposed to know the internals of an iterator!
* We would like the iterator to be opaque, unfortunately
@@ -1036,21 +1044,20 @@ void *_ao2_find(struct ao2_container *c, void *arg, enum search_flags flags);
* - a bucket number;
* - the object_id, which is also the container version number
* when the object was inserted. This identifies the object
- * univoquely, however reaching the desired object requires
+ * uniquely, however reaching the desired object requires
* scanning a list.
* - a pointer, and a container version when we saved the pointer.
* If the container has not changed its version number, then we
* can safely follow the pointer to reach the object in constant time.
*
* Details are in the implementation of ao2_iterator_next()
- * A freshly-initialized iterator has bucket=0, version = 0.
+ * A freshly-initialized iterator has bucket=0, version=0.
*/
struct ao2_iterator {
/*! the container */
struct ao2_container *c;
/*! operation flags */
int flags;
-#define F_AO2I_DONTLOCK 1 /*!< don't lock when iterating */
/*! current bucket */
int bucket;
/*! container version */
@@ -1061,12 +1068,47 @@ struct ao2_iterator {
unsigned int version;
};
-/* the flags field can contain F_AO2I_DONTLOCK, which will prevent
- ao2_iterator_next calls from locking the container while it
- searches for the next pointer */
+/*! Flags that can be passed to ao2_iterator_init() to modify the behavior
+ * of the iterator.
+ */
+enum ao2_iterator_flags {
+ /*! Prevents ao2_iterator_next() from locking the container
+ * while retrieving the next object from it.
+ */
+ AO2_ITERATOR_DONTLOCK = (1 << 0),
+};
+/*!
+ * \brief Create an iterator for a container
+ *
+ * \param c the container
+ * \param flags one or more flags from ao2_iterator_flags
+ *
+ * \retval the constructed iterator
+ *
+ * \note This function does \b not take a pointer to an iterator;
+ * rather, it returns an iterator structure that should be
+ * assigned to (overwriting) an existing iterator structure
+ * allocated on the stack or on the heap.
+ *
+ * This function will take a reference on the container being iterated.
+ *
+ */
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags);
+/*!
+ * \brief Destroy a container iterator
+ *
+ * \param i the iterator to destroy
+ *
+ * \retval none
+ *
+ * This function will release the container reference held by the iterator
+ * and any other resources it may be holding.
+ *
+ */
+void ao2_iterator_destroy(struct ao2_iterator *i);
+
#ifdef REF_DEBUG
#define ao2_t_iterator_next(arg1, arg2) _ao2_iterator_next_debug((arg1), (arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
diff --git a/main/astobj2.c b/main/astobj2.c
index a5ae37ca3..53f263946 100644
--- a/main/astobj2.c
+++ b/main/astobj2.c
@@ -783,10 +783,21 @@ struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
.c = c,
.flags = flags
};
+
+ ao2_ref(c, +1);
return a;
}
+/*!
+ * destroy an iterator
+ */
+void ao2_iterator_destroy(struct ao2_iterator *i)
+{
+ ao2_ref(i->c, -1);
+ i->c = NULL;
+}
+
/*
* move to the next element in the container.
*/
@@ -801,7 +812,7 @@ static void * __ao2_iterator_next(struct ao2_iterator *a, struct bucket_list **q
if (INTERNAL_OBJ(a->c) == NULL)
return NULL;
- if (!(a->flags & F_AO2I_DONTLOCK))
+ if (!(a->flags & AO2_ITERATOR_DONTLOCK))
ao2_lock(a->c);
/* optimization. If the container is unchanged and
@@ -857,7 +868,7 @@ void * _ao2_iterator_next_debug(struct ao2_iterator *a, char *tag, char *file, i
_ao2_ref_debug(ret, 1, tag, file, line, funcname);
}
- if (!(a->flags & F_AO2I_DONTLOCK))
+ if (!(a->flags & AO2_ITERATOR_DONTLOCK))
ao2_unlock(a->c);
return ret;
@@ -875,7 +886,7 @@ void * _ao2_iterator_next(struct ao2_iterator *a)
_ao2_ref(ret, 1);
}
- if (!(a->flags & F_AO2I_DONTLOCK))
+ if (!(a->flags & AO2_ITERATOR_DONTLOCK))
ao2_unlock(a->c);
return ret;
diff --git a/res/res_clialiases.c b/res/res_clialiases.c
index 16458c250..853735ba3 100644
--- a/res/res_clialiases.c
+++ b/res/res_clialiases.c
@@ -154,10 +154,10 @@ static char *alias_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a
ast_cli(a->fd, FORMAT, "Alias Command", "Real Command");
i = ao2_iterator_init(cli_aliases, 0);
-
for (; (alias = ao2_iterator_next(&i)); ao2_ref(alias, -1)) {
ast_cli(a->fd, FORMAT, alias->alias, alias->real_cmd);
}
+ ao2_iterator_destroy(&i);
return CLI_SUCCESS;
#undef FORMAT
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index 69b2d6c62..a3dcea362 100644
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -1582,7 +1582,6 @@ static char *handle_cli_moh_show_files(struct ast_cli_entry *e, int cmd, struct
return CLI_SHOWUSAGE;
i = ao2_iterator_init(mohclasses, 0);
-
for (; (class = ao2_t_iterator_next(&i, "Show files iterator")); mohclass_unref(class, "Unref iterator in moh show files")) {
int x;
@@ -1595,6 +1594,7 @@ static char *handle_cli_moh_show_files(struct ast_cli_entry *e, int cmd, struct
ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]);
}
}
+ ao2_iterator_destroy(&i);
return CLI_SUCCESS;
}
@@ -1619,7 +1619,6 @@ static char *handle_cli_moh_show_classes(struct ast_cli_entry *e, int cmd, struc
return CLI_SHOWUSAGE;
i = ao2_iterator_init(mohclasses, 0);
-
for (; (class = ao2_t_iterator_next(&i, "Show classes iterator")); mohclass_unref(class, "Unref iterator in moh show classes")) {
ast_cli(a->fd, "Class: %s\n", class->name);
ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
@@ -1631,6 +1630,7 @@ static char *handle_cli_moh_show_classes(struct ast_cli_entry *e, int cmd, struc
ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(class->format));
}
}
+ ao2_iterator_destroy(&i);
return CLI_SUCCESS;
}
diff --git a/res/res_odbc.c b/res/res_odbc.c
index 96e0e6207..ac1cff75e 100644
--- a/res/res_odbc.c
+++ b/res/res_odbc.c
@@ -898,6 +898,7 @@ static char *handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_c
break;
}
}
+ ao2_iterator_destroy(&aoi);
if (!ret && !strncasecmp(a->word, "all", length) && ++which > a->n) {
ret = ast_strdup("all");
}
@@ -932,6 +933,7 @@ static char *handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_c
ast_mutex_unlock(&current->lock);
ao2_ref(current, -1);
}
+ ao2_iterator_destroy(&aoi2);
} else {
/* Should only ever be one of these (unless there are transactions) */
struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
@@ -940,11 +942,13 @@ static char *handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_c
current->up && ast_odbc_sanity_check(current) ? "Yes" : "No");
ao2_ref(current, -1);
}
+ ao2_iterator_destroy(&aoi2);
}
ast_cli(a->fd, "\n");
}
ao2_ref(class, -1);
}
+ ao2_iterator_destroy(&aoi);
return CLI_SUCCESS;
}
@@ -1609,6 +1613,7 @@ static int reload(void)
class->delme = 1;
ao2_ref(class, -1);
}
+ ao2_iterator_destroy(&aoi);
load_odbc_config();
@@ -1648,6 +1653,7 @@ static int reload(void)
* b) the object has already been destroyed.
*/
}
+ ao2_iterator_destroy(&aoi2);
ao2_unlink(class_container, class); /* unlink C-ref from container (reference handled implicitly) */
/* At this point, either
* a) there's an outstanding O-ref, which holds an outstanding C-ref, or
@@ -1657,6 +1663,7 @@ static int reload(void)
}
ao2_ref(class, -1); /* C-ref-- (by iterator) */
}
+ ao2_iterator_destroy(&aoi);
/* Empty the cache; it will get rebuilt the next time the tables are needed. */
AST_RWLIST_WRLOCK(&odbc_tables);
diff --git a/res/res_phoneprov.c b/res/res_phoneprov.c
index 748327bf3..0a920e67a 100644
--- a/res/res_phoneprov.c
+++ b/res/res_phoneprov.c
@@ -831,6 +831,7 @@ static void delete_users(void)
ao2_unlink(users, user);
user = unref_user(user);
}
+ ao2_iterator_destroy(&i);
}
/*! \brief Build and return a user structure based on gathered config data */
@@ -1066,6 +1067,7 @@ static void delete_routes(void)
ao2_unlink(http_routes, route);
route = unref_route(route);
}
+ ao2_iterator_destroy(&i);
}
/*! \brief Delete all phone profiles, freeing their memory */
@@ -1079,6 +1081,7 @@ static void delete_profiles(void)
ao2_unlink(profiles, profile);
profile = unref_profile(profile);
}
+ ao2_iterator_destroy(&i);
}
/*! \brief A dialplan function that can be used to print a string for each phoneprov user */
@@ -1106,6 +1109,7 @@ static int pp_each_user_exec(struct ast_channel *chan, const char *cmd, char *da
ast_build_string(&buf, &len, "%s", expand_buf);
user = unref_user(user);
}
+ ao2_iterator_destroy(&i);
return 0;
}
@@ -1213,6 +1217,7 @@ static char *handle_show_routes(struct ast_cli_entry *e, int cmd, struct ast_cli
ast_cli(a->fd, FORMAT, route->uri, route->file->template);
route = unref_route(route);
}
+ ao2_iterator_destroy(&i);
ast_cli(a->fd, "\nDynamic routes\n\n");
ast_cli(a->fd, FORMAT, "Relative URI", "Template");
@@ -1223,6 +1228,7 @@ static char *handle_show_routes(struct ast_cli_entry *e, int cmd, struct ast_cli
ast_cli(a->fd, FORMAT, route->uri, route->file->template);
route = unref_route(route);
}
+ ao2_iterator_destroy(&i);
return CLI_SUCCESS;
}