[asterisk-commits] irroot: branch irroot/asterisk-trunk-quack-queue r343279 - /team/irroot/aster...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Nov 3 10:51:40 CDT 2011


Author: irroot
Date: Thu Nov  3 10:51:37 2011
New Revision: 343279

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=343279
Log:
Optomised try_calling / use linkedlist

moved unneeded locks / datastore lookup on each member out the loop.
q->head was a linked list not using the linkedlist api this has been fixed.

im hoping that the try_calling changes will improve performance substantially

Modified:
    team/irroot/asterisk-trunk-quack-queue/apps/app_queue.c

Modified: team/irroot/asterisk-trunk-quack-queue/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/irroot/asterisk-trunk-quack-queue/apps/app_queue.c?view=diff&rev=343279&r1=343278&r2=343279
==============================================================================
--- team/irroot/asterisk-trunk-quack-queue/apps/app_queue.c (original)
+++ team/irroot/asterisk-trunk-quack-queue/apps/app_queue.c Thu Nov  3 10:51:37 2011
@@ -1086,7 +1086,7 @@
 	struct ast_channel *chan;              /*!< Our channel */
 	AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules; /*!< Local copy of the queue's penalty rules */
 	struct penalty_rule *pr;               /*!< Pointer to the next penalty rule to implement */
-	struct queue_ent *next;                /*!< The next queue entry */
+	AST_LIST_ENTRY(queue_ent) next;        /*!< The next queue entry */
 };
 
 /*! \brief keep track of device state changes */
@@ -1238,7 +1238,7 @@
 	int autofill;                       /*!< Ignore the head call status and ring an available agent */
 	
 	struct ao2_container *members;             /*!< Head of the list of members */
-	struct queue_ent *head;             /*!< Head of the list of callers */
+	AST_LIST_HEAD(,queue_ent)  *head; /*!< Head of the list of callers */
 	AST_LIST_ENTRY(call_queue) list;    /*!< Next call queue */
 	AST_LIST_HEAD_NOLOCK(, penalty_rule) rules; /*!< The list of penalty rules to invoke */
 };
@@ -1347,20 +1347,11 @@
 }
 
 /*! \brief Insert the 'new' callattempt 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)
-{
-	struct queue_ent *cur;
-
-	if (!q || !new)
+static inline void insert_entry(struct call_queue *q, struct queue_ent *new, int *pos)
+{
+	if (!q || !new) {
 		return;
-	if (prev) {
-		cur = prev->next;
-		prev->next = new;
-	} else {
-		cur = q->head;
-		q->head = new;
-	}
-	new->next = cur;
+	}
 
 	/* every queue_ent must have a reference to it's parent call_queue, this
 	 * reference does not go away until the end of the queue_ent's life, meaning
@@ -1372,9 +1363,10 @@
 }
 
 /*! \brief return the device state for a member*/
-static int get_device_status(struct mem_state *s)
+static int get_device_status(struct member *m)
 {
 	int ret;
+	struct mem_state *s = m->device;
 
 	ao2_lock(s);
 	if (s->reserved && ((s->status == AST_DEVICE_NOT_INUSE) || (s->status == AST_DEVICE_UNKNOWN))) {
@@ -1397,7 +1389,6 @@
 {
 	struct member *member;
 	struct ao2_iterator mem_iter;
-	int status;
 	enum empty_conditions conditions;
 
 	ao2_lock(q);
@@ -1419,8 +1410,7 @@
 			}
 		}
 
-		status = get_device_status(member->device);
-		switch (status) {
+		switch (get_device_status(member)) {
 		case AST_DEVICE_INVALID:
 			if (conditions & QUEUE_EMPTY_INVALID) {
 				ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
@@ -1944,6 +1934,10 @@
 			free(q->sound_periodicannounce[i]);
 	}
 	ao2_ref(q->members, -1);
+	if (q->head) {
+		AST_LIST_HEAD_DESTROY(q->head);
+		ast_free(q->head);
+	}
 }
 
 /*! \brief create a new call_queue structure */
@@ -1958,6 +1952,12 @@
 		}
 		ast_string_field_set(q, name, queuename);
 	}
+	if (!(q->head = ast_calloc(1, sizeof(*q->head)))) {
+		ast_string_field_free_memory(q);
+		ao2_ref(q, -1);
+		return NULL;
+	}
+	AST_LIST_HEAD_INIT(q->head);
 	q->realtime = rt;
 	q->weight = 0;
 	q->found = 0;
@@ -2430,6 +2430,7 @@
 			res = RES_NOT_DYNAMIC;
 		}
 		ao2_unlock(m);
+		ao2_unlock(q->members);
                 ao2_ref(m, -1);
 		return res;
 	} else if (!link && (m->realtime || m->dynamic) && (memtype & MEMBER_STATIC)) {
@@ -2446,6 +2447,7 @@
 			m->realtime = 1;
 		} else if (!m->realtime) {
 			ao2_unlock(m);
+			ao2_unlock(q->members);
 			ao2_ref(m, -1);
 			return RES_EXISTS;
 		}
@@ -2532,7 +2534,7 @@
 			ast_queue_log(q->name, source, m->membername, "ADDMEMBER", "%s", "");
 		}
 		if (m->dynamic) {
-			int status = get_device_status(m->device);
+			int status = get_device_status(m);
 			manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
 				"Queue: %s\r\n"
 				"Location: %s\r\n"
@@ -2747,7 +2749,7 @@
 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
 {
 	struct call_queue *q;
-	struct queue_ent *cur, *prev = NULL;
+	struct queue_ent *cur;
 	int res = -1;
 	int pos = 0;
 	int inserted = 0;
@@ -2776,22 +2778,23 @@
 	 * the queue.
 	 * Take into account the priority of the calling user */
 	inserted = 0;
-	prev = NULL;
-	ao2_lock(q);
-	cur = q->head;
-	while (cur) {
+	
+	AST_LIST_LOCK(q->head);
+	AST_LIST_TRAVERSE_SAFE_BEGIN(q->head, cur, next) {
 		/* We have higher priority than the current user, enter
 		 * before him, after all the other users with priority
 		 * higher or equal to our priority. */
 		if ((!inserted) && (qe->prio > cur->prio)) {
-			insert_entry(q, prev, qe, &pos);
+			AST_LIST_INSERT_BEFORE_CURRENT(qe, next);
+			insert_entry(q, qe, &pos);
 			inserted = 1;
 		}
 		/* <= is necessary for the position comparison because it may not be possible to enter
 		 * at our desired position since higher-priority callers may have taken the position we want
 		 */
 		if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
-			insert_entry(q, prev, qe, &pos);
+			AST_LIST_INSERT_BEFORE_CURRENT(qe, next);
+			insert_entry(q, qe, &pos);
 			/*pos is incremented inside insert_entry, so don't need to add 1 here*/
 			if (position < pos) {
 				ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
@@ -2799,12 +2802,17 @@
 			inserted = 1;
 		}
 		cur->pos = ++pos;
-		prev = cur;
-		cur = cur->next;
-	}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+
 	/* No luck, join at the end of the queue */
-	if (!inserted)
-		insert_entry(q, prev, qe, &pos);
+	if (!inserted) {
+		AST_LIST_INSERT_TAIL(q->head, qe, next);
+		insert_entry(q, qe, &pos);
+	}
+	AST_LIST_UNLOCK(q->head);
+
+	ao2_lock(q);
 	ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
 	ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
 	ast_copy_string(qe->context, q->context, sizeof(qe->context));
@@ -3081,7 +3089,7 @@
 static void leave_queue(struct queue_ent *qe)
 {
 	struct call_queue *q;
-	struct queue_ent *current, *prev = NULL;
+	struct queue_ent *cur;
 	struct penalty_rule *pr_iter;
 	int pos = 0;
 
@@ -3089,11 +3097,11 @@
 		return;
 	}
 	ao2_t_ref(q, 1, "Copy queue pointer from queue entry");
-	ao2_lock(q);
-
-	prev = NULL;
-	for (current = q->head; current; current = current->next) {
-		if (current == qe) {
+
+	AST_LIST_LOCK(q->head);
+	AST_LIST_TRAVERSE_SAFE_BEGIN(q->head, cur, next) {
+		if (cur == qe) {
+			ao2_lock(q);
 			char posstr[20];
 			q->count--;
 
@@ -3101,24 +3109,22 @@
 			ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave",
 				"Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n",
 				qe->chan->name, q->name,  q->count, qe->pos, qe->chan->uniqueid);
+			ao2_unlock(q);
 			ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
 			/* Take us out of the queue */
-			if (prev)
-				prev->next = current->next;
-			else
-				q->head = current->next;
-			/* Free penalty rules */
+			AST_LIST_REMOVE_CURRENT(next);
 			while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list)))
 				ast_free(pr_iter);
 			snprintf(posstr, sizeof(posstr), "%d", qe->pos);
 			pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
 		} else {
 			/* Renumber the people after us in the queue based on a new count */
-			current->pos = ++pos;
-			prev = current;
-		}
-	}
-	ao2_unlock(q);
+			cur->pos = ++pos;
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+	AST_LIST_UNLOCK(q->head);
+
 	ao2_t_ref(q, -1, "Expire copied reference");
 }
 
@@ -3180,7 +3186,7 @@
 	struct member *mem;
 	int avl = 0;
 	struct ao2_iterator mem_iter;
-	int ringinuse, needone, status;
+	int ringinuse, needone;
 
 	ao2_lock(q);
 	ringinuse = q->ringinuse;
@@ -3192,8 +3198,7 @@
 	mem_iter = ao2_iterator_init(q->members, AO2_ITERATOR_DONTLOCK);
 	ao2_lock(q->members);
 	while ((mem = ao2_iterator_next(&mem_iter))) {
-		status = get_device_status(mem->device);
-		switch (status) {
+		switch (get_device_status(mem)) {
 			case AST_DEVICE_INVALID:
 			case AST_DEVICE_UNAVAILABLE:
 				break;
@@ -3367,7 +3372,7 @@
 	ignorebusy = tmp->member->ignorebusy;
 	membername = ast_strdupa(tmp->member->membername);
 	s = tmp->member->device;
-	dstat = get_device_status(s);
+	dstat = get_device_status(tmp->member);
 
 	/* mark device and call entry reserved */
 	if (!tmp->reserved) {
@@ -3437,7 +3442,10 @@
 
 		ao2_lock(qe->parent);
 		set_queue_member_status(tmp->member);
+		/* this is needs to be locked for new_attempt */
+		ao2_lock(qe->parent->members);
 		qe->parent->rrpos++;
+		ao2_unlock(qe->parent->members);
 		qe->linpos++;
 		ao2_unlock(qe->parent);
 
@@ -3620,11 +3628,15 @@
 	return ret;
 }
 
-/*! \brief Search for best metric and add to Round Robbin queue */
+/*! \brief Search for best metric and add to Round Robbin queue 
+ * \note the members container is locked here for new_attempt
+ */
 static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
 {
 	struct callattempt *best = find_best(outgoing);
 
+	/* this is needs to be locked for new_attempt */
+	ao2_lock(qe->parent->members);
 	if (best) {
 		/* Ring just the best channel */
 		ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
@@ -3640,6 +3652,7 @@
 		}
 	}
 	qe->parent->wrapped = 0;
+	ao2_unlock(qe->parent->members);
 
 	return 0;
 }
@@ -4259,33 +4272,36 @@
 	int avl;
 	int autofill;
 	int idx = 0;
+
 	/* How many members are available to be served? */
 	avl = num_available_members(qe->parent);
-
 	ao2_lock(qe->parent);
-	ch = qe->parent->head;
-
-	ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
-
-	while ((idx < avl) && (ch) && (ch != qe)) {
-		if (!ch->pending)
-			idx++;
-		ch = ch->next;
-	}
-
 	autofill = qe->parent->autofill;
 	ao2_unlock(qe->parent);
+
+	ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
+
+	AST_LIST_LOCK(qe->parent->head);
+	ch = AST_LIST_FIRST(qe->parent->head);
+	while (ch && (idx < avl) && (ch != qe)) {
+		if (!ch->pending) {
+			idx++;
+		}
+		ch = AST_LIST_NEXT(ch, next);
+	}
+
 	/* If the queue entry is within avl [the number of available members] calls from the top ...
 	 * Autofill and position check added to support autofill=no (as only calls
 	 * from the front of the queue are valid when autofill is disabled)
 	 */
-	if (ch && idx < avl && (autofill || qe->pos == 1)) {
+	if (ch && (idx < avl) && (autofill || qe->pos == 1)) {
 		ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
 		res = 1;
 	} else {
 		ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
 		res = 0;
 	}
+	AST_LIST_UNLOCK(qe->parent->head);
 
 	return res;
 }
@@ -4456,86 +4472,86 @@
 	return 0;
 }
 
-/*! \brief Calculate the metric of each member in the outgoing callattempts
+/*! \brief Create a new call attempt for the queue from member
  *
  * A numeric metric is given to each member depending on the ring strategy used
  * by the queue. Members with lower metrics will be called before members with
  * higher metrics
- * \retval -1 if penalties are exceeded
- * \retval 0 otherwise
+ * \retval null if metric cannot be allocated
+ * \retval new callattempt otherwise
  */
-static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
-{
-	int membercount = ao2_container_count(q->members);
-	unsigned int usepenalty;
-
-	ao2_lock(q);
-
-	usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
-
-	if (usepenalty) {
-		if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) ||
-			(qe->min_penalty && (mem->penalty < qe->min_penalty))) {
-			return -1;
-		}
-	} else {
-		ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
-			  membercount, q->penaltymemberslimit);
-	}
-
-	switch (q->strategy) {
+static struct callattempt *new_attempt(struct queue_ent *qe, struct member *mem, int pos, int usepenalty, int strategy)
+{
+	int metric;
+	struct callattempt *tmp;
+	struct call_queue *q = qe->parent;
+
+	switch (strategy) {
 	case QUEUE_STRATEGY_RINGALL:
 		/* Everyone equal, except for penalty */
-		tmp->metric = mem->penalty * 1000000 * usepenalty;
+		metric = mem->penalty * 1000000 * usepenalty;
 		break;
 	case QUEUE_STRATEGY_LINEAR:
 		if (pos < qe->linpos) {
-			tmp->metric = 1000 + pos;
+			metric = 1000 + pos;
 		} else {
 			if (pos > qe->linpos)
 				/* Indicate there is another priority */
 				qe->linwrapped = 1;
-			tmp->metric = pos;
-		}
-		tmp->metric += mem->penalty * 1000000 * usepenalty;
+			metric = pos;
+		}
+		metric += mem->penalty * 1000000 * usepenalty;
 		break;
 	case QUEUE_STRATEGY_RRORDERED:
 	case QUEUE_STRATEGY_RRMEMORY:
 		if (pos < q->rrpos) {
-			tmp->metric = 1000 + pos;
+			metric = 1000 + pos;
 		} else {
 			if (pos > q->rrpos)
 				/* Indicate there is another priority */
 				q->wrapped = 1;
-			tmp->metric = pos;
-		}
-		tmp->metric += mem->penalty * 1000000 * usepenalty;
+			metric = pos;
+		}
+		metric += mem->penalty * 1000000 * usepenalty;
 		break;
 	case QUEUE_STRATEGY_RANDOM:
-		tmp->metric = ast_random() % 1000;
-		tmp->metric += mem->penalty * 1000000 * usepenalty;
+		metric = ast_random() % 1000;
+		metric += mem->penalty * 1000000 * usepenalty;
 		break;
 	case QUEUE_STRATEGY_WRANDOM:
-		tmp->metric = ast_random() % ((1 + mem->penalty) * 1000);
+		metric = ast_random() % ((1 + mem->penalty) * 1000);
 		break;
 	case QUEUE_STRATEGY_FEWESTCALLS:
-		tmp->metric = mem->calls;
-		tmp->metric += mem->penalty * 1000000 * usepenalty;
+		metric = mem->calls;
+		metric += mem->penalty * 1000000 * usepenalty;
 		break;
 	case QUEUE_STRATEGY_LEASTRECENT:
-		if (!mem->lastcall)
-			tmp->metric = 0;
-		else
-			tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
-		tmp->metric += mem->penalty * 1000000 * usepenalty;
+		if (!mem->lastcall) {
+			metric = 0;
+		} else {
+			metric = 1000000 - (time(NULL) - mem->lastcall);
+		}
+		metric += mem->penalty * 1000000 * usepenalty;
 		break;
 	default:
-		ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
+		ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", strategy);
+		metric = -1;
 		break;
 	}
 
-	ao2_unlock(q);
-	return 0;
+	if ((metric < 0) || (!(tmp = ast_calloc(1, sizeof(*tmp))))) {
+		return NULL;
+	}
+
+	tmp->stillgoing = -1;
+	tmp->member = mem;/* Place the reference for cur into callattempt. */
+	tmp->lastcall = mem->lastcall;
+	tmp->lastwrapup = mem->lastwrapup;
+	tmp->reserved = 0;
+	tmp->metric = metric;
+	ast_copy_string(tmp->interface, mem->interface, sizeof(tmp->interface));
+
+	return tmp;
 }
 
 enum agent_complete_reason {
@@ -4719,7 +4735,7 @@
  * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this
  *    iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this
  *    member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also
- *    during each iteration, we call calc_metric to determine which members should be rung when.
+ *    during each iteration, we calculate a metric to determine which members should be rung when.
  * \note It is too costly to lock and unlock the queue and members for this and the queue and members container
  * Is locked for the whole process.
  *
@@ -4783,13 +4799,15 @@
 	struct ao2_iterator memi;
 	struct ast_datastore *datastore, *transfer_ds;
 	struct queue_end_bridge *queue_end_bridge = NULL;
+	struct ast_dialed_interface *di;
+	struct ast_party_connected_line connected;
+	struct callattempt *tmp;
+	AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
 	int reportholdtime, memberdelay;
+	unsigned int usepenalty;
+	int strategy;
 	char *monfmt;
 	int montype;
-
-	ast_channel_lock(qe->chan);
-	datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
-	ast_channel_unlock(qe->chan);
 
 	memset(&bridge_config, 0, sizeof(bridge_config));
 	tmpid[0] = 0;
@@ -4804,6 +4822,11 @@
 		res = 0;
 		goto out;
 	}
+
+	ao2_lock(qe->parent);
+	usepenalty = (ao2_container_count(qe->parent->members) <= qe->parent->penaltymemberslimit) ? 0 : 1;
+	strategy = qe->parent->strategy;
+	ao2_unlock(qe->parent);
 		
 	for (; options && *options; options++)
 		switch (*options) {
@@ -4838,15 +4861,13 @@
 			ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
 			break;
 		case 'n':
-			ao2_lock(qe->parent);
-			if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY ||
-			    qe->parent->strategy == QUEUE_STRATEGY_LINEAR ||
-                            qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) {
+			if (strategy == QUEUE_STRATEGY_RRMEMORY ||
+			    strategy == QUEUE_STRATEGY_LINEAR ||
+			    strategy == QUEUE_STRATEGY_RRORDERED) {
 				(*tries)++;
 			} else {
 				*tries = ao2_container_count(qe->parent->members);
 			}
-			ao2_unlock(qe->parent);
 			*noption = 1;
 			break;
 		case 'i':
@@ -4873,7 +4894,36 @@
 		qe->cancel_answered_elsewhere = 1;
 	}
 
-	ao2_lock(qe->parent);
+	ast_party_connected_line_init(&connected);
+	ast_channel_lock(qe->chan);
+		/*
+		 * Seed the callattempt's connected line information with previously
+		 * acquired connected line info from the queued channel.  The
+		 * previously acquired connected line info could have been set
+		 * through the CONNECTED_LINE dialplan function.
+		 */
+	ast_party_connected_line_copy(&connected, &qe->chan->connected);
+	datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
+	ast_channel_unlock(qe->chan);
+
+	if (!datastore && 
+	    (datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
+		datastore->inheritance = DATASTORE_INHERIT_FOREVER;
+		if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
+			goto out;
+		}
+		datastore->data = dialed_interfaces;
+		AST_LIST_HEAD_INIT(dialed_interfaces);
+
+		ast_channel_lock(qe->chan);
+		ast_channel_datastore_add(qe->chan, datastore);
+		ast_channel_unlock(qe->chan);
+	} else if (datastore) {
+		dialed_interfaces = datastore->data;
+	} else {
+		goto out;
+	}
+
 	ast_debug(1, "%s is trying to call a queue member.\n",
 							qe->chan->name);
 	ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
@@ -4885,43 +4935,6 @@
 	memi = ao2_iterator_init(qe->parent->members, AO2_ITERATOR_DONTLOCK);
 	ao2_lock(qe->parent->members);
 	while ((cur = ao2_iterator_next(&memi))) {
-		struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
-		struct ast_dialed_interface *di;
-		AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
-		if (!tmp) {
-			ao2_ref(cur, -1);
-			ao2_iterator_destroy(&memi);
-			ao2_lock(qe->parent->members);
-			ao2_unlock(qe->parent);
-			goto out;
-		}
-		if (!datastore) {
-			if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
-				ao2_ref(cur, -1);
-				ao2_iterator_destroy(&memi);
-				callattempt_free(tmp);
-				ao2_lock(qe->parent->members);
-				ao2_unlock(qe->parent);
-				goto out;
-			}
-			datastore->inheritance = DATASTORE_INHERIT_FOREVER;
-			if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
-				ao2_ref(cur, -1);
-				ao2_iterator_destroy(&memi);
-				callattempt_free(tmp);
-				ao2_lock(qe->parent->members);
-				ao2_unlock(qe->parent);
-				goto out;
-			}
-			datastore->data = dialed_interfaces;
-			AST_LIST_HEAD_INIT(dialed_interfaces);
-
-			ast_channel_lock(qe->chan);
-			ast_channel_datastore_add(qe->chan, datastore);
-			ast_channel_unlock(qe->chan);
-		} else
-			dialed_interfaces = datastore->data;
-
 		AST_LIST_LOCK(dialed_interfaces);
 		AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
 			if (!strcasecmp(cur->interface, di->interface)) {
@@ -4933,7 +4946,6 @@
 		AST_LIST_UNLOCK(dialed_interfaces);
 
 		if (di) {
-			callattempt_free(tmp);
 			ao2_ref(cur, -1);
 			continue;
 		}
@@ -4945,10 +4957,8 @@
 		if (strncasecmp(cur->interface, "Local/", 6)) {
 			if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
 				ao2_ref(cur, -1);
+				ao2_unlock(qe->parent->members);
 				ao2_iterator_destroy(&memi);
-				callattempt_free(tmp);
-				ao2_lock(qe->parent->members);
-				ao2_unlock(qe->parent);
 				goto out;
 			}
 			strcpy(di->interface, cur->interface);
@@ -4958,25 +4968,16 @@
 			AST_LIST_UNLOCK(dialed_interfaces);
 		}
 
-		ast_channel_lock(qe->chan);
-		/*
-		 * Seed the callattempt's connected line information with previously
-		 * acquired connected line info from the queued channel.  The
-		 * previously acquired connected line info could have been set
-		 * through the CONNECTED_LINE dialplan function.
-		 */
-		ast_party_connected_line_copy(&tmp->connected, &qe->chan->connected);
-		ast_channel_unlock(qe->chan);
-
-		tmp->stillgoing = -1;
-		tmp->member = cur;/* Place the reference for cur into callattempt. */
-		tmp->lastcall = cur->lastcall;
-		tmp->lastwrapup = cur->lastwrapup;
-		tmp->reserved = 0;
-		ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
-		/* Special case: If we ring everyone, go ahead and ring them, otherwise
-		   just calculate their metric for the appropriate strategy */
-		if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
+		if (usepenalty &&
+		    ((qe->max_penalty && (cur->penalty > qe->max_penalty)) ||
+		     (qe->min_penalty && (cur->penalty < qe->min_penalty)))) {
+			ao2_ref(cur, -1);
+			continue;
+		}
+
+		/* the ref for member is passed to this attempt*/
+		if ((tmp = new_attempt(qe, cur, x++, usepenalty, strategy))) {
+			ast_party_connected_line_copy(&tmp->connected, &connected);
 			/* Put them in the list of outgoing thingies...  We're ready now.
 			   XXX If we're forcibly removed, these outgoing calls won't get
 			   hung up XXX */
@@ -4987,13 +4988,13 @@
 				break;
 			}
 		} else {
-			ao2_unlock(cur);
-			callattempt_free(tmp);
-		}
-	}
-	ao2_lock(qe->parent->members);
+			ao2_ref(cur, -1);
+		}
+	}
+	ao2_unlock(qe->parent->members);
 	ao2_iterator_destroy(&memi);
 
+	ao2_lock(qe->parent);
 	if (qe->parent->timeoutpriority == TIMEOUT_PRIORITY_APP) {
 		/* Application arguments have higher timeout priority (behaviour for <=1.6) */
 		if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
@@ -6644,7 +6645,7 @@
 			while ((m = ao2_iterator_next(&mem_iter))) {
 				/* Count the agents who are logged in and presently answering calls */
 				ao2_lock(m);
-				status = get_device_status(m->device);
+				status = get_device_status(m);
 				if ((status != AST_DEVICE_UNAVAILABLE) && (status != AST_DEVICE_INVALID)) {
 					count++;
 				}
@@ -6657,7 +6658,7 @@
 			while ((m = ao2_iterator_next(&mem_iter))) {
 				ao2_lock(m);
 				/* Count the agents who are logged in and presently answering calls */
-				status = get_device_status(m->device);
+				status = get_device_status(m);
 				if ((status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
 					count++;
 				}
@@ -6672,7 +6673,7 @@
 			while ((m = ao2_iterator_next(&mem_iter))) {
 				ao2_lock(m);
 				/* Count the agents who are logged in, not paused and not wrapping up */
-				status = get_device_status(m->device);
+				status = get_device_status(m);
 				if ((status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
 				    !(m->lastcall && m->lastwrapup && ((now - m->lastwrapup) < m->lastcall))) {
 					count++;
@@ -6828,7 +6829,7 @@
 		while ((m = ao2_iterator_next(&mem_iter))) {
 			ao2_lock(m);
 			/* Count the agents who are logged in and presently answering calls */
-			status = get_device_status(m->device);
+			status = get_device_status(m);
 			if ((status != AST_DEVICE_UNAVAILABLE) && (status != AST_DEVICE_INVALID)) {
 				count++;
 			}
@@ -7481,7 +7482,7 @@
 				if (mem->penalty) {
 					ast_str_append(&out, 0, " with penalty %d", mem->penalty);
 				}
-				status = get_device_status(mem->device);
+				status = get_device_status(mem);
 				ast_str_append(&out, 0, "%s%s%s (%s)",
 					mem->dynamic ? " (dynamic)" : "",
 					mem->realtime ? " (realtime)" : "",
@@ -7500,7 +7501,6 @@
 			ao2_unlock(q->members);
 			ao2_iterator_destroy(&mem_iter);
 		}
-		ao2_lock(q);
 		if (!q->head) {
 			do_print(s, fd, "   No Callers");
 		} else {
@@ -7508,15 +7508,16 @@
 			int pos = 1;
 
 			do_print(s, fd, "   Callers: ");
-			for (qe = q->head; qe; qe = qe->next) {
+			AST_LIST_LOCK(q->head);
+			AST_LIST_TRAVERSE(q->head, qe, next) {
 				ast_str_set(&out, 0, "      %d. %s (wait: %ld:%2.2ld, prio: %d)",
 					pos++, qe->chan->name, (long) (now - qe->start) / 60,
 					(long) (now - qe->start) % 60, qe->prio);
 				do_print(s, fd, ast_str_buffer(out));
 			}
+			AST_LIST_UNLOCK(q->head);
 		}
 		do_print(s, fd, "");	/* blank line between entries */
-		ao2_unlock(q);
 		ao2_t_ref(q, -1, "Done with iterator"); /* Unref the iterator's reference */
 	}
 	ao2_iterator_destroy(&queue_iter);
@@ -7669,7 +7670,7 @@
 		mem_iter = ao2_iterator_init(q->members, AO2_ITERATOR_DONTLOCK);
 		ao2_lock(q->members);
 		while ((mem = ao2_iterator_next(&mem_iter))) {
-			status = get_device_status(mem->device);
+			status = get_device_status(mem);
 			if ((status != AST_DEVICE_UNAVAILABLE) && (status != AST_DEVICE_INVALID)) {
 				++qmemcount;
 				if (((status == AST_DEVICE_NOT_INUSE) || (status == AST_DEVICE_UNKNOWN)) && !(mem->paused)) {
@@ -7680,13 +7681,15 @@
 		}
 		ao2_unlock(q->members);
 		ao2_iterator_destroy(&mem_iter);
-		ao2_lock(q);
-		for (qe = q->head; qe; qe = qe->next) {
+
+		AST_LIST_LOCK(q->head);
+		AST_LIST_TRAVERSE(q->head, qe, next) {
 			if ((now - qe->start) > qlongestholdtime) {
 				qlongestholdtime = now - qe->start;
 			}
 			++qchancount;
 		}
+		AST_LIST_UNLOCK(q->head);
 		astman_append(s, "Event: QueueSummary\r\n"
 			"Queue: %s\r\n"
 			"LoggedIn: %d\r\n"
@@ -7698,7 +7701,6 @@
 			"%s"
 			"\r\n",
 			q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
-		ao2_unlock(q);
 		ao2_t_ref(q, -1, "Done with iterator");
 	}
 	ao2_iterator_destroy(&queue_iter);
@@ -7769,7 +7771,7 @@
 		ao2_lock(q->members);
 		while ((mem = ao2_iterator_next(&mem_iter))) {
 			if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
-				status = get_device_status(mem->device);
+				status = get_device_status(mem);
 				astman_append(s, "Event: QueueMember\r\n"
 					"Queue: %s\r\n"
 					"Name: %s\r\n"
@@ -7792,8 +7794,8 @@
 		ao2_iterator_destroy(&mem_iter);
 		/* List Queue Entries */
 		pos = 1;
-		ao2_lock(q);
-		for (qe = q->head; qe; qe = qe->next) {
+		AST_LIST_LOCK(q->head);
+		AST_LIST_TRAVERSE(q->head, qe, next) {
 			astman_append(s, "Event: QueueEntry\r\n"
 				"Queue: %s\r\n"
 				"Position: %d\r\n"
@@ -7813,7 +7815,7 @@
 				S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
 				(long) (now - qe->start), idText);
 		}
-		ao2_unlock(q);
+		AST_LIST_UNLOCK(q->head);
 		ao2_t_ref(q, -1, "Done with iterator");
 	}
 	ao2_iterator_destroy(&queue_iter);
@@ -8867,33 +8869,31 @@
 	}
 
 	/* include the callers inside the result. */
-	ao2_lock(queue);
-	if (queue->head) {
-		for (qe = queue->head; qe; qe = qe->next) {
+	AST_LIST_LOCK(queue->head);
+	AST_LIST_TRAVERSE(queue->head, qe, next) {
+		if (!data_callers) {
+			data_callers = ast_data_add_node(data_queue, "callers");
 			if (!data_callers) {
-				data_callers = ast_data_add_node(data_queue, "callers");
-				if (!data_callers) {
-					continue;
-				}
-			}
-
-			data_caller = ast_data_add_node(data_callers, "caller");
-			if (!data_caller) {
 				continue;
 			}
-
-			ast_data_add_structure(queue_ent, data_caller, qe);
-
-			/* add the caller channel. */
-			data_caller_channel = ast_data_add_node(data_caller, "channel");
-			if (!data_caller_channel) {
-				continue;
-			}
-
-			ast_channel_data_add_structure(data_caller_channel, qe->chan, 1);
-		}
-	}
-	ao2_unlock(queue);
+		}
+
+		data_caller = ast_data_add_node(data_callers, "caller");
+		if (!data_caller) {
+			continue;
+		}
+
+		ast_data_add_structure(queue_ent, data_caller, qe);
+
+		/* add the caller channel. */
+		data_caller_channel = ast_data_add_node(data_caller, "channel");
+		if (!data_caller_channel) {
+			continue;
+		}
+
+		ast_channel_data_add_structure(data_caller_channel, qe->chan, 1);
+	}
+	AST_LIST_UNLOCK(queue->head);
 
 	/* if this queue doesn't match remove the added queue. */
 	if (!ast_data_search_match(search, data_queue)) {
@@ -8984,7 +8984,7 @@
 	}
 
 	q_iter = ao2_iterator_init(queues, AO2_ITERATOR_UNLINK);
-	while ((q = ao2_t_iterator_next(&q_iter, "Iterate through queues"))) {
+	while ((q = ao2_iterator_next(&q_iter))) {
 		ao2_t_ref(q, -1, "Done with iterator");
 	}
 	ao2_iterator_destroy(&q_iter);




More information about the asterisk-commits mailing list