[asterisk-commits] irroot: branch irroot/distrotech-customers-trunk r342056 - /team/irroot/distr...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Oct 24 07:33:12 CDT 2011
Author: irroot
Date: Mon Oct 24 07:33:08 2011
New Revision: 342056
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=342056
Log:
Add locking for device states
Modified:
team/irroot/distrotech-customers-trunk/apps/app_queue.c
Modified: team/irroot/distrotech-customers-trunk/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/irroot/distrotech-customers-trunk/apps/app_queue.c?view=diff&rev=342056&r1=342055&r2=342056
==============================================================================
--- team/irroot/distrotech-customers-trunk/apps/app_queue.c (original)
+++ team/irroot/distrotech-customers-trunk/apps/app_queue.c Mon Oct 24 07:33:08 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