diff options
-rw-r--r-- | apps/app_queue.c | 47 | ||||
-rw-r--r-- | channels/chan_console.c | 8 | ||||
-rw-r--r-- | channels/chan_iax2.c | 13 | ||||
-rw-r--r-- | channels/chan_sip.c | 49 | ||||
-rw-r--r-- | funcs/func_dialgroup.c | 1 | ||||
-rw-r--r-- | include/asterisk/astobj2.h | 68 | ||||
-rw-r--r-- | main/astobj2.c | 17 | ||||
-rw-r--r-- | res/res_clialiases.c | 2 | ||||
-rw-r--r-- | res/res_musiconhold.c | 4 | ||||
-rw-r--r-- | res/res_odbc.c | 7 | ||||
-rw-r--r-- | res/res_phoneprov.c | 6 |
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(®exbuf); @@ -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(®exbuf); @@ -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(¤t->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; } |