[Asterisk-code-review] app queue: queue members can receive multiple calls (asterisk[11])

Kevin Harwell asteriskteam at digium.com
Thu Apr 21 15:36:57 CDT 2016


Kevin Harwell has uploaded a new change for review.

  https://gerrit.asterisk.org/2679

Change subject: app_queue: queue members can receive multiple calls
......................................................................

app_queue: queue members can receive multiple calls

It was possible for a queue member that is a member of at least 2 or more
queues to receive mulitiple calls at the same time. This happened because
of a race between when a member was being rung and when the device state
notified the other queue(s) member object of the state change.

This patch makes it so when a queue member is being rung it gets added to
a global pool of queue members. If that same member is tried again, e.g.
from another queue, and it is found to already exist in the pending member
container then it will not ring that member.

ASTERISK-16115 #close

Change-Id: Ice45a1c95b9f6f15d8a9fa709c5e5c84ffd29780
---
M apps/app_queue.c
1 file changed, 65 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/79/2679/1

diff --git a/apps/app_queue.c b/apps/app_queue.c
index fa432cb..a984a78 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -1675,6 +1675,33 @@
 	return -1;
 }
 
+/*
+ * A "pool" of member objects that calls are currently pending on. If an
+ * agent is a member of multiple queues it's possible for that agent to be
+ * called by each of the queues at the same time. This happens because device
+ * state is slow to notify the queue app of one of it's member's being rung.
+ * This "pool" allows us to track which members are currently being rung while
+ * we wait on the device state change.
+ */
+static struct ao2_container *pending_members;
+#define MAX_CALL_ATTEMPT_BUCKETS 11
+
+static int pending_members_hash(const void *obj, const int flags)
+{
+	const struct member *object = obj;
+	const char *key = (flags & OBJ_KEY) ? obj : object->interface;
+	return ast_str_hash(key);
+}
+
+static int pending_members_cmp(void *obj, void *arg, int flags)
+{
+	const struct member *object_left = obj;
+	const struct member *object_right = arg;
+	const char *right_key = (flags & OBJ_KEY) ? arg : object_right->interface;
+
+	return strcmp(object_left->interface, right_key) ? 0 : CMP_MATCH | CMP_STOP;
+}
+
 struct statechange {
 	AST_LIST_ENTRY(statechange) entry;
 	int state;
@@ -1689,6 +1716,9 @@
 static int update_status(struct call_queue *q, struct member *m, const int status)
 {
 	m->status = status;
+
+	/* Whatever the status is clear the member from the pending members pool */
+	ao2_find(pending_members, m, OBJ_POINTER | OBJ_NODATA | OBJ_UNLINK);
 
 	if (q->maskmemberstatus) {
 		return 0;
@@ -3662,6 +3692,30 @@
 	}
 
 	if (!call->member->ringinuse) {
+		struct member *member;
+
+		ao2_lock(pending_members);
+
+		member = ao2_find(pending_members, call->member, OBJ_POINTER | OBJ_NOLOCK);
+		if (member) {
+			/*
+			 * If found that means this member is currently being attempted
+			 * from another calling thread, so stop trying from this thread
+			 */
+			ast_debug(1, "%s has another call trying, can't receive call\n",
+				  call->interface);
+			ao2_ref(member, -1);
+			ao2_unlock(pending_members);
+			return 0;
+		}
+
+		/*
+		 * If not found add it to the container so another queue
+		 * won't attempt to call this member at the same time.
+		 */
+		ao2_link(pending_members, call->member);
+		ao2_unlock(pending_members);
+
 		if (member_call_pending_set(call->member)) {
 			ast_debug(1, "%s has another call pending, can't receive call\n",
 				call->interface);
@@ -10084,6 +10138,7 @@
 	}
 	ao2_iterator_destroy(&q_iter);
 	devicestate_tps = ast_taskprocessor_unreference(devicestate_tps);
+	ao2_cleanup(pending_members);
 	ao2_ref(queues, -1);
 	ast_unload_realtime("queue_members");
 	return res;
@@ -10096,6 +10151,16 @@
 	struct ast_config *member_config;
 
 	queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
+	if (!queues) {
+		return AST_MODULE_LOAD_DECLINE;
+	}
+
+	pending_members = ao2_container_alloc(
+		MAX_CALL_ATTEMPT_BUCKETS, pending_members_hash, pending_members_cmp);
+	if (!pending_members) {
+		unload_module();
+		return AST_MODULE_LOAD_DECLINE;
+	}
 
 	use_weight = 0;
 

-- 
To view, visit https://gerrit.asterisk.org/2679
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ice45a1c95b9f6f15d8a9fa709c5e5c84ffd29780
Gerrit-PatchSet: 1
Gerrit-Project: asterisk
Gerrit-Branch: 11
Gerrit-Owner: Kevin Harwell <kharwell at digium.com>



More information about the asterisk-code-review mailing list