[asterisk-commits] mmichelson: branch mmichelson/queue_refcount_trunk r82255 - /team/mmichelson/...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Sep 11 11:30:09 CDT 2007


Author: mmichelson
Date: Tue Sep 11 11:30:09 2007
New Revision: 82255

URL: http://svn.digium.com/view/asterisk?view=rev&rev=82255
Log:
Trunk version of refcounted queues.


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

Modified: team/mmichelson/queue_refcount_trunk/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/team/mmichelson/queue_refcount_trunk/apps/app_queue.c?view=diff&rev=82255&r1=82254&r2=82255
==============================================================================
--- team/mmichelson/queue_refcount_trunk/apps/app_queue.c (original)
+++ team/mmichelson/queue_refcount_trunk/apps/app_queue.c Tue Sep 11 11:30:09 2007
@@ -120,6 +120,7 @@
 #define MAX_PERIODIC_ANNOUNCEMENTS 10 /* The maximum periodic announcements we can have */
 #define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 /* The minimum number of seconds between position announcements
                                              The default value of 15 provides backwards compatibility */
+#define MAX_QUEUE_BUCKETS 53
 
 #define	RES_OKAY	0		/* Action completed */
 #define	RES_EXISTS	(-1)		/* Entry already exists */
@@ -413,7 +414,7 @@
 	AST_LIST_ENTRY(call_queue) list;    /*!< Next call queue */
 };
 
-static AST_LIST_HEAD_STATIC(queues, call_queue);
+static struct ao2_container *queues;
 
 static void update_realtime_members(struct call_queue *q);
 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
@@ -452,6 +453,30 @@
 	}
 
 	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;
+}
+
+static inline struct call_queue *queue_ref(struct call_queue *q)
+{
+	ao2_ref(q, 1);
+	return q;
+}
+
+static inline struct call_queue *queue_unref(struct call_queue *q)
+{
+	ao2_ref(q, -1);
+	return q;
 }
 
 static void set_queue_variables(struct queue_ent *qe)
@@ -554,6 +579,7 @@
 	struct member *cur;
 	struct ao2_iterator i;
 	struct member_interface *curint;
+	struct ao2_iterator queue_iter;
 	char *loc;
 	char *technology;
 
@@ -585,8 +611,8 @@
 	}
 
 	ast_debug(1, "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) {
+	queue_iter = ao2_iterator_init(queues, 0);
+	while ((q = ao2_iterator_next(&queue_iter))) {
 		ast_mutex_lock(&q->lock);
 		i = ao2_iterator_init(q->members, 0);
 		while ((cur = ao2_iterator_next(&i))) {
@@ -624,9 +650,9 @@
 			}
 			ao2_ref(cur, -1);
 		}
+		queue_unref(q);
 		ast_mutex_unlock(&q->lock);
 	}
-	AST_LIST_UNLOCK(&queues);
 
 	return NULL;
 }
@@ -727,16 +753,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 int compress_char(const char c)
 {
@@ -849,20 +865,23 @@
 {
 	struct call_queue *q;
 	struct member *mem;
+	struct ao2_iterator queue_iter;
 	int ret = 0;
 
-	AST_LIST_LOCK(&queues);
-	AST_LIST_TRAVERSE(&queues, q, list) {
+	queue_iter = ao2_iterator_init(queues, 0);
+	while ((q = ao2_iterator_next(&queue_iter))) {
 		ast_mutex_lock(&q->lock);
 		if ((mem = ao2_find(q->members, (char *)interface, 0))) {
 			ao2_ref(mem, -1);
 			ret = 1;
 		}
 		ast_mutex_unlock(&q->lock);
-		if (ret)
+		if (ret) {
+			queue_unref(q);
 			break;
-	}
-	AST_LIST_UNLOCK(&queues);
+		}
+		queue_unref(q);
+	}
 
 	return ret;
 }
@@ -1126,12 +1145,24 @@
 	}
 }
 
-static void destroy_queue(struct call_queue *q)
-{
+static void destroy_queue(void *obj)
+{
+	struct call_queue *q = obj;
+	ast_debug(0, "Queue destructor called for queue '%s'!\n", q->name);
 	free_members(q, 1);
 	ast_mutex_destroy(&q->lock);
 	ao2_ref(q->members, -1);
-	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.
@@ -1141,24 +1172,27 @@
 {
 	struct ast_variable *v;
 	struct call_queue *q;
+<<<<<<< .mine
+	struct call_queue tmpq;
+	struct member *m, *prev_m, *next_m;
+=======
 	struct member *m;
 	struct ao2_iterator i;
+>>>>>>> .r82248
 	char *interface = NULL;
 	char *tmp, *tmp_name;
 	char tmpbuf[64];	/* Must be longer than the longest queue param 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;
-	}
+	ast_copy_string(tmpq.name, queuename, sizeof(tmpq.name));
 
 	/* Static queues override realtime. */
-	if (q) {
+	if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
 		ast_mutex_lock(&q->lock);
 		if (!q->realtime) {
 			if (q->dead) {
 				ast_mutex_unlock(&q->lock);
+				queue_unref(q);
 				return NULL;
 			} else {
 				ast_mutex_unlock(&q->lock);
@@ -1180,13 +1214,9 @@
 
 			q->dead = 1;
 			/* 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);
-			} else
-				ast_mutex_unlock(&q->lock);
+			ao2_unlink(queues, q);
+			ast_mutex_unlock(&q->lock);
+			queue_unref(q);
 		}
 		return NULL;
 	}
@@ -1198,7 +1228,8 @@
 		ast_mutex_lock(&q->lock);
 		clear_queue(q);
 		q->realtime = 1;
-		AST_LIST_INSERT_HEAD(&queues, q, list);
+		ao2_link(queues, q);
+		queue_ref(q);
 	}
 	init_queue(q);		/* Ensure defaults for all parameters not set explicitly. */
 
@@ -1255,16 +1286,11 @@
 {
 	struct ast_variable *queue_vars;
 	struct ast_config *member_config = NULL;
-	struct call_queue *q;
+	struct call_queue *q = NULL, tmpq;
 
 	/* 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);
+	ast_copy_string(tmpq.name, queuename, sizeof(tmpq.name));
+	q = ao2_find(queues, &tmpq, OBJ_POINTER);
 
 	if (!q || q->realtime) {
 		/*! \note Load from realtime before taking the global qlock, to avoid blocking all
@@ -1285,15 +1311,14 @@
 			}
 		}
 
-		AST_LIST_LOCK(&queues);
-
+		ao2_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);
+		ao2_unlock(queues);
+
 	} else {
 		update_realtime_members(q);
 	}
@@ -1377,7 +1402,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 */
@@ -1426,7 +1451,7 @@
 		ast_debug(1, "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;
 }
@@ -1614,6 +1639,7 @@
 
 	if (!(q = qe->parent))
 		return;
+	queue_ref(q);
 	ast_mutex_lock(&q->lock);
 
 	prev = NULL;
@@ -1639,13 +1665,12 @@
 	}
 	ast_mutex_unlock(&q->lock);
 
-	if (q->dead && !q->count) {	
+	if (q->dead) {	
 		/* 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);
+		queue_unref(q);
+	}
+	queue_unref(q);
 }
 
 /* Hang up a list of outgoing calls */
@@ -1719,12 +1744,16 @@
 	struct call_queue *q;
 	struct member *mem;
 	int found = 0;
+	struct ao2_iterator queue_iter;
 	
 	/* &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 */
+	queue_iter = ao2_iterator_init(queues, 0);
+	while ((q = ao2_iterator_next(&queue_iter))) {
+		if (q == rq) { /* don't check myself, could deadlock */
+			queue_unref(q);
 			continue;
+		}
 		ast_mutex_lock(&q->lock);
 		if (q->count && q->members) {
 			if ((mem = ao2_find(q->members, member->interface, 0))) {
@@ -1737,8 +1766,11 @@
 			}
 		}
 		ast_mutex_unlock(&q->lock);
-		if (found)
+		if (found) {
+			queue_unref(q);
 			break;
+		}
+		queue_unref(q);
 	}
 	return found;
 }
@@ -2265,8 +2297,9 @@
 			if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
 				/* Got hung up */
 				*to = -1;
-				if (f)
+				if (f) {
 					ast_frfree(f);
+				}
 				return NULL;
 			}
 			if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
@@ -2603,7 +2636,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);
 	ast_debug(1, "%s is trying to call a queue member.\n",
 							qe->chan->name);
@@ -2620,7 +2653,7 @@
 		if (!tmp) {
 			ast_mutex_unlock(&qe->parent->lock);
 			if (use_weight)
-				AST_LIST_UNLOCK(&queues);
+				ao2_unlock(queues);
 			goto out;
 		}
 		tmp->stillgoing = -1;
@@ -2652,7 +2685,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) {
@@ -3109,18 +3142,12 @@
 
 static int remove_from_queue(const char *queuename, const char *interface)
 {
-	struct call_queue *q;
+	struct call_queue *q, tmpq;
 	struct member *mem;
 	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;
-		}
-
+	ast_copy_string(tmpq.name, queuename, sizeof(tmpq.name));
+	if((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
 		if ((mem = ao2_find(q->members, (char *)interface, OBJ_UNLINK))) {
 			q->membercount--;
 			manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
@@ -3138,13 +3165,11 @@
 			res = RES_EXISTS;
 		}
 		ast_mutex_unlock(&q->lock);
-		break;
+		queue_unref(q);
 	}
 
 	if (res == RES_OKAY)
 		remove_from_interfaces(interface);
-
-	AST_LIST_UNLOCK(&queues);
 
 	return res;
 }
@@ -3161,7 +3186,7 @@
 	if (!(q = load_realtime_queue(queuename)))
 		return res;
 
-	AST_LIST_LOCK(&queues);
+	ao2_lock(queues);
 
 	ast_mutex_lock(&q->lock);
 	if ((old_member = interface_exists(q, interface)) == NULL) {
@@ -3197,7 +3222,7 @@
 		res = RES_EXISTS;
 	}
 	ast_mutex_unlock(&q->lock);
-	AST_LIST_UNLOCK(&queues);
+	ao2_unlock(queues);
 
 	return res;
 }
@@ -3207,14 +3232,15 @@
 	int found = 0;
 	struct call_queue *q;
 	struct member *mem;
+	struct ao2_iterator queue_iter;
 
 	/* 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) {
+	queue_iter = ao2_iterator_init(queues, 0);
+	while((q = ao2_iterator_next(&queue_iter))) {
 		ast_mutex_lock(&q->lock);
 		if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
 			if ((mem = interface_exists(q, interface))) {
@@ -3252,8 +3278,8 @@
 			}
 		}
 		ast_mutex_unlock(&q->lock);
-	}
-	AST_LIST_UNLOCK(&queues);
+		queue_unref(q);
+	}
 
 	return found ? RESULT_SUCCESS : RESULT_FAILURE;
 }
@@ -3272,10 +3298,10 @@
 	int paused = 0;
 	struct ast_db_entry *db_tree;
 	struct ast_db_entry *entry;
-	struct call_queue *cur_queue;
+	struct call_queue *cur_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);
@@ -3283,12 +3309,8 @@
 
 		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);
@@ -3299,8 +3321,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;
@@ -3344,9 +3365,10 @@
 				break;
 			}
 		}
-	}
-
-	AST_LIST_UNLOCK(&queues);
+		queue_unref(cur_queue);
+	}
+
+	ao2_unlock(queues);
 	if (db_tree) {
 		ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
 		ast_db_freetree(db_tree);
@@ -3673,8 +3695,9 @@
 
 		/* This is the wait loop for callers 2 through maxlen */
 		res = wait_our_turn(&qe, ringing, &reason);
-		if (res)
+		if (res) {
 			goto stop;
+		}
 
 		makeannouncement = 0;
 
@@ -3711,8 +3734,9 @@
 
 			/* Try calling all queue members for 'timeout' seconds */
 			res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing);
-			if (res)
+			if (res) {
 				goto stop;
+			}
 
 			stat = get_member_status(qe.parent, qe.max_penalty);
 
@@ -3821,7 +3845,7 @@
 static int queue_function_var(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 {
 	int res = -1;
-	struct call_queue *q;
+	struct call_queue *q, tmpq;
 
 	char interfacevar[256]="";
         float sl = 0;
@@ -3833,16 +3857,10 @@
 		return -1;
 	}
 	
-	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);
-
-	if (q) {
+	ast_copy_string(tmpq.name, data, sizeof(tmpq.name));
+
+	if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
+		ast_mutex_lock(&q->lock);
         	if (q->setqueuevar) {
 		        sl = 0;
 			res = 0;
@@ -3858,6 +3876,7 @@
 	        }
 
 		ast_mutex_unlock(&q->lock);
+		queue_unref(q);
 	} else
 		ast_log(LOG_WARNING, "queue %s was not found\n", data);
 
@@ -3869,7 +3888,7 @@
 static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 {
 	int count = 0;
-	struct call_queue *q;
+	struct call_queue *q, tmpq;
 	struct member *m;
 	struct ao2_iterator i;
 
@@ -3879,17 +3898,11 @@
 		ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
 		return -1;
 	}
+
+	ast_copy_string(tmpq.name, data, sizeof(tmpq.name));
 	
-	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);
-
-	if (q) {
+	if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
+		ast_mutex_lock(&q->lock);
 		i = ao2_iterator_init(q->members, 0);
 		while ((m = ao2_iterator_next(&i))) {
 			/* Count the agents who are logged in and presently answering calls */
@@ -3899,6 +3912,7 @@
 			ao2_ref(m, -1);
 		}
 		ast_mutex_unlock(&q->lock);
+		queue_unref(q);
 	} else
 		ast_log(LOG_WARNING, "queue %s was not found\n", data);
 
@@ -3910,7 +3924,7 @@
 static int queue_function_queuewaitingcount(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 {
 	int count = 0;
-	struct call_queue *q;
+	struct call_queue *q, tmpq;
 
 	buf[0] = '\0';
 	
@@ -3918,19 +3932,14 @@
 		ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
 		return -1;
 	}
+
+	ast_copy_string(tmpq.name, data, sizeof(tmpq.name));
 	
-	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);
-
-	if (q) {
+	if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
+		ast_mutex_lock(&q->lock);
 		count = q->count;
 		ast_mutex_unlock(&q->lock);
+		queue_unref(q);
 	} else
 		ast_log(LOG_WARNING, "queue %s was not found\n", data);
 
@@ -3941,7 +3950,7 @@
 
 static int queue_function_queuememberlist(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 {
-	struct call_queue *q;
+	struct call_queue *q, tmpq;
 	struct member *m;
 
 	/* Ensure an otherwise empty list doesn't return garbage */
@@ -3952,20 +3961,18 @@
 		return -1;
 	}
 
-	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);
-
-	if (q) {
+	ast_copy_string(tmpq.name, data, sizeof(tmpq.name));
+
+	if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
 		int buflen = 0, count = 0;
 		struct ao2_iterator i = ao2_iterator_init(q->members, 0);
 
+<<<<<<< .mine
+		ast_mutex_lock(&q->lock);
+		for (m = q->members; m; m = m->next) {
+=======
 		while ((m = ao2_iterator_next(&i))) {
+>>>>>>> .r82248
 			/* strcat() is always faster than printf() */
 			if (count++) {
 				strncat(buf + buflen, ",", len - buflen - 1);
@@ -3981,6 +3988,7 @@
 			ao2_ref(m, -1);
 		}
 		ast_mutex_unlock(&q->lock);
+		queue_unref(q);
 	} else
 		ast_log(LOG_WARNING, "queue %s was not found\n", data);
 
@@ -4037,7 +4045,7 @@
 
 static int reload_queues(int reload)
 {
-	struct call_queue *q;
+	struct call_queue *q, tmpq;
 	struct ast_config *cfg;
 	char *cat, *tmp;
 	struct ast_variable *var;
@@ -4050,6 +4058,7 @@
 	char *membername;
 	int penalty;
 	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+	struct ao2_iterator queue_iter;
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(interface);
 		AST_APP_ARG(penalty);
@@ -4061,12 +4070,14 @@
 		return 0;
 	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
 		return 0;
-	AST_LIST_LOCK(&queues);
+	ao2_lock(queues);
 	use_weight=0;
 	/* Mark all queues as dead for the moment */
-	AST_LIST_TRAVERSE(&queues, q, list) {
+	queue_iter = ao2_iterator_init(queues, F_AO2I_DONTLOCK);
+	while ((q = ao2_iterator_next(&queue_iter))) {
 		if(!q->realtime)
 			q->dead = 1;
+		queue_unref(q);
 	}
 
 	/* Chug through config file */
@@ -4089,11 +4100,8 @@
 					montype_default = 1;
 		} else {	/* Define queue */
 			/* Look for an existing one */
-			AST_LIST_TRAVERSE(&queues, q, list) {
-				if (!strcmp(q->name, cat))
-					break;
-			}
-			if (!q) {
+			ast_copy_string(tmpq.name, cat, sizeof(tmpq.name));
+			if(!(q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
 				/* Make one then */
 				if (!(q = alloc_queue(cat))) {
 					/* TODO: Handle memory allocation failure */
@@ -4172,20 +4180,19 @@
 				}
 
 				if (new) {
-					AST_LIST_INSERT_HEAD(&queues, q, list);
+					ao2_link(queues, q);
+					queue_ref(q);
 				} else
 					ast_mutex_unlock(&q->lock);
+				queue_unref(q);
 			}
 		}
 	}
 	ast_config_destroy(cfg);
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) {
+	queue_iter = ao2_iterator_init(queues, 0);
+	while ((q = ao2_iterator_next(&queue_iter))) {
 		if (q->dead) {
-			AST_LIST_REMOVE_CURRENT(&queues, list);
-			if (!q->count)
-				destroy_queue(q);
-			else
-				ast_debug(1, "XXX Leaking a little memory :( XXX\n");
+			ao2_unlink(queues, q);
 		} else {
 			ast_mutex_lock(&q->lock);
 			i = ao2_iterator_init(q->members, 0);
@@ -4197,9 +4204,9 @@
 			}
 			ast_mutex_unlock(&q->lock);
 		}
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-	AST_LIST_UNLOCK(&queues);
+		queue_unref(q);
+	}
+	ao2_unlock(queues);
 	return 1;
 }
 
@@ -4218,7 +4225,11 @@
 	struct ast_str *out = ast_str_alloca(240);
 	int found = 0;
 	time_t now = time(NULL);
+<<<<<<< .mine
+	struct ao2_iterator queue_iter;
+=======
 	struct ao2_iterator i;
+>>>>>>> .r82248
 
 	if (argc != 2 && argc != 3)
 		return RESULT_SHOWUSAGE;
@@ -4227,8 +4238,8 @@
 	if (argc == 3)	/* specific queue */
 		load_realtime_queue(argv[2]);
 
-	AST_LIST_LOCK(&queues);
-	AST_LIST_TRAVERSE(&queues, q, list) {
+	queue_iter = ao2_iterator_init(queues, 0);
+	while ((q = ao2_iterator_next(&queue_iter))) {
 		float sl;
 
 		ast_mutex_lock(&q->lock);
@@ -4291,10 +4302,12 @@
 		}
 		do_print(s, fd, "");	/* blank line between entries */
 		ast_mutex_unlock(&q->lock);
-		if (argc == 3)	/* print a specific entry */
+		if (argc == 3)	{ /* print a specific entry */
+			queue_unref(q);
 			break;
-	}
-	AST_LIST_UNLOCK(&queues);
+		}
+		queue_unref(q);
+	}
 	if (!found) {
 		if (argc == 3)
 			ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
@@ -4316,15 +4329,15 @@
 	char *ret = NULL;
 	int which = 0;
 	int wordlen = strlen(word);
+	struct ao2_iterator queue_iter;
 	
-	AST_LIST_LOCK(&queues);
-	AST_LIST_TRAVERSE(&queues, q, list) {
+	queue_iter = ao2_iterator_init(queues, 0);
+	while((q = ao2_iterator_next(&queue_iter))) {
 		if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
 			ret = ast_strdup(q->name);	
 			break;
 		}
 	}
-	AST_LIST_UNLOCK(&queues);
 
 	return ret;
 }
@@ -4362,14 +4375,18 @@
 	struct call_queue *q;
 	struct queue_ent *qe;
 	struct member *mem;
+<<<<<<< .mine
+	struct ao2_iterator queue_iter;
+=======
 	struct ao2_iterator i;
+>>>>>>> .r82248
 
 	astman_send_ack(s, m, "Queue summary will follow");
 	time(&now);
-	AST_LIST_LOCK(&queues);
 	if (!ast_strlen_zero(id))
 		snprintf(idText, 256, "ActionID: %s\r\n", id);
-        AST_LIST_TRAVERSE(&queues, q, list) {
+	queue_iter = ao2_iterator_init(queues, 0);
+	while((q = ao2_iterator_next(&queue_iter))) {
 		ast_mutex_lock(&q->lock);
 
 		/* List queue properties */
@@ -4399,13 +4416,12 @@
 				q->name, qmemcount, qmemavail, qchancount, q->holdtime, idText);
 		}
 		ast_mutex_unlock(&q->lock);
+		queue_unref(q);
 	}
 	astman_append(s,
 		"Event: QueueSummaryComplete\r\n"
 		"%s"
 		"\r\n", idText);
-
-	AST_LIST_UNLOCK(&queues);
 
 	return RESULT_SUCCESS;
 }
@@ -4423,15 +4439,19 @@
 	struct queue_ent *qe;
 	float sl = 0;
 	struct member *mem;
+<<<<<<< .mine
+	struct ao2_iterator queue_iter;
+=======
 	struct ao2_iterator i;
+>>>>>>> .r82248
 
 	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) {
+	queue_iter = ao2_iterator_init(queues, 0);
+	while ((q = ao2_iterator_next(&queue_iter))) {
 		ast_mutex_lock(&q->lock);
 
 		/* List queue properties */
@@ -4491,15 +4511,13 @@
 			}
 		}
 		ast_mutex_unlock(&q->lock);
+		queue_unref(q);
 	}
 
 	astman_append(s,
 		"Event: QueueStatusComplete\r\n"
 		"%s"
 		"\r\n",idText);
-
-	AST_LIST_UNLOCK(&queues);
-
 
 	return RESULT_SUCCESS;
 }
@@ -4757,7 +4775,11 @@
 	int which = 0;
 	struct call_queue *q;
 	struct member *m;
+<<<<<<< .mine
+	struct ao2_iterator queue_iter;
+=======
 	struct ao2_iterator i;
+>>>>>>> .r82248
 
 	/* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
 	if (pos > 5 || pos < 3)
@@ -4769,6 +4791,16 @@
 		return complete_queue(line, word, pos, state);
 
 	/* here is the case for 3, <member> */
+<<<<<<< .mine
+	queue_iter = ao2_iterator_init(queues, 0);
+	while ((q = ao2_iterator_next(&queue_iter))) {
+		ast_mutex_lock(&q->lock);
+		for (m = q->members ; m ; m = m->next) {
+			if (++which > state) {
+				ast_mutex_unlock(&q->lock);
+				queue_unref(q);
+				return ast_strdup(m->interface);
+=======
 	if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */
 		AST_LIST_TRAVERSE(&queues, q, list) {
 			ast_mutex_lock(&q->lock);
@@ -4781,9 +4813,11 @@
 					ao2_ref(m, -1);
 					return tmp;
 				}
-			}
-			ast_mutex_unlock(&q->lock);
-		}
+>>>>>>> .r82248
+			}
+		}
+		ast_mutex_unlock(&q->lock);
+		queue_unref(q);
 	}
 
 	return NULL;
@@ -4855,6 +4889,8 @@
 
 	clear_and_free_interfaces();
 
+	ao2_ref(queues, -1);
+
 	return res;
 }
 
@@ -4862,6 +4898,8 @@
 {
 	int res;
 	struct ast_context *con;
+
+	queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
 
 	if (!reload_queues(0))
 		return AST_MODULE_LOAD_DECLINE;




More information about the asterisk-commits mailing list