summaryrefslogtreecommitdiff
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_calendar.c5
-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
12 files changed, 184 insertions, 43 deletions
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 7b19f9f3e..80ce8dd39 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -1139,12 +1139,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;
@@ -1196,7 +1198,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);
@@ -1215,10 +1216,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));
@@ -1398,6 +1401,7 @@ static void clear_queue(struct call_queue *q)
mem->calls = 0;
ao2_ref(mem, -1);
}
+ ao2_iterator_destroy(&mem_iter);
}
}
@@ -1756,6 +1760,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) {
@@ -1786,6 +1791,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 */
@@ -1934,6 +1940,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,
@@ -1954,6 +1961,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);
@@ -2059,6 +2067,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,
@@ -2079,6 +2088,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);
@@ -2506,6 +2516,7 @@ static int num_available_members(struct call_queue *q)
break;
}
}
+ ao2_iterator_destroy(&mem_iter);
return avl;
}
@@ -2544,6 +2555,7 @@ static int compare_weight(struct call_queue *rq, struct member *member)
break;
}
}
+ ao2_iterator_destroy(&queue_iter);
return found;
}
@@ -3540,6 +3552,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);
@@ -3960,6 +3973,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;
@@ -3968,6 +3982,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);
@@ -3977,6 +3992,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);
@@ -4025,6 +4041,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);
@@ -4060,6 +4077,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) */
@@ -4597,10 +4615,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;
}
@@ -4641,6 +4662,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))
@@ -4832,6 +4854,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;
}
@@ -4870,6 +4893,7 @@ static int set_member_penalty(const char *queuename, const char *interface, int
ao2_unlock(q);
queue_unref(q);
}
+ ao2_iterator_destroy(&queue_iter);
if (foundinterface) {
return RESULT_SUCCESS;
@@ -5647,6 +5671,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))) {
@@ -5656,6 +5681,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);
@@ -5701,6 +5727,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
@@ -5784,6 +5811,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
@@ -6284,6 +6312,7 @@ static int clear_stats(const char *queuename)
clear_queue(q);
ao2_unlock(q);
}
+ ao2_iterator_destroy(&queue_iter);
return 0;
}
@@ -6363,7 +6392,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
}
}
- 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;
@@ -6427,6 +6456,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
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");
@@ -6446,6 +6476,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
ao2_unlock(q);
queue_unref(q); /* Unref the iterator's reference */
}
+ ao2_iterator_destroy(&queue_iter);
ao2_unlock(queues);
if (!found) {
if (argc == 3)
@@ -6474,6 +6505,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;
}
@@ -6582,6 +6614,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;
@@ -6603,6 +6636,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"
@@ -6676,6 +6710,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) {
@@ -6698,6 +6733,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"
@@ -7044,13 +7080,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;
}
@@ -7450,6 +7490,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 4be7f92aa..ead0b1231 100644
--- a/channels/chan_console.c
+++ b/channels/chan_console.c
@@ -1013,6 +1013,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");
@@ -1162,9 +1163,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;
}
@@ -1367,6 +1371,7 @@ static void destroy_pvts(void)
}
unref_pvt(pvt);
}
+ ao2_iterator_destroy(&i);
}
/*!
@@ -1440,6 +1445,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 c3bc2b38d..0feec77d1 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -1640,6 +1640,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);
@@ -2385,6 +2386,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);
@@ -3641,6 +3643,7 @@ static char *complete_iax2_peers(const char *line, const char *word, int pos, in
}
peer_unref(peer);
}
+ ao2_iterator_destroy(&i);
return res;
}
@@ -5422,6 +5425,7 @@ static int iax2_getpeertrunk(struct sockaddr_in sin)
}
peer_unref(peer);
}
+ ao2_iterator_destroy(&i);
return res;
}
@@ -6326,6 +6330,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);
@@ -6452,6 +6457,7 @@ static int __iax2_show_peers(int manager, int fd, struct mansession *s, const in
}
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);
@@ -6595,6 +6601,7 @@ static char *complete_iax2_unregister(const char *line, const char *word, int po
}
peer_unref(p);
}
+ ao2_iterator_destroy(&i);
}
return res;
@@ -6715,6 +6722,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;
@@ -7322,6 +7330,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);
@@ -7856,6 +7865,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 */
@@ -12459,6 +12469,7 @@ static void prune_users(void)
}
user_unref(user);
}
+ ao2_iterator_destroy(&i);
}
/* Prune peers who still are supposed to be deleted */
@@ -12474,6 +12485,7 @@ static void prune_peers(void)
}
peer_unref(peer);
}
+ ao2_iterator_destroy(&i);
}
static void set_config_destroy(void)
@@ -12950,6 +12962,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 4bfe696da..ee2c99eb3 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -14609,7 +14609,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)
@@ -14622,6 +14621,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
@@ -14813,6 +14813,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);
@@ -14987,6 +14988,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);
@@ -15380,6 +15382,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");
@@ -15873,6 +15876,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 */
@@ -16547,7 +16551,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) {
@@ -16559,6 +16562,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;
}
@@ -16583,6 +16587,7 @@ static char *complete_sip_peer(const char *word, int state, int flags2)
break;
}
}
+ ao2_iterator_destroy(&i);
return result;
}
@@ -16592,21 +16597,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;
}
@@ -16692,7 +16698,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);
@@ -16772,6 +16777,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]);
@@ -16828,6 +16834,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]);
@@ -22048,7 +22055,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");
@@ -22075,6 +22081,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");
@@ -26109,11 +26116,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) {
@@ -26129,6 +26135,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 */
@@ -26420,6 +26427,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)) {
@@ -26436,6 +26444,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 71b86c909..f0393d34f 100644
--- a/include/asterisk/astobj2.h
+++ b/include/asterisk/astobj2.h
@@ -597,6 +597,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
@@ -975,15 +977,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
@@ -1002,6 +1004,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
@@ -1017,12 +1023,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
@@ -1038,21 +1046,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 */
@@ -1063,12 +1070,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 ad6dcb1a2..01fd4b17f 100644
--- a/main/astobj2.c
+++ b/main/astobj2.c
@@ -784,10 +784,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.
*/
@@ -802,7 +813,7 @@ static void *internal_ao2_iterator_next(struct ao2_iterator *a, struct bucket_li
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
@@ -858,7 +869,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;
@@ -876,7 +887,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_calendar.c b/res/res_calendar.c
index e6f8d53f3..e916ac0f0 100644
--- a/res/res_calendar.c
+++ b/res/res_calendar.c
@@ -1043,12 +1043,14 @@ static int calendar_query_exec(struct ast_channel *chan, const char *cmd, char *
ast_debug(10, "%s (%ld - %ld) overlapped with (%ld - %ld)\n", event->summary, (long) event->start, (long) event->end, (long) start, (long) end);
if (add_event_to_list(events, event, start, end) < 0) {
event = ast_calendar_unref_event(event);
+ ao2_iterator_destroy(&i);
return -1;
}
}
event = ast_calendar_unref_event(event);
}
+ ao2_iterator_destroy(&i);
ast_channel_lock(chan);
do {
@@ -1292,6 +1294,7 @@ static char *handle_show_calendars(struct ast_cli_entry *e, int cmd, struct ast_
ast_cli(a->fd, FORMAT, cal->name, cal->tech->type, calendar_is_busy(cal) ? "busy" : "free");
cal = unref_calendar(cal);
}
+ ao2_iterator_destroy(&i);
return CLI_SUCCESS;
#undef FORMAT
@@ -1345,6 +1348,7 @@ static char *handle_show_calendar(struct ast_cli_entry *e, int cmd, struct ast_c
}
cal = unref_calendar(cal);
}
+ ao2_iterator_destroy(&i);
return ret;
}
@@ -1384,6 +1388,7 @@ static char *handle_show_calendar(struct ast_cli_entry *e, int cmd, struct ast_c
event = ast_calendar_unref_event(event);
}
+ ao2_iterator_destroy(&i);
cal = unref_calendar(cal);
return CLI_SUCCESS;
#undef FORMAT
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 090f927a2..b5bc77d74 100644
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -1608,7 +1608,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;
@@ -1621,6 +1620,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;
}
@@ -1645,7 +1645,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>"));
@@ -1657,6 +1656,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 2fec8884e..9498cc591 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 a8ebe67a0..49fdbf870 100644
--- a/res/res_phoneprov.c
+++ b/res/res_phoneprov.c
@@ -830,6 +830,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 */
@@ -1076,6 +1077,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 */
@@ -1089,6 +1091,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 */
@@ -1126,6 +1129,7 @@ static int pp_each_user_helper(struct ast_channel *chan, char *data, char *buf,
}
user = unref_user(user);
}
+ ao2_iterator_destroy(&i);
ast_free(str);
return 0;
@@ -1253,6 +1257,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");
@@ -1263,6 +1268,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;
}