[asterisk-commits] tilghman: branch 1.4 r82155 - /branches/1.4/apps/app_queue.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Sep 10 13:02:03 CDT 2007


Author: tilghman
Date: Mon Sep 10 13:02:02 2007
New Revision: 82155

URL: http://svn.digium.com/view/asterisk?view=rev&rev=82155
Log:
Convert struct member to use refcounts (closes issue #10199)

Modified:
    branches/1.4/apps/app_queue.c

Modified: branches/1.4/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/branches/1.4/apps/app_queue.c?view=diff&rev=82155&r1=82154&r2=82155
==============================================================================
--- branches/1.4/apps/app_queue.c (original)
+++ branches/1.4/apps/app_queue.c Mon Sep 10 13:02:02 2007
@@ -92,6 +92,7 @@
 #include "asterisk/astdb.h"
 #include "asterisk/devicestate.h"
 #include "asterisk/stringfields.h"
+#include "asterisk/astobj2.h"
 
 enum {
 	QUEUE_STRATEGY_RINGALL = 0,
@@ -324,7 +325,6 @@
 	time_t lastcall;                    /*!< When last successful call was hungup */
 	unsigned int dead:1;                /*!< Used to detect members deleted in realtime */
 	unsigned int delme:1;               /*!< Flag to delete entry on reload */
-	struct member *next;                /*!< Next member */
 };
 
 struct member_interface {
@@ -396,7 +396,7 @@
 	int memberdelay;                    /*!< Seconds to delay connecting member to caller */
 	int autofill;                       /*!< Ignore the head call status and ring an available agent */
 	
-	struct member *members;             /*!< Head of the list of members */
+	struct ao2_container *members;             /*!< Head of the list of members */
 	int membercount;					/*!< Number of members in queue */
 	struct queue_ent *head;             /*!< Head of the list of callers */
 	AST_LIST_ENTRY(call_queue) list;    /*!< Next call queue */
@@ -481,28 +481,38 @@
 static enum queue_member_status get_member_status(struct call_queue *q, int max_penalty)
 {
 	struct member *member;
+	struct ao2_iterator i;
 	enum queue_member_status result = QUEUE_NO_MEMBERS;
 
 	ast_mutex_lock(&q->lock);
-	for (member = q->members; member; member = member->next) {
-		if (max_penalty && (member->penalty > max_penalty))
+	i = ao2_iterator_init(q->members, 0);
+	while ((member = ao2_iterator_next(&i))) {
+		if (max_penalty && (member->penalty > max_penalty)) {
+			ao2_ref(member, -1);
 			continue;
-
-		if (member->paused) continue;
+		}
+
+		if (member->paused) {
+			ao2_ref(member, -1);
+			continue;
+		}
 
 		switch (member->status) {
 		case AST_DEVICE_INVALID:
 			/* nothing to do */
+			ao2_ref(member, -1);
 			break;
 		case AST_DEVICE_UNAVAILABLE:
 			result = QUEUE_NO_REACHABLE_MEMBERS;
+			ao2_ref(member, -1);
 			break;
 		default:
 			ast_mutex_unlock(&q->lock);
+			ao2_ref(member, -1);
 			return QUEUE_NORMAL;
 		}
 	}
-	
+
 	ast_mutex_unlock(&q->lock);
 	return result;
 }
@@ -517,6 +527,7 @@
 	struct call_queue *q;
 	struct statechange *sc = data;
 	struct member *cur;
+	struct ao2_iterator i;
 	struct member_interface *curint;
 	char *loc;
 	char *technology;
@@ -556,7 +567,8 @@
 	AST_LIST_LOCK(&queues);
 	AST_LIST_TRAVERSE(&queues, q, list) {
 		ast_mutex_lock(&q->lock);
-		for (cur = q->members; cur; cur = cur->next) {
+		i = ao2_iterator_init(q->members, 0);
+		while ((cur = ao2_iterator_next(&i))) {
 			char *interface;
 			char *slash_pos;
 			interface = ast_strdupa(cur->interface);
@@ -564,13 +576,17 @@
 				if ((slash_pos = strchr(slash_pos + 1, '/')))
 					*slash_pos = '\0';
 
-			if (strcasecmp(sc->dev, interface))
+			if (strcasecmp(sc->dev, interface)) {
+				ao2_ref(cur, -1);
 				continue;
+			}
 
 			if (cur->status != sc->state) {
 				cur->status = sc->state;
-				if (q->maskmemberstatus)
+				if (q->maskmemberstatus) {
+					ao2_ref(cur, -1);
 					continue;
+				}
 
 				manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
 					"Queue: %s\r\n"
@@ -585,6 +601,7 @@
 					q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static",
 					cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
 			}
+			ao2_ref(cur, -1);
 		}
 		ast_mutex_unlock(&q->lock);
 	}
@@ -623,7 +640,7 @@
 {
 	struct member *cur;
 	
-	if ((cur = ast_calloc(1, sizeof(*cur)))) {
+	if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
 		cur->penalty = penalty;
 		cur->paused = paused;
 		ast_copy_string(cur->interface, interface, sizeof(cur->interface));
@@ -645,6 +662,34 @@
 		ast_copy_string(q->name, queuename, sizeof(q->name));
 	}
 	return q;
+}
+
+static int compress_char(const char c)
+{
+	if (c < 32)
+		return 0;
+	else if (c > 96)
+		return c - 64;
+	else
+		return c - 32;
+}
+
+static int member_hash_fn(const void *obj, const int flags)
+{
+	const struct member *mem = obj;
+	const char *chname = strchr(mem->interface, '/');
+	int ret = 0, i;
+	if (!chname)
+		chname = mem->interface;
+	for (i = 0; i < 5 && chname[i]; i++)
+		ret += compress_char(chname[i]) << (i * 6);
+	return ret;
+}
+
+static int member_cmp_fn(void *obj1, void *obj2, int flags)
+{
+	struct member *mem1 = obj1, *mem2 = obj2;
+	return strcmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH;
 }
 
 static void init_queue(struct call_queue *q)
@@ -668,6 +713,7 @@
 	q->context[0] = '\0';
 	q->monfmt[0] = '\0';
 	q->periodicannouncefrequency = 0;
+	q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
 	q->membercount = 0;
 	ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
 	ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
@@ -729,9 +775,9 @@
 	AST_LIST_LOCK(&queues);
 	AST_LIST_TRAVERSE(&queues, q, list) {
 		ast_mutex_lock(&q->lock);
-		for (mem = q->members; mem && !ret; mem = mem->next) {
-			if (!strcasecmp(interface, mem->interface))
-				ret = 1;
+		if ((mem = ao2_find(q->members, (char *)interface, 0))) {
+			ao2_ref(mem, -1);
+			ret = 1;
 		}
 		ast_mutex_unlock(&q->lock);
 		if (ret)
@@ -930,7 +976,7 @@
 
 static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str)
 {
-	struct member *m, *prev_m;
+	struct member *m;
 	int penalty = 0;
 	int paused  = 0;
 
@@ -947,9 +993,7 @@
 	}
 
 	/* Find the member, or the place to put a new one. */
-	for (m = q->members, prev_m = NULL;
-		m && strcmp(m->interface, interface);
-		prev_m = m, m = m->next);
+	m = ao2_find(q->members, interface, 0);
 
 	/* Create a new one if not found, else update penalty */
 	if (!m) {
@@ -957,11 +1001,7 @@
 			m->dead = 0;
 			m->realtime = 1;
 			add_to_interfaces(interface);
-			if (prev_m) {
-				prev_m->next = m;
-			} else {
-				q->members = m;
-			}
+			ao2_link(q->members, m);
 			q->membercount++;
 		}
 	} else {
@@ -969,26 +1009,23 @@
 		if (paused_str)
 			m->paused = paused;
 		m->penalty = penalty;
+		ao2_ref(m, -1);
 	}
 }
 
 static void free_members(struct call_queue *q, int all)
 {
 	/* Free non-dynamic members */
-	struct member *curm, *next, *prev = NULL;
-
-	for (curm = q->members; curm; curm = next) {
-		next = curm->next;
-		if (all || !curm->dynamic) {
-			if (prev)
-				prev->next = next;
-			else
-				q->members = next;
-			remove_from_interfaces(curm->interface);
+	struct member *cur;
+	struct ao2_iterator i = ao2_iterator_init(q->members, 0);
+
+	while ((cur = ao2_iterator_next(&i))) {
+		if (all || !cur->dynamic) {
+			ao2_unlink(q->members, cur);
+			remove_from_interfaces(cur->interface);
 			q->membercount--;
-			free(curm);
-		} else
-			prev = curm;
+		}
+		ao2_ref(cur, -1);
 	}
 }
 
@@ -996,6 +1033,7 @@
 {
 	free_members(q, 1);
 	ast_mutex_destroy(&q->lock);
+	ao2_ref(q->members, -1);
 	free(q);
 }
 
@@ -1006,7 +1044,8 @@
 {
 	struct ast_variable *v;
 	struct call_queue *q;
-	struct member *m, *prev_m, *next_m;
+	struct member *m;
+	struct ao2_iterator i;
 	char *interface = NULL;
 	char *tmp, *tmp_name;
 	char tmpbuf[64];	/* Must be longer than the longest queue param name. */
@@ -1085,9 +1124,12 @@
 
 	/* Temporarily set realtime members dead so we can detect deleted ones. 
 	 * Also set the membercount correctly for realtime*/
-	for (m = q->members; m; m = m->next, q->membercount++) {
+	i = ao2_iterator_init(q->members, 0);
+	while ((m = ao2_iterator_next(&i))) {
+		q->membercount++;
 		if (m->realtime)
 			m->dead = 1;
+		ao2_ref(m, -1);
 	}
 
 	while ((interface = ast_category_browse(member_config, interface))) {
@@ -1098,25 +1140,16 @@
 	}
 
 	/* Delete all realtime members that have been deleted in DB. */
-	m = q->members;
-	prev_m = NULL;
-	while (m) {
-		next_m = m->next;
+	i = ao2_iterator_init(q->members, 0);
+	while ((m = ao2_iterator_next(&i))) {
 		if (m->dead) {
-			if (prev_m) {
-				prev_m->next = next_m;
-			} else {
-				q->members = next_m;
-			}
+			ao2_unlink(q->members, m);
 			ast_mutex_unlock(&q->lock);
 			remove_from_interfaces(m->interface);
 			ast_mutex_lock(&q->lock);
 			q->membercount--;
-			free(m);
-		} else {
-			prev_m = m;
-		}
-		m = next_m;
+		}
+		ao2_ref(m, -1);
 	}
 
 	ast_mutex_unlock(&q->lock);
@@ -1146,8 +1179,9 @@
 static void update_realtime_members(struct call_queue *q)
 {
 	struct ast_config *member_config = NULL;
-	struct member *m, *prev_m, *next_m;
+	struct member *m;
 	char *interface = NULL;
+	struct ao2_iterator i;
 
 	member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , NULL);
 	if (!member_config) {
@@ -1160,9 +1194,11 @@
 	ast_mutex_lock(&q->lock);
 	
 	/* Temporarily set realtime  members dead so we can detect deleted ones.*/ 
-	for (m = q->members; m; m = m->next) {
+	i = ao2_iterator_init(q->members, 0);
+	while ((m = ao2_iterator_next(&i))) {
 		if (m->realtime)
 			m->dead = 1;
+		ao2_ref(m, -1);
 	}
 
 	while ((interface = ast_category_browse(member_config, interface))) {
@@ -1173,25 +1209,16 @@
 	}
 
 	/* Delete all realtime members that have been deleted in DB. */
-	m = q->members;
-	prev_m = NULL;
-	while (m) {
-		next_m = m->next;
+	i = ao2_iterator_init(q->members, 0);
+	while ((m = ao2_iterator_next(&i))) {
 		if (m->dead) {
-			if (prev_m) {
-				prev_m->next = next_m;
-			} else {
-				q->members = next_m;
-			}
+			ao2_unlink(q->members, m);
 			ast_mutex_unlock(&q->lock);
 			remove_from_interfaces(m->interface);
 			ast_mutex_lock(&q->lock);
 			q->membercount--;
-			free(m);
-		} else {
-			prev_m = m;
-		}
-		m = next_m;
+		}
+		ao2_ref(m, -1);
 	}
 	ast_mutex_unlock(&q->lock);
 }
@@ -1541,13 +1568,17 @@
 static int update_status(struct call_queue *q, struct member *member, int status)
 {
 	struct member *cur;
+	struct ao2_iterator i;
 
 	/* Since a reload could have taken place, we have to traverse the list to
 		be sure it's still valid */
 	ast_mutex_lock(&q->lock);
-	for (cur = q->members; cur; cur = cur->next) {
-		if (member != cur)
+	i = ao2_iterator_init(q->members, 0);
+	while ((cur = ao2_iterator_next(&i))) {
+		if (member != cur) {
+			ao2_ref(cur, -1);
 			continue;
+		}
 
 		cur->status = status;
 		if (!q->maskmemberstatus) {
@@ -1564,6 +1595,7 @@
 				q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime": "static",
 				cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
 		}
+		ao2_ref(cur, -1);
 	}
 	ast_mutex_unlock(&q->lock);
 	return 0;
@@ -1597,16 +1629,13 @@
 			continue;
 		ast_mutex_lock(&q->lock);
 		if (q->count && q->members) {
-			for (mem = q->members; mem; mem = mem->next) {
-				if (strcmp(mem->interface, member->interface))
-					continue;
-
+			if ((mem = ao2_find(q->members, member->interface, 0))) {
 				ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
 				if (q->weight > rq->weight) {
 					ast_log(LOG_DEBUG, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, q->count, rq->name, rq->weight, rq->count);
 					found = 1;
-					break;
 				}
+				ao2_ref(mem, -1);
 			}
 		}
 		ast_mutex_unlock(&q->lock);
@@ -2199,7 +2228,8 @@
 				ast_log(LOG_DEBUG, "Even though there are %d available members, the strategy is ringall so only the head call is allowed in\n", avl);
 			avl = 1;
 		} else {
-			for (cur = qe->parent->members; cur; cur = cur->next) {
+			struct ao2_iterator i = ao2_iterator_init(qe->parent->members, 0);
+			while ((cur = ao2_iterator_next(&i))) {
 				switch (cur->status) {
 				case AST_DEVICE_NOT_INUSE:
 				case AST_DEVICE_UNKNOWN:
@@ -2207,6 +2237,7 @@
 						avl++;
 					break;
 				}
+				ao2_ref(cur, -1);
 			}
 		}
 
@@ -2294,20 +2325,9 @@
 
 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl)
 {
-	struct member *cur;
-
-	/* Since a reload could have taken place, we have to traverse the list to
-		be sure it's still valid */
 	ast_mutex_lock(&q->lock);
-	cur = q->members;
-	while (cur) {
-		if (member == cur) {
-			time(&cur->lastcall);
-			cur->calls++;
-			break;
-		}
-		cur = cur->next;
-	}
+	time(&member->lastcall);
+	member->calls++;
 	q->callscompleted++;
 	if (callcompletedinsl)
 		q->callscompletedinsl++;
@@ -2405,6 +2425,7 @@
 	char vars[2048];
 	int forwardsallowed = 1;
 	int callcompletedinsl;
+	struct ao2_iterator memi;
 
 	memset(&bridge_config, 0, sizeof(bridge_config));
 	time(&now);
@@ -2452,13 +2473,13 @@
 		ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
 							qe->chan->name);
 	ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
-	cur = qe->parent->members;
 	if (!ast_strlen_zero(qe->announce))
 		announce = qe->announce;
 	if (!ast_strlen_zero(announceoverride))
 		announce = announceoverride;
 
-	for (; cur; cur = cur->next) {
+	memi = ao2_iterator_init(qe->parent->members, 0);
+	while ((cur = ao2_iterator_next(&memi))) {
 		struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
 
 		if (!tmp) {
@@ -2468,7 +2489,7 @@
 			goto out;
 		}
 		tmp->stillgoing = -1;
-		tmp->member = cur;		/* Never directly dereference!  Could change on reload */
+		tmp->member = cur;
 		tmp->oldstatus = cur->status;
 		tmp->lastcall = cur->lastcall;
 		ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
@@ -2484,6 +2505,7 @@
 			if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
 				break;
 		} else {
+			ao2_ref(cur, -1);
 			free(tmp);
 		}
 	}
@@ -2798,13 +2820,16 @@
 static struct member *interface_exists(struct call_queue *q, const char *interface)
 {
 	struct member *mem;
+	struct ao2_iterator i;
 
 	if (!q)
 		return NULL;
 
-	for (mem = q->members; mem; mem = mem->next) {
+	i = ao2_iterator_init(q->members, 0);
+	while ((mem = ao2_iterator_next(&i))) {
 		if (!strcasecmp(interface, mem->interface))
 			return mem;
+		ao2_ref(mem, -1);
 	}
 
 	return NULL;
@@ -2822,19 +2847,25 @@
 	char value[PM_MAX_LEN];
 	int value_len = 0;
 	int res;
+	struct ao2_iterator i;
 
 	memset(value, 0, sizeof(value));
 
 	if (!pm_queue)
 		return;
 
-	for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
-		if (!cur_member->dynamic)
+	i = ao2_iterator_init(pm_queue->members, 0);
+	while ((cur_member = ao2_iterator_next(&i))) {
+		if (!cur_member->dynamic) {
+			ao2_ref(cur_member, -1);
 			continue;
-
-		res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d;%s%s",
-			cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername,
-			cur_member->next ? "|" : "");
+		}
+
+		res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s",
+			value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername);
+
+		ao2_ref(cur_member, -1);
+
 		if (res != strlen(value + value_len)) {
 			ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
 			break;
@@ -2853,7 +2884,7 @@
 static int remove_from_queue(const char *queuename, const char *interface)
 {
 	struct call_queue *q;
-	struct member *last_member, *look;
+	struct member *mem;
 	int res = RES_NOSUCHQUEUE;
 
 	AST_LIST_LOCK(&queues);
@@ -2864,28 +2895,15 @@
 			continue;
 		}
 
-		if ((last_member = interface_exists(q, interface))) {
-			if ((look = q->members) == last_member) {
-				q->members = last_member->next;
-				q->membercount--;
-			} else {
-				while (look != NULL) {
-					if (look->next == last_member) {
-						look->next = last_member->next;
-						q->membercount--;
-						break;
-					} else {
-						look = look->next;
-					}
-				}
-			}
+		if ((mem = ao2_find(q->members, (char *)interface, OBJ_UNLINK))) {
+			q->membercount--;
 			manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
 				"Queue: %s\r\n"
 				"Location: %s\r\n"
 				"MemberName: %s\r\n",
-				q->name, last_member->interface, last_member->membername);
-			free(last_member);
-			
+				q->name, mem->interface, mem->membername);
+			ao2_ref(mem, -1);
+
 			if (queue_persistent_members)
 				dump_queue_members(q);
 			
@@ -2909,7 +2927,7 @@
 static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump)
 {
 	struct call_queue *q;
-	struct member *new_member;
+	struct member *new_member, *old_member;
 	int res = RES_NOSUCHQUEUE;
 
 	/* \note Ensure the appropriate realtime queue is loaded.  Note that this
@@ -2920,12 +2938,11 @@
 	AST_LIST_LOCK(&queues);
 
 	ast_mutex_lock(&q->lock);
-	if (interface_exists(q, interface) == NULL) {
+	if ((old_member = interface_exists(q, interface)) == NULL) {
 		add_to_interfaces(interface);
 		if ((new_member = create_queue_member(interface, membername, penalty, paused))) {
 			new_member->dynamic = 1;
-			new_member->next = q->members;
-			q->members = new_member;
+			ao2_link(q->members, new_member);
 			q->membercount++;
 			manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
 				"Queue: %s\r\n"
@@ -2950,6 +2967,7 @@
 			res = RES_OUTOFMEMORY;
 		}
 	} else {
+		ao2_ref(old_member, -1);
 		res = RES_EXISTS;
 	}
 	ast_mutex_unlock(&q->lock);
@@ -2993,6 +3011,7 @@
 					"MemberName: %s\r\n"
 					"Paused: %d\r\n",
 						q->name, mem->interface, mem->membername, paused);
+				ao2_ref(mem, -1);
 			}
 		}
 		ast_mutex_unlock(&q->lock);
@@ -3635,6 +3654,7 @@
 	struct call_queue *q;
 	struct ast_module_user *lu;
 	struct member *m;
+	struct ao2_iterator i;
 
 	buf[0] = '\0';
 	
@@ -3655,11 +3675,13 @@
 	AST_LIST_UNLOCK(&queues);
 
 	if (q) {
-		for (m = q->members; m; m = m->next) {
+		i = ao2_iterator_init(q->members, 0);
+		while ((m = ao2_iterator_next(&i))) {
 			/* Count the agents who are logged in and presently answering calls */
 			if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
 				count++;
 			}
+			ao2_ref(m, -1);
 		}
 		ast_mutex_unlock(&q->lock);
 	} else
@@ -3733,8 +3755,9 @@
 
 	if (q) {
 		int buflen = 0, count = 0;
-
-		for (m = q->members; m; m = m->next) {
+		struct ao2_iterator i = ao2_iterator_init(q->members, 0);
+
+		while ((m = ao2_iterator_next(&i))) {
 			/* strcat() is always faster than printf() */
 			if (count++) {
 				strncat(buf + buflen, ",", len - buflen - 1);
@@ -3747,6 +3770,7 @@
 				ast_log(LOG_WARNING, "Truncating list\n");
 				break;
 			}
+			ao2_ref(m, -1);
 		}
 		ast_mutex_unlock(&q->lock);
 	} else
@@ -3802,7 +3826,8 @@
 	struct ast_config *cfg;
 	char *cat, *tmp;
 	struct ast_variable *var;
-	struct member *prev, *cur, *newm, *next;
+	struct member *cur, *newm;
+	struct ao2_iterator i;
 	int new;
 	const char *general_val = NULL;
 	char parse[80];
@@ -3862,10 +3887,12 @@
 				/* Re-initialize the queue, and clear statistics */
 				init_queue(q);
 				clear_queue(q);
-				for (cur = q->members; cur; cur = cur->next) {
+				i = ao2_iterator_init(q->members, 0);
+				while ((cur = ao2_iterator_next(&i))) {
 					if (!cur->dynamic) {
 						cur->delme = 1;
 					}
+					ao2_ref(cur, -1);
 				}
 				for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
 					if (!strcasecmp(var->name, "member")) {
@@ -3892,54 +3919,35 @@
 							membername = interface;
 
 						/* Find the old position in the list */
-						for (prev = NULL, cur = q->members; cur; prev = cur, cur = cur->next) {
-							if (!strcmp(cur->interface, interface)) {
-								break;
-							}
-						}
+						cur = ao2_find(q->members, interface, OBJ_UNLINK);
 
 						newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0);
-
-						if (cur) {
-							/* Delete it now */
-							newm->next = cur->next;
-							if (prev) {
-								prev->next = newm;
-							} else {
-								q->members = newm;
-							}
-							free(cur);
-						} else {
+						ao2_link(q->members, newm);
+
+						if (cur)
+							ao2_ref(cur, -1);
+						else {
 							/* Add them to the master int list if necessary */
 							add_to_interfaces(interface);
-							newm->next = q->members;
-							q->members = newm;
+							q->membercount++;
 						}
-						q->membercount++;
 					} else {
 						queue_set_param(q, var->name, var->value, var->lineno, 1);
 					}
 				}
 
 				/* Free remaining members marked as delme */
-				for (prev = NULL, cur = q->members;
-				     cur;
-				     cur = next) {
-					next = cur->next;
-
-					if (!cur->delme) {
-						prev = cur;
+				i = ao2_iterator_init(q->members, 0);
+				while ((cur = ao2_iterator_next(&i))) {
+					if (! cur->delme) {
+						ao2_ref(cur, -1);
 						continue;
 					}
 
-					if (prev)
-						prev->next = next;
-					else
-						q->members = next;
-
 					remove_from_interfaces(cur->interface);
 					q->membercount--;
-					free(cur);
+					ao2_unlink(q->members, cur);
+					ao2_ref(cur, -1);
 				}
 
 				if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
@@ -3962,10 +3970,12 @@
 				ast_log(LOG_DEBUG, "XXX Leaking a little memory :( XXX\n");
 		} else {
 			ast_mutex_lock(&q->lock);
-			for (cur = q->members; cur; cur = cur->next) {
-				if(cur->dynamic)
+			i = ao2_iterator_init(q->members, 0);
+			while ((cur = ao2_iterator_next(&i))) {
+				if (cur->dynamic)
 					q->membercount++;
 				cur->status = ast_device_state(cur->interface);
+				ao2_ref(cur, -1);
 			}
 			ast_mutex_unlock(&q->lock);
 		}
@@ -3987,6 +3997,7 @@
 	size_t max_left;
 	float sl = 0;
 	char *term = manager ? "\r\n" : "\n";
+	struct ao2_iterator i;
 
 	time(&now);
 	if (argc == 2)
@@ -4045,12 +4056,13 @@
 		else
 			ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
 				q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
-		if (q->members) {
+		if (ao2_container_count(q->members)) {
 			if (s)
 				astman_append(s, "   Members: %s", term);
 			else
 				ast_cli(fd, "   Members: %s", term);
-			for (mem = q->members; mem; mem = mem->next) {
+			i = ao2_iterator_init(q->members, 0);
+			while ((mem = ao2_iterator_next(&i))) {
 				max_buf[0] = '\0';
 				max = max_buf;
 				max_left = sizeof(max_buf);
@@ -4072,6 +4084,7 @@
 					astman_append(s, "      %s%s%s", mem->interface, max_buf, term);
 				else
 					ast_cli(fd, "      %s%s%s", mem->interface, max_buf, term);
+				ao2_ref(mem, -1);
 			}
 		} else if (s)
 			astman_append(s, "   No Members%s", term);
@@ -4166,6 +4179,7 @@
 	struct queue_ent *qe;
 	float sl = 0;
 	struct member *mem;
+	struct ao2_iterator i;
 
 	astman_send_ack(s, m, "Queue status will follow");
 	time(&now);
@@ -4194,7 +4208,8 @@
 				q->name, q->maxlen, q->count, q->holdtime, q->callscompleted,
 				q->callsabandoned, q->servicelevel, sl, q->weight, idText);
 			/* List Queue Members */
-			for (mem = q->members; mem; mem = mem->next) {
+			i = ao2_iterator_init(q->members, 0);
+			while ((mem = ao2_iterator_next(&i))) {
 				if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) {
 					astman_append(s, "Event: QueueMember\r\n"
 						"Queue: %s\r\n"
@@ -4210,6 +4225,7 @@
 						q->name, mem->interface, mem->dynamic ? "dynamic" : "static",
 						mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
 				}
+				ao2_ref(mem, -1);
 			}
 			/* List Queue Entries */
 			pos = 1;
@@ -4474,6 +4490,7 @@
 	int which = 0;
 	struct call_queue *q;
 	struct member *m;
+	struct ao2_iterator i;
 
 	/* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
 	if (pos > 5 || pos < 3)
@@ -4488,10 +4505,14 @@
 	if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */
 		AST_LIST_TRAVERSE(&queues, q, list) {
 			ast_mutex_lock(&q->lock);
-			for (m = q->members ; m ; m = m->next) {
+			i = ao2_iterator_init(q->members, 0);
+			while ((m = ao2_iterator_next(&i))) {
 				if (++which > state) {
+					char *tmp;
 					ast_mutex_unlock(&q->lock);
-					return ast_strdup(m->interface);
+					tmp = ast_strdup(m->interface);
+					ao2_ref(m, -1);
+					return tmp;
 				}
 			}
 			ast_mutex_unlock(&q->lock);




More information about the asterisk-commits mailing list