[asterisk-commits] irroot: branch irroot/distrotech-customers-1.8 r342058 - in /team/irroot/dist...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Oct 24 07:37:30 CDT 2011


Author: irroot
Date: Mon Oct 24 07:37:27 2011
New Revision: 342058

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=342058
Log:
Add locking for device states

Modified:
    team/irroot/distrotech-customers-1.8/   (props changed)
    team/irroot/distrotech-customers-1.8/apps/app_queue.c

Propchange: team/irroot/distrotech-customers-1.8/
------------------------------------------------------------------------------
    svn:mergeinfo = /team/irroot/distrotech-customers-trunk:342056

Modified: team/irroot/distrotech-customers-1.8/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/irroot/distrotech-customers-1.8/apps/app_queue.c?view=diff&rev=342058&r1=342057&r2=342058
==============================================================================
--- team/irroot/distrotech-customers-1.8/apps/app_queue.c (original)
+++ team/irroot/distrotech-customers-1.8/apps/app_queue.c Mon Oct 24 07:37:27 2011
@@ -1400,15 +1400,17 @@
  * This function checks to see if members are available to be called. If any member
  * is available, the function immediately returns 0. If no members are available,
  * then -1 is returned.
+ *
+ * It must be called with ref and lock held for q
+ *
  */
 static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions)
 {
 	struct member *member;
 	struct ao2_iterator mem_iter;
 
-	ao2_lock(q);
 	mem_iter = ao2_iterator_init(q->members, 0);
-	for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
+	while((member = ao2_iterator_next(&mem_iter))) {
 		if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) {
 			if (conditions & QUEUE_EMPTY_PENALTY) {
 				ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
@@ -1416,6 +1418,7 @@
 			}
 		}
 
+		ao2_lock(member->device);
 		switch (member->device->status) {
 		case AST_DEVICE_INVALID:
 			if (conditions & QUEUE_EMPTY_INVALID) {
@@ -1456,18 +1459,18 @@
 				ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime);
 				break;
 			} else {
-				ao2_unlock(q);
+				ao2_unlock(member->device);
+				ast_debug(4, "%s is available.\n", member->membername);
 				ao2_ref(member, -1);
 				ao2_iterator_destroy(&mem_iter);
-				ast_debug(4, "%s is available.\n", member->membername);
 				return 0;
 			}
 			break;
 		}
+		ao2_unlock(member->device);
+		ao2_ref(member, -1);
 	}
 	ao2_iterator_destroy(&mem_iter);
-
-	ao2_unlock(q);
 	return -1;
 }
 
@@ -1490,7 +1493,9 @@
 		}
 		miter = ao2_iterator_init(q->members, 0);
 		while((m = ao2_iterator_next(&miter))) {
+			ao2_lock(m->device);
 			if (strcmp(m->device->state_interface, s->state_interface)) {
+				ao2_unlock(m->device);
 				ao2_ref(m, -1);
 				continue;
 			}
@@ -1508,6 +1513,7 @@
 				q->name, m->interface, m->membername, s->state_interface, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static",
 				m->penalty, m->calls, (int)m->lastcall, s->status, m->paused
 			);
+			ao2_unlock(m->device);
 			ao2_ref(m, -1);
 		}
 		ao2_iterator_destroy(&miter);
@@ -1533,7 +1539,9 @@
 	}
 
 	if ((s = ao2_find(devices, (char *)device, 0))) {
+		ao2_lock(s);
 		s->status = state;
+		ao2_unlock(s);
 		update_status(s);
 		ao2_ref(s, -1);
 		ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", device, state, ast_devstate2str(state));
@@ -1578,6 +1586,7 @@
 {
 	struct mem_state *s;
 	char *device;
+	int status = extensionstate2devicestate(state);
 
 	if (!asprintf(&device, "hint:%s@%s", exten, context)) {
 		ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
@@ -1585,10 +1594,12 @@
 	}
 
 	if ((s = ao2_find(devices, device, 0))) {
-		s->status = extensionstate2devicestate(state);
+		ao2_lock(s);
+		s->status = status;
+		ao2_unlock(s);
 		update_status(s);
 		ao2_ref(s, -1);
-		ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, s->status, ast_devstate2str(s->status));
+		ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, status, ast_devstate2str(status));
 	} else {
 		ast_debug(3, "Extension '%s@%s' changed state but we don't care because they're not a member of any queue.\n",
 			  exten, context);
@@ -1621,15 +1632,13 @@
 
 	dev_int = ast_strdupa(state_interface);
 	/* ref will be held for each shared member and one ref for container */
-	if (!(state = ao2_find(devices, dev_int, 0))) {
-		if ((state = ao2_alloc(sizeof(*state), NULL))) {
-			ao2_link(devices, state);
-			state->reserved = 0;
-		} else {
-			return NULL;
-		}
-	}
-
+	if ((state = ao2_find(devices, dev_int, 0))) {
+		return state;
+	} else  if (!(state = ao2_alloc(sizeof(*state), NULL))) {
+		return NULL;
+	}
+
+	state->reserved = 0;
 	if (!strncmp(dev_int, "hint:", 5)) {
 		context = ast_strdupa(dev_int);
 		exten = strsep(&context, "@") + 5;
@@ -1645,6 +1654,7 @@
 		ast_copy_string(state->state_interface, dev_int, sizeof(state->state_interface));
 		state->status = ast_device_state(state->state_interface);
 	}
+	ao2_link(devices, state);
 
 	return state;
 }
@@ -2566,9 +2576,9 @@
 			return res;
 		}
 	}
-	if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen))
+	if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) {
 		*reason = QUEUE_FULL;
-	else if (*reason == QUEUE_UNKNOWN) {
+	} else if (*reason == QUEUE_UNKNOWN) {
 		/* There's space for us, put us at the right position inside
 		 * the queue.
 		 * Take into account the priority of the calling user */
@@ -2926,7 +2936,9 @@
  */
 static void callattempt_free(struct callattempt *doomed)
 {
+	ao2_lock(doomed->member->device);
 	doomed->member->device->reserved--;
+	ao2_unlock(doomed->member->device);
 	if (doomed->member) {
 		ao2_ref(doomed->member, -1);
 	}
@@ -2970,6 +2982,7 @@
 
 	mem_iter = ao2_iterator_init(q->members, 0);
 	while ((mem = ao2_iterator_next(&mem_iter))) {
+		ao2_lock(mem->device);
 		switch (mem->device->status) {
 			case AST_DEVICE_INVALID:
 			case AST_DEVICE_UNAVAILABLE:
@@ -2993,6 +3006,7 @@
 				avl++;
 				break;
 		}
+		ao2_unlock(mem->device);
 		ao2_ref(mem, -1);
 
 		/* If autofill is not enabled or if the queue's strategy is ringall, then
@@ -3142,14 +3156,17 @@
 	}
 
 	if (!qe->parent->ringinuse || !tmp->member->ignorebusy) {
+		ao2_lock(s);
 		if ((s->reserved > 1) || ((s->status != AST_DEVICE_NOT_INUSE) && (s->status != AST_DEVICE_UNKNOWN))) {
 			ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
 			if (qe->chan->cdr) {
 				ast_cdr_busy(qe->chan->cdr);
 			}
 			tmp->stillgoing = 0;
+			ao2_unlock(s);
 			return 0;
 		}
+		ao2_unlock(s);
 	}
 
 	if (use_weight && compare_weight(qe->parent,tmp->member)) {
@@ -4072,11 +4089,15 @@
 		if (qe->parent->leavewhenempty) {
 			int status = 0;
 
+			ao2_lock(qe->parent);
 			if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty))) {
 				*reason = QUEUE_LEAVEEMPTY;
 				ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
+				ao2_unlock(qe->parent);
 				leave_queue(qe);
 				break;
+			} else {
+				ao2_unlock(qe->parent);
 			}
 		}
 
@@ -4650,7 +4671,9 @@
 
 		tmp->stillgoing = -1;
 		tmp->member = cur;/* Place the reference for cur into callattempt. */
+		ao2_lock(tmp->member->device);
 		tmp->member->device->reserved++;
+		ao2_unlock(tmp->member->device);
 		tmp->lastcall = cur->lastcall;
 		tmp->lastqueue = cur->lastqueue;
 		ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
@@ -5363,6 +5386,7 @@
 			new_member->dynamic = 1;
 			ao2_link(q->members, new_member);
 			q->membercount++;
+			ao2_lock(new_member->device);
 			manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
 				"Queue: %s\r\n"
 				"Location: %s\r\n"
@@ -5379,6 +5403,7 @@
 				new_member->penalty, new_member->calls, (int) new_member->lastcall,
 				new_member->device->status, new_member->paused);
 
+			ao2_unlock(new_member->device);
 			ao2_ref(new_member, -1);
 			new_member = NULL;
 
@@ -6122,12 +6147,16 @@
 
 		if (qe.parent->leavewhenempty) {
 			int status = 0;
+			ao2_lock(qe.parent);
 			if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.parent->leavewhenempty))) {
-				record_abandoned(&qe);
 				reason = QUEUE_LEAVEEMPTY;
 				ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
+				ao2_unlock(qe.parent);
+				record_abandoned(&qe);
 				res = 0;
 				break;
+			} else {
+				ao2_unlock(qe.parent);
 			}
 		}
 
@@ -6317,9 +6346,11 @@
 			mem_iter = ao2_iterator_init(q->members, 0);
 			while ((m = ao2_iterator_next(&mem_iter))) {
 				/* Count the agents who are logged in and presently answering calls */
+				ao2_lock(m->device);
 				if ((m->device->status != AST_DEVICE_UNAVAILABLE) && (m->device->status != AST_DEVICE_INVALID)) {
 					count++;
 				}
+				ao2_unlock(m->device);
 				ao2_ref(m, -1);
 			}
 			ao2_iterator_destroy(&mem_iter);
@@ -6327,9 +6358,11 @@
 			mem_iter = ao2_iterator_init(q->members, 0);
 			while ((m = ao2_iterator_next(&mem_iter))) {
 				/* Count the agents who are logged in and presently answering calls */
+				ao2_lock(m->device);
 				if ((m->device->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
 					count++;
 				}
+				ao2_unlock(m->device);
 				ao2_ref(m, -1);
 			}
 			ao2_iterator_destroy(&mem_iter);
@@ -6339,10 +6372,12 @@
 			mem_iter = ao2_iterator_init(q->members, 0);
 			while ((m = ao2_iterator_next(&mem_iter))) {
 				/* Count the agents who are logged in, not paused and not wrapping up */
+				ao2_lock(m->device);
 				if ((m->device->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
 						!(m->lastcall && q->wrapuptime && ((now - q->wrapuptime) < m->lastcall))) {
 					count++;
 				}
+				ao2_unlock(m->device);
 				ao2_ref(m, -1);
 			}
 			ao2_iterator_destroy(&mem_iter);
@@ -6478,9 +6513,11 @@
 		mem_iter = ao2_iterator_init(q->members, 0);
 		while ((m = ao2_iterator_next(&mem_iter))) {
 			/* Count the agents who are logged in and presently answering calls */
+			ao2_lock(m->device);
 			if ((m->device->status != AST_DEVICE_UNAVAILABLE) && (m->device->status != AST_DEVICE_INVALID)) {
 				count++;
 			}
+			ao2_unlock(m->device);
 			ao2_ref(m, -1);
 		}
 		ao2_iterator_destroy(&mem_iter);
@@ -7221,11 +7258,14 @@
 				if (mem->penalty) {
 					ast_str_append(&out, 0, " with penalty %d", mem->penalty);
 				}
+				ao2_lock(mem->device);
 				ast_str_append(&out, 0, "%s%s%s (%s)",
 					mem->dynamic ? " (dynamic)" : "",
 					mem->realtime ? " (realtime)" : "",
 					mem->paused ? " (paused)" : "",
 					ast_devstate2str(mem->device->status));
+				ao2_unlock(mem->device);
+
 				if (mem->calls) {
 					ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
 						mem->calls, (long) (time(NULL) - mem->lastcall));
@@ -7396,12 +7436,14 @@
 			/* List Queue Members */
 			mem_iter = ao2_iterator_init(q->members, 0);
 			while ((mem = ao2_iterator_next(&mem_iter))) {
+				ao2_lock(mem->device);
 				if ((mem->device->status != AST_DEVICE_UNAVAILABLE) && (mem->device->status != AST_DEVICE_INVALID)) {
 					++qmemcount;
 					if (((mem->device->status == AST_DEVICE_NOT_INUSE) || (mem->device->status == AST_DEVICE_UNKNOWN)) && !(mem->paused)) {
 						++qmemavail;
 					}
 				}
+				ao2_unlock(mem->device);
 				ao2_ref(mem, -1);
 			}
 			ao2_iterator_destroy(&mem_iter);
@@ -7483,6 +7525,7 @@
 			mem_iter = ao2_iterator_init(q->members, 0);
 			while ((mem = ao2_iterator_next(&mem_iter))) {
 				if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
+					ao2_lock(mem->device);
 					astman_append(s, "Event: QueueMember\r\n"
 						"Queue: %s\r\n"
 						"Name: %s\r\n"
@@ -7498,6 +7541,7 @@
 						"\r\n",
 						q->name, mem->membername, mem->interface, mem->device->state_interface, mem->dynamic ? "dynamic" : "static",
 						mem->penalty, mem->calls, (int)mem->lastcall, mem->device->status, mem->paused, idText);
+					ao2_unlock(mem->device);
 				}
 				ao2_ref(mem, -1);
 			}




More information about the asterisk-commits mailing list