[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