[asterisk-commits] mmichelson: branch mmichelson/queue_refcount r80876 - /team/mmichelson/queue_...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Aug 24 16:57:28 CDT 2007


Author: mmichelson
Date: Fri Aug 24 16:57:28 2007
New Revision: 80876

URL: http://svn.digium.com/view/asterisk?view=rev&rev=80876
Log:
Queues are now implemented using ao2_containers and are refcounted. Small-scale local tests show that this
works, but I'll need to test a LOT more before I think about putting this into a branch.


Modified:
    team/mmichelson/queue_refcount/apps/app_queue.c

Modified: team/mmichelson/queue_refcount/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/team/mmichelson/queue_refcount/apps/app_queue.c?view=diff&rev=80876&r1=80875&r2=80876
==============================================================================
--- team/mmichelson/queue_refcount/apps/app_queue.c (original)
+++ team/mmichelson/queue_refcount/apps/app_queue.c Fri Aug 24 16:57:28 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,
@@ -123,6 +124,8 @@
 #define	RES_EXISTS	(-1)		/* Entry already exists */
 #define	RES_OUTOFMEMORY	(-2)		/* Out of memory */
 #define	RES_NOSUCHQUEUE	(-3)		/* No such queue */
+
+#define MAX_QUEUE_BUCKETS 17
 
 static char *app = "Queue";
 
@@ -398,10 +401,9 @@
 	struct member *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 */
 };
 
-static AST_LIST_HEAD_STATIC(queues, call_queue);
+static ao2_container *queues;
 
 static int set_member_paused(const char *queuename, const char *interface, int paused);
 
@@ -450,6 +452,19 @@
 
 	return -1;
 }
+
+static int queue_hash_cb(const void *obj, const int flags)
+{
+	const struct call_queue *q = obj;
+	return ast_str_hash(q->name);
+}
+
+static int queue_cmp_cb(void *obj, void *arg, int flags)
+{
+	struct call_queue *q = obj, *q2 = arg;
+	return !strcasecmp(q->name, q2->name) ? CMP_MATCH : 0;
+}
+
 
 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
@@ -519,6 +534,7 @@
 	struct member_interface *curint;
 	char *loc;
 	char *technology;
+	ao2_iterator i;
 
 	technology = ast_strdupa(sc->dev);
 	loc = strchr(technology, '/');
@@ -552,8 +568,8 @@
 
 	if (option_debug)
 		ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
-	AST_LIST_LOCK(&queues);
-	AST_LIST_TRAVERSE(&queues, q, list) {
+	i = ao2_iterator_init(queues, 0);
+	while((q = ao2_iterator_next(&i))) {
 		ast_mutex_lock(&q->lock);
 		for (cur = q->members; cur; cur = cur->next) {
 			char *interface;
@@ -563,13 +579,17 @@
 				if ((slash_pos = strchr(slash_pos + 1, '/')))
 					*slash_pos = '\0';
 
-			if (strcasecmp(sc->dev, interface))
+			if (strcasecmp(sc->dev, interface)) {
+				ao2_ref(q, -1);
 				continue;
+			}
 
 			if (cur->status != sc->state) {
 				cur->status = sc->state;
-				if (q->maskmemberstatus)
+				if (q->maskmemberstatus) {
+					ao2_ref(q, -1);
 					continue;
+				}
 
 				manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
 					"Queue: %s\r\n"
@@ -586,8 +606,8 @@
 			}
 		}
 		ast_mutex_unlock(&q->lock);
-	}
-	AST_LIST_UNLOCK(&queues);
+		ao2_ref(q, -1);
+	}
 
 	free(sc);
 
@@ -633,17 +653,6 @@
 	}
 
 	return cur;
-}
-
-static struct call_queue *alloc_queue(const char *queuename)
-{
-	struct call_queue *q;
-
-	if ((q = ast_calloc(1, sizeof(*q)))) {
-		ast_mutex_init(&q->lock);
-		ast_copy_string(q->name, queuename, sizeof(q->name));
-	}
-	return q;
 }
 
 static void init_queue(struct call_queue *q)
@@ -724,19 +733,22 @@
 	struct call_queue *q;
 	struct member *mem;
 	int ret = 0;
-
-	AST_LIST_LOCK(&queues);
-	AST_LIST_TRAVERSE(&queues, q, list) {
+	ao2_iterator i;
+
+	i = ao2_iterator_init(queues, 0);
+	while((q = ao2_iterator_next(&i))) {
 		ast_mutex_lock(&q->lock);
 		for (mem = q->members; mem && !ret; mem = mem->next) {
 			if (!strcasecmp(interface, mem->interface))
 				ret = 1;
 		}
 		ast_mutex_unlock(&q->lock);
-		if (ret)
+		if (ret) {
+			ao2_ref(q, -1);
 			break;
-	}
-	AST_LIST_UNLOCK(&queues);
+		}
+		ao2_ref(q, -1);
+	}
 
 	return ret;
 }
@@ -990,11 +1002,22 @@
 	}
 }
 
-static void destroy_queue(struct call_queue *q)
-{
+static void destroy_queue(void *obj)
+{
+	struct call_queue *q = obj;
 	free_members(q, 1);
 	ast_mutex_destroy(&q->lock);
-	free(q);
+}
+
+static struct call_queue *alloc_queue(const char *queuename)
+{
+	struct call_queue *q;
+
+	if ((q = ao2_alloc(sizeof(*q), destroy_queue))) {
+		ast_mutex_init(&q->lock);
+		ast_copy_string(q->name, queuename, sizeof(q->name));
+	}
+	return q;
 }
 
 /*!\brief Reload a single queue via realtime.
@@ -1003,17 +1026,18 @@
 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
 {
 	struct ast_variable *v;
-	struct call_queue *q;
+	struct call_queue *q = NULL;
+	struct call_queue tmpq;
 	struct member *m, *prev_m, *next_m;
 	char *interface = NULL;
 	char *tmp, *tmp_name;
 	char tmpbuf[64];	/* Must be longer than the longest queue param name. */
 
+	ast_copy_string(tmpq.name, queuename, sizeof(tmpq.name));
+
 	/* Find the queue in the in-core list (we will create a new one if not found). */
-	AST_LIST_TRAVERSE(&queues, q, list) {
-		if (!strcasecmp(q->name, queuename))
-			break;
-	}
+
+	q = ao2_find(queues, &tmpq, OBJ_POINTER);
 
 	/* Static queues override realtime. */
 	if (q) {
@@ -1021,6 +1045,7 @@
 		if (!q->realtime) {
 			if (q->dead) {
 				ast_mutex_unlock(&q->lock);
+				ao2_ref(q, -1);
 				return NULL;
 			} else {
 				ast_mutex_unlock(&q->lock);
@@ -1044,9 +1069,12 @@
 			/* Delete if unused (else will be deleted when last caller leaves). */
 			if (!q->count) {
 				/* Delete. */
-				AST_LIST_REMOVE(&queues, q, list);
 				ast_mutex_unlock(&q->lock);
-				destroy_queue(q);
+				usleep(1);
+				ast_mutex_lock(&q->lock);
+				ast_mutex_unlock(&q->lock);
+				ao2_unlink(queues, q);
+				ao2_ref(q, -1);
 			} else
 				ast_mutex_unlock(&q->lock);
 		}
@@ -1060,7 +1088,7 @@
 		ast_mutex_lock(&q->lock);
 		clear_queue(q);
 		q->realtime = 1;
-		AST_LIST_INSERT_HEAD(&queues, q, list);
+		ao2_link(queues, q);
 	}
 	init_queue(q);		/* Ensure defaults for all parameters not set explicitly. */
 
@@ -1175,16 +1203,13 @@
 {
 	struct ast_variable *queue_vars;
 	struct ast_config *member_config = NULL;
-	struct call_queue *q;
+	struct call_queue tmpq;
+	struct call_queue *q = NULL;
+
+	ast_copy_string(tmpq.name, queuename, sizeof(tmpq.name));
 
 	/* Find the queue in the in-core list first. */
-	AST_LIST_LOCK(&queues);
-	AST_LIST_TRAVERSE(&queues, q, list) {
-		if (!strcasecmp(q->name, queuename)) {
-			break;
-		}
-	}
-	AST_LIST_UNLOCK(&queues);
+	q = ao2_find(queues, &tmpq, OBJ_POINTER);
 
 	if (!q || q->realtime) {
 		/*! \note Load from realtime before taking the global qlock, to avoid blocking all
@@ -1205,15 +1230,12 @@
 			}
 		}
 
-		AST_LIST_LOCK(&queues);
-
 		q = find_queue_by_name_rt(queuename, queue_vars, member_config);
 		if (member_config)
 			ast_config_destroy(member_config);
 		if (queue_vars)
 			ast_variables_destroy(queue_vars);
 
-		AST_LIST_UNLOCK(&queues);
 	} else { 
 		update_realtime_members(q);
 	}
@@ -1232,7 +1254,7 @@
 	if (!(q = load_realtime_queue(queuename)))
 		return res;
 
-	AST_LIST_LOCK(&queues);
+	ao2_lock(queues);
 	ast_mutex_lock(&q->lock);
 
 	/* This is our one */
@@ -1280,7 +1302,7 @@
 			ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
 	}
 	ast_mutex_unlock(&q->lock);
-	AST_LIST_UNLOCK(&queues);
+	ao2_unlock(queues);
 
 	return res;
 }
@@ -1463,6 +1485,7 @@
 
 	if (!(q = qe->parent))
 		return;
+	ao2_ref(q, 1);
 	ast_mutex_lock(&q->lock);
 
 	prev = NULL;
@@ -1491,10 +1514,8 @@
 
 	if (q->dead && !q->count) {	
 		/* It's dead and nobody is in it, so kill it */
-		AST_LIST_LOCK(&queues);
-		AST_LIST_REMOVE(&queues, q, list);
-		AST_LIST_UNLOCK(&queues);
-		destroy_queue(q);
+		ao2_unlink(queues, q);
+		ao2_ref(q, -1);
 	}
 }
 
@@ -1564,29 +1585,39 @@
 	struct call_queue *q;
 	struct member *mem;
 	int found = 0;
+	ao2_iterator i;
 	
 	/* &qlock and &rq->lock already set by try_calling()
 	 * to solve deadlock */
-	AST_LIST_TRAVERSE(&queues, q, list) {
-		if (q == rq) /* don't check myself, could deadlock */
+	i = ao2_iterator_init(queues, 0);
+	while ((q = ao2_iterator_next(&i))) {
+		if (q == rq) { /* don't check myself, could deadlock */
+			ao2_ref(q, -1);
 			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))
+				if (strcmp(mem->interface, member->interface)) {
+					ao2_ref(q, -1);
 					continue;
+				}
 
 				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;
+					ao2_ref(q, -1);
 					break;
 				}
 			}
 		}
 		ast_mutex_unlock(&q->lock);
-		if (found)
+		if (found) {
+			ao2_ref(q, -1);
 			break;
+		}
+		ao2_ref(q, -1);
 	}
 	return found;
 }
@@ -2421,7 +2452,7 @@
 
 	/* Hold the lock while we setup the outgoing calls */
 	if (use_weight)
-		AST_LIST_LOCK(&queues);
+		ao2_lock(queues);
 	ast_mutex_lock(&qe->parent->lock);
 	if (option_debug)
 		ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
@@ -2439,7 +2470,7 @@
 		if (!tmp) {
 			ast_mutex_unlock(&qe->parent->lock);
 			if (use_weight)
-				AST_LIST_UNLOCK(&queues);
+				ao2_unlock(queues);
 			goto out;
 		}
 		tmp->stillgoing = -1;
@@ -2469,7 +2500,7 @@
 	ring_one(qe, outgoing, &numbusies);
 	ast_mutex_unlock(&qe->parent->lock);
 	if (use_weight)
-		AST_LIST_UNLOCK(&queues);
+		ao2_unlock(queues);
 	lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
 	ast_mutex_lock(&qe->parent->lock);
 	if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
@@ -2828,54 +2859,50 @@
 static int remove_from_queue(const char *queuename, const char *interface)
 {
 	struct call_queue *q;
+	struct call_queue tmpq;
 	struct member *last_member, *look;
 	int res = RES_NOSUCHQUEUE;
 
-	AST_LIST_LOCK(&queues);
-	AST_LIST_TRAVERSE(&queues, q, list) {
-		ast_mutex_lock(&q->lock);
-		if (strcmp(q->name, queuename)) {
-			ast_mutex_unlock(&q->lock);
-			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;
-					}
+	ast_copy_string(tmpq.name, queuename, sizeof(tmpq.name));
+
+	q = ao2_find(queues, &tmpq, OBJ_POINTER);
+	ast_mutex_lock(&q->lock);
+
+	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;
 				}
 			}
-			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);
-			
-			if (queue_persistent_members)
-				dump_queue_members(q);
-			
-			res = RES_OKAY;
-		} else {
-			res = RES_EXISTS;
-		}
-		ast_mutex_unlock(&q->lock);
-		break;
-	}
+		}
+		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);
+		
+		if (queue_persistent_members)
+			dump_queue_members(q);
+		
+		res = RES_OKAY;
+	} else {
+		res = RES_EXISTS;
+	}
+	ast_mutex_unlock(&q->lock);
+	ao2_ref(q, -1);
 
 	if (res == RES_OKAY)
 		remove_from_interfaces(interface);
 
-	AST_LIST_UNLOCK(&queues);
 
 	return res;
 }
@@ -2892,8 +2919,7 @@
 	if (!(q = load_realtime_queue(queuename)))
 		return res;
 
-	AST_LIST_LOCK(&queues);
-
+	ao2_lock(queues);
 	ast_mutex_lock(&q->lock);
 	if (interface_exists(q, interface) == NULL) {
 		add_to_interfaces(interface);
@@ -2928,7 +2954,7 @@
 		res = RES_EXISTS;
 	}
 	ast_mutex_unlock(&q->lock);
-	AST_LIST_UNLOCK(&queues);
+	ao2_unlock(queues);
 
 	return res;
 }
@@ -2938,14 +2964,15 @@
 	int found = 0;
 	struct call_queue *q;
 	struct member *mem;
+	ao2_iterator i;
 
 	/* Special event for when all queues are paused - individual events still generated */
 	/* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
 	if (ast_strlen_zero(queuename))
 		ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
 
-	AST_LIST_LOCK(&queues);
-	AST_LIST_TRAVERSE(&queues, q, list) {
+	i = ao2_iterator_init(queues, 0);
+	while ((q = ao2_iterator_next(&i))) {
 		ast_mutex_lock(&q->lock);
 		if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
 			if ((mem = interface_exists(q, interface))) {
@@ -2968,8 +2995,8 @@
 			}
 		}
 		ast_mutex_unlock(&q->lock);
-	}
-	AST_LIST_UNLOCK(&queues);
+		ao2_ref(q, -1);
+	}
 
 	return found ? RESULT_SUCCESS : RESULT_FAILURE;
 }
@@ -2989,22 +3016,18 @@
 	struct ast_db_entry *db_tree;
 	struct ast_db_entry *entry;
 	struct call_queue *cur_queue;
+	struct call_queue tmpq;
 	char queue_data[PM_MAX_LEN];
 
-	AST_LIST_LOCK(&queues);
-
+	ao2_lock(queues);
 	/* Each key in 'pm_family' is the name of a queue */
 	db_tree = ast_db_gettree(pm_family, NULL);
 	for (entry = db_tree; entry; entry = entry->next) {
 
 		queue_name = entry->key + strlen(pm_family) + 2;
-
-		AST_LIST_TRAVERSE(&queues, cur_queue, list) {
-			ast_mutex_lock(&cur_queue->lock);
-			if (!strcmp(queue_name, cur_queue->name))
-				break;
-			ast_mutex_unlock(&cur_queue->lock);
-		}
+		ast_copy_string(tmpq.name, queue_name, sizeof(tmpq.name));
+
+		cur_queue = ao2_find(queues, &tmpq, OBJ_POINTER);
 		
 		if (!cur_queue)
 			cur_queue = load_realtime_queue(queue_name);
@@ -3015,8 +3038,7 @@
 			ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
 			ast_db_del(pm_family, queue_name);
 			continue;
-		} else
-			ast_mutex_unlock(&cur_queue->lock);
+		} 
 
 		if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
 			continue;
@@ -3063,7 +3085,7 @@
 		}
 	}
 
-	AST_LIST_UNLOCK(&queues);
+	ao2_unlock(queues);
 	if (db_tree) {
 		ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
 		ast_db_freetree(db_tree);
@@ -3596,6 +3618,9 @@
 		set_queue_result(chan, reason);
 		res = 0;
 	}
+
+	if(qe.parent)
+		ao2_ref(qe.parent, -1);
 	ast_module_user_remove(lu);
 
 	return res;
@@ -3605,6 +3630,7 @@
 {
 	int count = 0;
 	struct call_queue *q;
+	struct call_queue tmpq;
 	struct ast_module_user *lu;
 
 	buf[0] = '\0';
@@ -3614,20 +3640,16 @@
 		return -1;
 	}
 
+	ast_copy_string(tmpq.name, data, sizeof(tmpq.name));
+
 	lu = ast_module_user_add(chan);
 	
-	AST_LIST_LOCK(&queues);
-	AST_LIST_TRAVERSE(&queues, q, list) {
-		if (!strcasecmp(q->name, data)) {
-			ast_mutex_lock(&q->lock);
-			break;
-		}
-	}
-	AST_LIST_UNLOCK(&queues);
+	q = ao2_find(queues, &tmpq, OBJ_POINTER);
 
 	if (q) {
 		count = q->membercount;
 		ast_mutex_unlock(&q->lock);
+		ao2_ref(q, -1);
 	} else
 		ast_log(LOG_WARNING, "queue %s was not found\n", data);
 
@@ -3641,6 +3663,7 @@
 {
 	int count = 0;
 	struct call_queue *q;
+	struct call_queue tmpq;
 	struct ast_module_user *lu;
 
 	buf[0] = '\0';
@@ -3650,20 +3673,16 @@
 		return -1;
 	}
 
+	ast_copy_string(tmpq.name, data, sizeof(tmpq.name));
+
 	lu = ast_module_user_add(chan);
 	
-	AST_LIST_LOCK(&queues);
-	AST_LIST_TRAVERSE(&queues, q, list) {
-		if (!strcasecmp(q->name, data)) {
-			ast_mutex_lock(&q->lock);
-			break;
-		}
-	}
-	AST_LIST_UNLOCK(&queues);
+	q = ao2_find(queues, &tmpq, OBJ_POINTER);
 
 	if (q) {
 		count = q->count;
 		ast_mutex_unlock(&q->lock);
+		ao2_ref(q, -1);
 	} else
 		ast_log(LOG_WARNING, "queue %s was not found\n", data);
 
@@ -3676,6 +3695,7 @@
 {
 	struct ast_module_user *u;
 	struct call_queue *q;
+	struct call_queue tmpq;
 	struct member *m;
 
 	/* Ensure an otherwise empty list doesn't return garbage */
@@ -3685,17 +3705,11 @@
 		ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
 		return -1;
 	}
-	
+
+	ast_copy_string(tmpq.name, data, sizeof(tmpq.name));
 	u = ast_module_user_add(chan);
 
-	AST_LIST_LOCK(&queues);
-	AST_LIST_TRAVERSE(&queues, q, list) {
-		if (!strcasecmp(q->name, data)) {
-			ast_mutex_lock(&q->lock);
-			break;
-		}
-	}
-	AST_LIST_UNLOCK(&queues);
+	q = ao2_find(queues, &tmpq, OBJ_POINTER);
 
 	if (q) {
 		int buflen = 0, count = 0;
@@ -3715,6 +3729,7 @@
 			}
 		}
 		ast_mutex_unlock(&q->lock);
+		ao2_ref(q, -1);
 	} else
 		ast_log(LOG_WARNING, "queue %s was not found\n", data);
 
@@ -3765,6 +3780,7 @@
 static int reload_queues(void)
 {
 	struct call_queue *q;
+	struct call_queue tmpq;
 	struct ast_config *cfg;
 	char *cat, *tmp;
 	struct ast_variable *var;
@@ -3775,6 +3791,7 @@
 	char *interface;
 	char *membername;
 	int penalty;
+	ao2_iterator i;
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(interface);
 		AST_APP_ARG(penalty);
@@ -3785,11 +3802,13 @@
 		ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
 		return 0;
 	}
-	AST_LIST_LOCK(&queues);
 	use_weight=0;
 	/* Mark all queues as dead for the moment */
-	AST_LIST_TRAVERSE(&queues, q, list)
+	i = ao2_iterator_init(queues, 0);
+	while((q = ao2_iterator_next(&i))) {
 		q->dead = 1;
+		ao2_ref(q, -1);
+	}
 
 	/* Chug through config file */
 	cat = NULL;
@@ -3808,10 +3827,8 @@
 					montype_default = 1;
 		} else {	/* Define queue */
 			/* Look for an existing one */
-			AST_LIST_TRAVERSE(&queues, q, list) {
-				if (!strcmp(q->name, cat))
-					break;
-			}
+			ast_copy_string(tmpq.name, cat, sizeof(tmpq.name));
+			q = ao2_find(queues, &tmpq, OBJ_POINTER);
 			if (!q) {
 				/* Make one then */
 				if (!(q = alloc_queue(cat))) {
@@ -3910,18 +3927,20 @@
 					rr_dep_warning();
 
 				if (new) {
-					AST_LIST_INSERT_HEAD(&queues, q, list);
+					ao2_link(queues, q);
 				} else
 					ast_mutex_unlock(&q->lock);
 			}
 		}
 	}
 	ast_config_destroy(cfg);
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) {
+	i = ao2_iterator_init(queues,0);
+	while ((q = ao2_iterator_next(&i))) {
 		if (q->dead) {
-			AST_LIST_REMOVE_CURRENT(&queues, list);
-			if (!q->count)
-				destroy_queue(q);
+			ao2_unlink(queues, q);
+			if (!q->count) {
+				ao2_ref(q, -1);
+			}
 			else
 				ast_log(LOG_DEBUG, "XXX Leaking a little memory :( XXX\n");
 		} else {
@@ -3930,26 +3949,102 @@
 				cur->status = ast_device_state(cur->interface);
 			ast_mutex_unlock(&q->lock);
 		}
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-	AST_LIST_UNLOCK(&queues);
+		ao2_ref(q, -1);
+	}
 	return 1;
 }
 
-static int __queues_show(struct mansession *s, int manager, int fd, int argc, char **argv)
-{
-	struct call_queue *q;
-	struct queue_ent *qe;
-	struct member *mem;
-	int pos, queue_show;
-	time_t now;
+static void show(struct call_queue *q, int fd, char **argv, struct mansession *s, char *term)
+{
 	char max_buf[80];
 	char *max;
 	size_t max_left;
-	float sl = 0;
+	float sl;
+	time_t now;
+	struct queue_ent *qe;
+	struct member *mem;
+	int pos;
+
+	max_buf[0] = '\0';
+	max = max_buf;
+	max_left = sizeof(max_buf);
+	if (q->maxlen)
+		ast_build_string(&max, &max_left, "%d", q->maxlen);
+	else
+		ast_build_string(&max, &max_left, "unlimited");
+	sl = 0;
+	if (q->callscompleted > 0)
+		sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
+	if (s)
+		astman_append(s, "%-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);
+	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 (s)
+			astman_append(s, "   Members: %s", term);
+		else
+			ast_cli(fd, "   Members: %s", term);
+		for (mem = q->members; mem; mem = mem->next) {
+			max_buf[0] = '\0';
+			max = max_buf;
+			max_left = sizeof(max_buf);
+			if (mem->penalty)
+				ast_build_string(&max, &max_left, " with penalty %d", mem->penalty);
+			if (mem->dynamic)
+				ast_build_string(&max, &max_left, " (dynamic)");
+			if (mem->paused)
+				ast_build_string(&max, &max_left, " (paused)");
+			ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status));
+			if (mem->calls) {
+				ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)",
+					mem->calls, (long) (time(NULL) - mem->lastcall));
+			} else
+				ast_build_string(&max, &max_left, " has taken no calls yet");
+			if (s)
+				astman_append(s, "      %s%s%s", mem->interface, max_buf, term);
+			else
+				ast_cli(fd, "      %s%s%s", mem->interface, max_buf, term);
+		}
+	} else if (s)
+		astman_append(s, "   No Members%s", term);
+	else	
+		ast_cli(fd, "   No Members%s", term);
+	if (q->head) {
+		pos = 1;
+		if (s)
+			astman_append(s, "   Callers: %s", term);
+		else
+			ast_cli(fd, "   Callers: %s", term);
+		for (qe = q->head; qe; qe = qe->next) {
+			if (s)
+				astman_append(s, "      %d. %s (wait: %ld:%2.2ld, prio: %d)%s",
+					pos++, qe->chan->name, (long) (now - qe->start) / 60,
+					(long) (now - qe->start) % 60, qe->prio, term);
+			else
+				ast_cli(fd, "      %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++,
+					qe->chan->name, (long) (now - qe->start) / 60,
+					(long) (now - qe->start) % 60, qe->prio, term);
+		}
+	} else if (s)
+		astman_append(s, "   No Callers%s", term);
+	else
+		ast_cli(fd, "   No Callers%s", term);
+	if (s)
+		astman_append(s, "%s", term);
+	else
+		ast_cli(fd, "%s", term);
+}
+
+static int __queues_show(struct mansession *s, int manager, int fd, int argc, char **argv)
+{
+	struct call_queue *q;
+	int queue_show;
 	char *term = manager ? "\r\n" : "\n";
-
-	time(&now);
+	ao2_iterator i;
+
 	if (argc == 2)
 		queue_show = 0;
 	else if (argc == 3)
@@ -3961,9 +4056,9 @@
 	if (queue_show)
 		load_realtime_queue(argv[2]);
 
-	AST_LIST_LOCK(&queues);
-	if (AST_LIST_EMPTY(&queues)) {
-		AST_LIST_UNLOCK(&queues);
+	ao2_lock(queues);
+	if (!ao2_container_count(queues)) {
+		ao2_unlock(queues);
 		if (queue_show) {
 			if (s)
 				astman_append(s, "No such queue: %s.%s",argv[2], term);
@@ -3977,94 +4072,26 @@
 		}
 		return RESULT_SUCCESS;
 	}
-	AST_LIST_TRAVERSE(&queues, q, list) {
-		ast_mutex_lock(&q->lock);
-		if (queue_show) {
-			if (strcasecmp(q->name, argv[2]) != 0) {
-				ast_mutex_unlock(&q->lock);
-				if (!AST_LIST_NEXT(q, list)) {
-					ast_cli(fd, "No such queue: %s.%s",argv[2], term);
-					break;
-				}
-				continue;
-			}
-		}
-		max_buf[0] = '\0';
-		max = max_buf;
-		max_left = sizeof(max_buf);
-		if (q->maxlen)
-			ast_build_string(&max, &max_left, "%d", q->maxlen);
-		else
-			ast_build_string(&max, &max_left, "unlimited");
-		sl = 0;
-		if (q->callscompleted > 0)
-			sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
-		if (s)
-			astman_append(s, "%-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);
-		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 (s)
-				astman_append(s, "   Members: %s", term);
-			else
-				ast_cli(fd, "   Members: %s", term);
-			for (mem = q->members; mem; mem = mem->next) {
-				max_buf[0] = '\0';
-				max = max_buf;
-				max_left = sizeof(max_buf);
-				if (mem->penalty)
-					ast_build_string(&max, &max_left, " with penalty %d", mem->penalty);
-				if (mem->dynamic)
-					ast_build_string(&max, &max_left, " (dynamic)");
-				if (mem->paused)
-					ast_build_string(&max, &max_left, " (paused)");
-				ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status));
-				if (mem->calls) {
-					ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)",
-						mem->calls, (long) (time(NULL) - mem->lastcall));
-				} else
-					ast_build_string(&max, &max_left, " has taken no calls yet");
-				if (s)
-					astman_append(s, "      %s%s%s", mem->interface, max_buf, term);
-				else
-					ast_cli(fd, "      %s%s%s", mem->interface, max_buf, term);
-			}
-		} else if (s)
-			astman_append(s, "   No Members%s", term);
-		else	
-			ast_cli(fd, "   No Members%s", term);
-		if (q->head) {
-			pos = 1;
-			if (s)
-				astman_append(s, "   Callers: %s", term);
-			else
-				ast_cli(fd, "   Callers: %s", term);
-			for (qe = q->head; qe; qe = qe->next) {
-				if (s)
-					astman_append(s, "      %d. %s (wait: %ld:%2.2ld, prio: %d)%s",
-						pos++, qe->chan->name, (long) (now - qe->start) / 60,
-						(long) (now - qe->start) % 60, qe->prio, term);
-				else
-					ast_cli(fd, "      %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++,
-						qe->chan->name, (long) (now - qe->start) / 60,
-						(long) (now - qe->start) % 60, qe->prio, term);
-			}
-		} else if (s)
-			astman_append(s, "   No Callers%s", term);
-		else
-			ast_cli(fd, "   No Callers%s", term);
-		if (s)
-			astman_append(s, "%s", term);
-		else
-			ast_cli(fd, "%s", term);
-		ast_mutex_unlock(&q->lock);
-		if (queue_show)
-			break;
-	}
-	AST_LIST_UNLOCK(&queues);
+	ao2_unlock(queues);
+
+	if(queue_show) {
+		struct call_queue tmpq;
+		ast_copy_string(tmpq.name, argv[2], sizeof(tmpq.name));
+		if(!(q = ao2_find(queues, &tmpq, OBJ_POINTER))) 
+			ast_cli(fd, "No such queue: %s.%s", argv[2], term);
+		else {
+			show(q, fd, argv, s, term);
+			ao2_ref(q, -1);
+		}
+	} else {
+		i = ao2_iterator_init(queues, 0);
+		while ((q = ao2_iterator_next(&i))) {
+			ast_mutex_lock(&q->lock);
+			show(q, fd, argv, s, term);
+			ast_mutex_unlock(&q->lock);
+			ao2_ref(q, -1);
+		}
+	}
 	return RESULT_SUCCESS;
 }
 
@@ -4079,15 +4106,17 @@
 	char *ret = NULL;
 	int which = 0;
 	int wordlen = strlen(word);
+	ao2_iterator i;
 	
-	AST_LIST_LOCK(&queues);
-	AST_LIST_TRAVERSE(&queues, q, list) {
+	i = ao2_iterator_init(queues, 0);
+	while((q = ao2_iterator_next(&i))) {
 		if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
-			ret = ast_strdup(q->name);	
+			ret = ast_strdup(q->name);
+			ao2_ref(q, -1);
 			break;
 		}
-	}
-	AST_LIST_UNLOCK(&queues);
+		ao2_ref(q, -1);
+	}
 
 	return ret;
 }
@@ -4125,14 +4154,15 @@
 	struct queue_ent *qe;
 	float sl = 0;
 	struct member *mem;
+	ao2_iterator i;
 
 	astman_send_ack(s, m, "Queue status will follow");
 	time(&now);
-	AST_LIST_LOCK(&queues);
 	if (!ast_strlen_zero(id))
 		snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
 
-	AST_LIST_TRAVERSE(&queues, q, list) {
+	i = ao2_iterator_init(queues,0);
+	while((q = ao2_iterator_next(&i))) {
 		ast_mutex_lock(&q->lock);
 
 		/* List queue properties */
@@ -4189,6 +4219,7 @@
 			}
 		}
 		ast_mutex_unlock(&q->lock);
+		ao2_ref(q, -1);
 	}
 
 	astman_append(s,
@@ -4196,7 +4227,6 @@
 		"%s"
 		"\r\n",idText);
 
-	AST_LIST_UNLOCK(&queues);
 
 
 	return RESULT_SUCCESS;
@@ -4433,6 +4463,7 @@
 	int which = 0;
 	struct call_queue *q;
 	struct member *m;
+	ao2_iterator i;
 
 	/* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
 	if (pos > 5 || pos < 3)
@@ -4444,17 +4475,18 @@
 		return complete_queue(line, word, pos, state);
 
 	/* here is the case for 3, <member> */
-	if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */
-		AST_LIST_TRAVERSE(&queues, q, list) {
-			ast_mutex_lock(&q->lock);
-			for (m = q->members ; m ; m = m->next) {
-				if (++which > state) {
-					ast_mutex_unlock(&q->lock);
-					return ast_strdup(m->interface);
-				}
-			}
-			ast_mutex_unlock(&q->lock);
-		}
+	i = ao2_iterator_init(queues, 0);
+	while((q = ao2_iterator_next(&i))) {
+		ast_mutex_lock(&q->lock);
+		for (m = q->members ; m ; m = m->next) {
+			if (++which > state) {
+				ast_mutex_unlock(&q->lock);
+				ao2_ref(q, -1);
+				return ast_strdup(m->interface);
+			}
+		}
+		ast_mutex_unlock(&q->lock);
+		ao2_ref(q, -1);
 	}
 
 	return NULL;
@@ -4531,12 +4563,15 @@
 
 	clear_and_free_interfaces();
 
+	ao2_ref(queues, -1);
+
 	return res;
 }
 
 static int load_module(void)
 {
 	int res;
+	queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
 	if(!reload_queues())
 		return AST_MODULE_LOAD_DECLINE;
 	if (queue_persistent_members)




More information about the asterisk-commits mailing list