[asterisk-commits] mmichelson: branch mmichelson/queue_refcount r80876 - /team/mmichelson/queue_...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Aug 24 16:57:28 CDT 2007
Author: mmichelson
Date: Fri Aug 24 16:57:28 2007
New Revision: 80876
URL: http://svn.digium.com/view/asterisk?view=rev&rev=80876
Log:
Queues are now implemented using ao2_containers and are refcounted. Small-scale local tests show that this
works, but I'll need to test a LOT more before I think about putting this into a branch.
Modified:
team/mmichelson/queue_refcount/apps/app_queue.c
Modified: team/mmichelson/queue_refcount/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/team/mmichelson/queue_refcount/apps/app_queue.c?view=diff&rev=80876&r1=80875&r2=80876
==============================================================================
--- team/mmichelson/queue_refcount/apps/app_queue.c (original)
+++ team/mmichelson/queue_refcount/apps/app_queue.c Fri Aug 24 16:57:28 2007
@@ -92,6 +92,7 @@
#include "asterisk/astdb.h"
#include "asterisk/devicestate.h"
#include "asterisk/stringfields.h"
+#include "asterisk/astobj2.h"
enum {
QUEUE_STRATEGY_RINGALL = 0,
@@ -123,6 +124,8 @@
#define RES_EXISTS (-1) /* Entry already exists */
#define RES_OUTOFMEMORY (-2) /* Out of memory */
#define RES_NOSUCHQUEUE (-3) /* No such queue */
+
+#define MAX_QUEUE_BUCKETS 17
static char *app = "Queue";
@@ -398,10 +401,9 @@
struct member *members; /*!< Head of the list of members */
int membercount; /*!< Number of members in queue */
struct queue_ent *head; /*!< Head of the list of callers */
- AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */
};
-static AST_LIST_HEAD_STATIC(queues, call_queue);
+static ao2_container *queues;
static int set_member_paused(const char *queuename, const char *interface, int paused);
@@ -450,6 +452,19 @@
return -1;
}
+
+static int queue_hash_cb(const void *obj, const int flags)
+{
+ const struct call_queue *q = obj;
+ return ast_str_hash(q->name);
+}
+
+static int queue_cmp_cb(void *obj, void *arg, int flags)
+{
+ struct call_queue *q = obj, *q2 = arg;
+ return !strcasecmp(q->name, q2->name) ? CMP_MATCH : 0;
+}
+
/*! \brief Insert the 'new' 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)
@@ -519,6 +534,7 @@
struct member_interface *curint;
char *loc;
char *technology;
+ ao2_iterator i;
technology = ast_strdupa(sc->dev);
loc = strchr(technology, '/');
@@ -552,8 +568,8 @@
if (option_debug)
ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
- AST_LIST_LOCK(&queues);
- AST_LIST_TRAVERSE(&queues, q, list) {
+ i = ao2_iterator_init(queues, 0);
+ while((q = ao2_iterator_next(&i))) {
ast_mutex_lock(&q->lock);
for (cur = q->members; cur; cur = cur->next) {
char *interface;
@@ -563,13 +579,17 @@
if ((slash_pos = strchr(slash_pos + 1, '/')))
*slash_pos = '\0';
- if (strcasecmp(sc->dev, interface))
+ if (strcasecmp(sc->dev, interface)) {
+ ao2_ref(q, -1);
continue;
+ }
if (cur->status != sc->state) {
cur->status = sc->state;
- if (q->maskmemberstatus)
+ if (q->maskmemberstatus) {
+ ao2_ref(q, -1);
continue;
+ }
manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
"Queue: %s\r\n"
@@ -586,8 +606,8 @@
}
}
ast_mutex_unlock(&q->lock);
- }
- AST_LIST_UNLOCK(&queues);
+ ao2_ref(q, -1);
+ }
free(sc);
@@ -633,17 +653,6 @@
}
return cur;
-}
-
-static struct call_queue *alloc_queue(const char *queuename)
-{
- struct call_queue *q;
-
- if ((q = ast_calloc(1, sizeof(*q)))) {
- ast_mutex_init(&q->lock);
- ast_copy_string(q->name, queuename, sizeof(q->name));
- }
- return q;
}
static void init_queue(struct call_queue *q)
@@ -724,19 +733,22 @@
struct call_queue *q;
struct member *mem;
int ret = 0;
-
- AST_LIST_LOCK(&queues);
- AST_LIST_TRAVERSE(&queues, q, list) {
+ ao2_iterator i;
+
+ i = ao2_iterator_init(queues, 0);
+ while((q = ao2_iterator_next(&i))) {
ast_mutex_lock(&q->lock);
for (mem = q->members; mem && !ret; mem = mem->next) {
if (!strcasecmp(interface, mem->interface))
ret = 1;
}
ast_mutex_unlock(&q->lock);
- if (ret)
+ if (ret) {
+ ao2_ref(q, -1);
break;
- }
- AST_LIST_UNLOCK(&queues);
+ }
+ ao2_ref(q, -1);
+ }
return ret;
}
@@ -990,11 +1002,22 @@
}
}
-static void destroy_queue(struct call_queue *q)
-{
+static void destroy_queue(void *obj)
+{
+ struct call_queue *q = obj;
free_members(q, 1);
ast_mutex_destroy(&q->lock);
- free(q);
+}
+
+static struct call_queue *alloc_queue(const char *queuename)
+{
+ struct call_queue *q;
+
+ if ((q = ao2_alloc(sizeof(*q), destroy_queue))) {
+ ast_mutex_init(&q->lock);
+ ast_copy_string(q->name, queuename, sizeof(q->name));
+ }
+ return q;
}
/*!\brief Reload a single queue via realtime.
@@ -1003,17 +1026,18 @@
static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
{
struct ast_variable *v;
- struct call_queue *q;
+ struct call_queue *q = NULL;
+ struct call_queue tmpq;
struct member *m, *prev_m, *next_m;
char *interface = NULL;
char *tmp, *tmp_name;
char tmpbuf[64]; /* Must be longer than the longest queue param name. */
+ ast_copy_string(tmpq.name, queuename, sizeof(tmpq.name));
+
/* Find the queue in the in-core list (we will create a new one if not found). */
- AST_LIST_TRAVERSE(&queues, q, list) {
- if (!strcasecmp(q->name, queuename))
- break;
- }
+
+ q = ao2_find(queues, &tmpq, OBJ_POINTER);
/* Static queues override realtime. */
if (q) {
@@ -1021,6 +1045,7 @@
if (!q->realtime) {
if (q->dead) {
ast_mutex_unlock(&q->lock);
+ ao2_ref(q, -1);
return NULL;
} else {
ast_mutex_unlock(&q->lock);
@@ -1044,9 +1069,12 @@
/* Delete if unused (else will be deleted when last caller leaves). */
if (!q->count) {
/* Delete. */
- AST_LIST_REMOVE(&queues, q, list);
ast_mutex_unlock(&q->lock);
- destroy_queue(q);
+ usleep(1);
+ ast_mutex_lock(&q->lock);
+ ast_mutex_unlock(&q->lock);
+ ao2_unlink(queues, q);
+ ao2_ref(q, -1);
} else
ast_mutex_unlock(&q->lock);
}
@@ -1060,7 +1088,7 @@
ast_mutex_lock(&q->lock);
clear_queue(q);
q->realtime = 1;
- AST_LIST_INSERT_HEAD(&queues, q, list);
+ ao2_link(queues, q);
}
init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
@@ -1175,16 +1203,13 @@
{
struct ast_variable *queue_vars;
struct ast_config *member_config = NULL;
- struct call_queue *q;
+ struct call_queue tmpq;
+ struct call_queue *q = NULL;
+
+ ast_copy_string(tmpq.name, queuename, sizeof(tmpq.name));
/* Find the queue in the in-core list first. */
- AST_LIST_LOCK(&queues);
- AST_LIST_TRAVERSE(&queues, q, list) {
- if (!strcasecmp(q->name, queuename)) {
- break;
- }
- }
- AST_LIST_UNLOCK(&queues);
+ q = ao2_find(queues, &tmpq, OBJ_POINTER);
if (!q || q->realtime) {
/*! \note Load from realtime before taking the global qlock, to avoid blocking all
@@ -1205,15 +1230,12 @@
}
}
- AST_LIST_LOCK(&queues);
-
q = find_queue_by_name_rt(queuename, queue_vars, member_config);
if (member_config)
ast_config_destroy(member_config);
if (queue_vars)
ast_variables_destroy(queue_vars);
- AST_LIST_UNLOCK(&queues);
} else {
update_realtime_members(q);
}
@@ -1232,7 +1254,7 @@
if (!(q = load_realtime_queue(queuename)))
return res;
- AST_LIST_LOCK(&queues);
+ ao2_lock(queues);
ast_mutex_lock(&q->lock);
/* This is our one */
@@ -1280,7 +1302,7 @@
ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
}
ast_mutex_unlock(&q->lock);
- AST_LIST_UNLOCK(&queues);
+ ao2_unlock(queues);
return res;
}
@@ -1463,6 +1485,7 @@
if (!(q = qe->parent))
return;
+ ao2_ref(q, 1);
ast_mutex_lock(&q->lock);
prev = NULL;
@@ -1491,10 +1514,8 @@
if (q->dead && !q->count) {
/* It's dead and nobody is in it, so kill it */
- AST_LIST_LOCK(&queues);
- AST_LIST_REMOVE(&queues, q, list);
- AST_LIST_UNLOCK(&queues);
- destroy_queue(q);
+ ao2_unlink(queues, q);
+ ao2_ref(q, -1);
}
}
@@ -1564,29 +1585,39 @@
struct call_queue *q;
struct member *mem;
int found = 0;
+ ao2_iterator i;
/* &qlock and &rq->lock already set by try_calling()
* to solve deadlock */
- AST_LIST_TRAVERSE(&queues, q, list) {
- if (q == rq) /* don't check myself, could deadlock */
+ i = ao2_iterator_init(queues, 0);
+ while ((q = ao2_iterator_next(&i))) {
+ if (q == rq) { /* don't check myself, could deadlock */
+ ao2_ref(q, -1);
continue;
+ }
ast_mutex_lock(&q->lock);
if (q->count && q->members) {
for (mem = q->members; mem; mem = mem->next) {
- if (strcmp(mem->interface, member->interface))
+ if (strcmp(mem->interface, member->interface)) {
+ ao2_ref(q, -1);
continue;
+ }
ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
if (q->weight > rq->weight) {
ast_log(LOG_DEBUG, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, q->count, rq->name, rq->weight, rq->count);
found = 1;
+ ao2_ref(q, -1);
break;
}
}
}
ast_mutex_unlock(&q->lock);
- if (found)
+ if (found) {
+ ao2_ref(q, -1);
break;
+ }
+ ao2_ref(q, -1);
}
return found;
}
@@ -2421,7 +2452,7 @@
/* Hold the lock while we setup the outgoing calls */
if (use_weight)
- AST_LIST_LOCK(&queues);
+ ao2_lock(queues);
ast_mutex_lock(&qe->parent->lock);
if (option_debug)
ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
@@ -2439,7 +2470,7 @@
if (!tmp) {
ast_mutex_unlock(&qe->parent->lock);
if (use_weight)
- AST_LIST_UNLOCK(&queues);
+ ao2_unlock(queues);
goto out;
}
tmp->stillgoing = -1;
@@ -2469,7 +2500,7 @@
ring_one(qe, outgoing, &numbusies);
ast_mutex_unlock(&qe->parent->lock);
if (use_weight)
- AST_LIST_UNLOCK(&queues);
+ ao2_unlock(queues);
lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
ast_mutex_lock(&qe->parent->lock);
if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
@@ -2828,54 +2859,50 @@
static int remove_from_queue(const char *queuename, const char *interface)
{
struct call_queue *q;
+ struct call_queue tmpq;
struct member *last_member, *look;
int res = RES_NOSUCHQUEUE;
- AST_LIST_LOCK(&queues);
- AST_LIST_TRAVERSE(&queues, q, list) {
- ast_mutex_lock(&q->lock);
- if (strcmp(q->name, queuename)) {
- ast_mutex_unlock(&q->lock);
- continue;
- }
-
- if ((last_member = interface_exists(q, interface))) {
- if ((look = q->members) == last_member) {
- q->members = last_member->next;
- q->membercount--;
- } else {
- while (look != NULL) {
- if (look->next == last_member) {
- look->next = last_member->next;
- q->membercount--;
- break;
- } else {
- look = look->next;
- }
+ ast_copy_string(tmpq.name, queuename, sizeof(tmpq.name));
+
+ q = ao2_find(queues, &tmpq, OBJ_POINTER);
+ ast_mutex_lock(&q->lock);
+
+ if ((last_member = interface_exists(q, interface))) {
+ if ((look = q->members) == last_member) {
+ q->members = last_member->next;
+ q->membercount--;
+ } else {
+ while (look != NULL) {
+ if (look->next == last_member) {
+ look->next = last_member->next;
+ q->membercount--;
+ break;
+ } else {
+ look = look->next;
}
}
- manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
- "Queue: %s\r\n"
- "Location: %s\r\n"
- "MemberName: %s\r\n",
- q->name, last_member->interface, last_member->membername);
- free(last_member);
-
- if (queue_persistent_members)
- dump_queue_members(q);
-
- res = RES_OKAY;
- } else {
- res = RES_EXISTS;
- }
- ast_mutex_unlock(&q->lock);
- break;
- }
+ }
+ manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
+ "Queue: %s\r\n"
+ "Location: %s\r\n"
+ "MemberName: %s\r\n",
+ q->name, last_member->interface, last_member->membername);
+ free(last_member);
+
+ if (queue_persistent_members)
+ dump_queue_members(q);
+
+ res = RES_OKAY;
+ } else {
+ res = RES_EXISTS;
+ }
+ ast_mutex_unlock(&q->lock);
+ ao2_ref(q, -1);
if (res == RES_OKAY)
remove_from_interfaces(interface);
- AST_LIST_UNLOCK(&queues);
return res;
}
@@ -2892,8 +2919,7 @@
if (!(q = load_realtime_queue(queuename)))
return res;
- AST_LIST_LOCK(&queues);
-
+ ao2_lock(queues);
ast_mutex_lock(&q->lock);
if (interface_exists(q, interface) == NULL) {
add_to_interfaces(interface);
@@ -2928,7 +2954,7 @@
res = RES_EXISTS;
}
ast_mutex_unlock(&q->lock);
- AST_LIST_UNLOCK(&queues);
+ ao2_unlock(queues);
return res;
}
@@ -2938,14 +2964,15 @@
int found = 0;
struct call_queue *q;
struct member *mem;
+ ao2_iterator i;
/* Special event for when all queues are paused - individual events still generated */
/* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
if (ast_strlen_zero(queuename))
ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
- AST_LIST_LOCK(&queues);
- AST_LIST_TRAVERSE(&queues, q, list) {
+ i = ao2_iterator_init(queues, 0);
+ while ((q = ao2_iterator_next(&i))) {
ast_mutex_lock(&q->lock);
if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
if ((mem = interface_exists(q, interface))) {
@@ -2968,8 +2995,8 @@
}
}
ast_mutex_unlock(&q->lock);
- }
- AST_LIST_UNLOCK(&queues);
+ ao2_ref(q, -1);
+ }
return found ? RESULT_SUCCESS : RESULT_FAILURE;
}
@@ -2989,22 +3016,18 @@
struct ast_db_entry *db_tree;
struct ast_db_entry *entry;
struct call_queue *cur_queue;
+ struct call_queue tmpq;
char queue_data[PM_MAX_LEN];
- AST_LIST_LOCK(&queues);
-
+ ao2_lock(queues);
/* Each key in 'pm_family' is the name of a queue */
db_tree = ast_db_gettree(pm_family, NULL);
for (entry = db_tree; entry; entry = entry->next) {
queue_name = entry->key + strlen(pm_family) + 2;
-
- AST_LIST_TRAVERSE(&queues, cur_queue, list) {
- ast_mutex_lock(&cur_queue->lock);
- if (!strcmp(queue_name, cur_queue->name))
- break;
- ast_mutex_unlock(&cur_queue->lock);
- }
+ ast_copy_string(tmpq.name, queue_name, sizeof(tmpq.name));
+
+ cur_queue = ao2_find(queues, &tmpq, OBJ_POINTER);
if (!cur_queue)
cur_queue = load_realtime_queue(queue_name);
@@ -3015,8 +3038,7 @@
ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
ast_db_del(pm_family, queue_name);
continue;
- } else
- ast_mutex_unlock(&cur_queue->lock);
+ }
if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
continue;
@@ -3063,7 +3085,7 @@
}
}
- AST_LIST_UNLOCK(&queues);
+ ao2_unlock(queues);
if (db_tree) {
ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
ast_db_freetree(db_tree);
@@ -3596,6 +3618,9 @@
set_queue_result(chan, reason);
res = 0;
}
+
+ if(qe.parent)
+ ao2_ref(qe.parent, -1);
ast_module_user_remove(lu);
return res;
@@ -3605,6 +3630,7 @@
{
int count = 0;
struct call_queue *q;
+ struct call_queue tmpq;
struct ast_module_user *lu;
buf[0] = '\0';
@@ -3614,20 +3640,16 @@
return -1;
}
+ ast_copy_string(tmpq.name, data, sizeof(tmpq.name));
+
lu = ast_module_user_add(chan);
- AST_LIST_LOCK(&queues);
- AST_LIST_TRAVERSE(&queues, q, list) {
- if (!strcasecmp(q->name, data)) {
- ast_mutex_lock(&q->lock);
- break;
- }
- }
- AST_LIST_UNLOCK(&queues);
+ q = ao2_find(queues, &tmpq, OBJ_POINTER);
if (q) {
count = q->membercount;
ast_mutex_unlock(&q->lock);
+ ao2_ref(q, -1);
} else
ast_log(LOG_WARNING, "queue %s was not found\n", data);
@@ -3641,6 +3663,7 @@
{
int count = 0;
struct call_queue *q;
+ struct call_queue tmpq;
struct ast_module_user *lu;
buf[0] = '\0';
@@ -3650,20 +3673,16 @@
return -1;
}
+ ast_copy_string(tmpq.name, data, sizeof(tmpq.name));
+
lu = ast_module_user_add(chan);
- AST_LIST_LOCK(&queues);
- AST_LIST_TRAVERSE(&queues, q, list) {
- if (!strcasecmp(q->name, data)) {
- ast_mutex_lock(&q->lock);
- break;
- }
- }
- AST_LIST_UNLOCK(&queues);
+ q = ao2_find(queues, &tmpq, OBJ_POINTER);
if (q) {
count = q->count;
ast_mutex_unlock(&q->lock);
+ ao2_ref(q, -1);
} else
ast_log(LOG_WARNING, "queue %s was not found\n", data);
@@ -3676,6 +3695,7 @@
{
struct ast_module_user *u;
struct call_queue *q;
+ struct call_queue tmpq;
struct member *m;
/* Ensure an otherwise empty list doesn't return garbage */
@@ -3685,17 +3705,11 @@
ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
return -1;
}
-
+
+ ast_copy_string(tmpq.name, data, sizeof(tmpq.name));
u = ast_module_user_add(chan);
- AST_LIST_LOCK(&queues);
- AST_LIST_TRAVERSE(&queues, q, list) {
- if (!strcasecmp(q->name, data)) {
- ast_mutex_lock(&q->lock);
- break;
- }
- }
- AST_LIST_UNLOCK(&queues);
+ q = ao2_find(queues, &tmpq, OBJ_POINTER);
if (q) {
int buflen = 0, count = 0;
@@ -3715,6 +3729,7 @@
}
}
ast_mutex_unlock(&q->lock);
+ ao2_ref(q, -1);
} else
ast_log(LOG_WARNING, "queue %s was not found\n", data);
@@ -3765,6 +3780,7 @@
static int reload_queues(void)
{
struct call_queue *q;
+ struct call_queue tmpq;
struct ast_config *cfg;
char *cat, *tmp;
struct ast_variable *var;
@@ -3775,6 +3791,7 @@
char *interface;
char *membername;
int penalty;
+ ao2_iterator i;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(interface);
AST_APP_ARG(penalty);
@@ -3785,11 +3802,13 @@
ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
return 0;
}
- AST_LIST_LOCK(&queues);
use_weight=0;
/* Mark all queues as dead for the moment */
- AST_LIST_TRAVERSE(&queues, q, list)
+ i = ao2_iterator_init(queues, 0);
+ while((q = ao2_iterator_next(&i))) {
q->dead = 1;
+ ao2_ref(q, -1);
+ }
/* Chug through config file */
cat = NULL;
@@ -3808,10 +3827,8 @@
montype_default = 1;
} else { /* Define queue */
/* Look for an existing one */
- AST_LIST_TRAVERSE(&queues, q, list) {
- if (!strcmp(q->name, cat))
- break;
- }
+ ast_copy_string(tmpq.name, cat, sizeof(tmpq.name));
+ q = ao2_find(queues, &tmpq, OBJ_POINTER);
if (!q) {
/* Make one then */
if (!(q = alloc_queue(cat))) {
@@ -3910,18 +3927,20 @@
rr_dep_warning();
if (new) {
- AST_LIST_INSERT_HEAD(&queues, q, list);
+ ao2_link(queues, q);
} else
ast_mutex_unlock(&q->lock);
}
}
}
ast_config_destroy(cfg);
- AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) {
+ i = ao2_iterator_init(queues,0);
+ while ((q = ao2_iterator_next(&i))) {
if (q->dead) {
- AST_LIST_REMOVE_CURRENT(&queues, list);
- if (!q->count)
- destroy_queue(q);
+ ao2_unlink(queues, q);
+ if (!q->count) {
+ ao2_ref(q, -1);
+ }
else
ast_log(LOG_DEBUG, "XXX Leaking a little memory :( XXX\n");
} else {
@@ -3930,26 +3949,102 @@
cur->status = ast_device_state(cur->interface);
ast_mutex_unlock(&q->lock);
}
- }
- AST_LIST_TRAVERSE_SAFE_END;
- AST_LIST_UNLOCK(&queues);
+ ao2_ref(q, -1);
+ }
return 1;
}
-static int __queues_show(struct mansession *s, int manager, int fd, int argc, char **argv)
-{
- struct call_queue *q;
- struct queue_ent *qe;
- struct member *mem;
- int pos, queue_show;
- time_t now;
+static void show(struct call_queue *q, int fd, char **argv, struct mansession *s, char *term)
+{
char max_buf[80];
char *max;
size_t max_left;
- float sl = 0;
+ float sl;
+ time_t now;
+ struct queue_ent *qe;
+ struct member *mem;
+ int pos;
+
+ max_buf[0] = '\0';
+ max = max_buf;
+ max_left = sizeof(max_buf);
+ if (q->maxlen)
+ ast_build_string(&max, &max_left, "%d", q->maxlen);
+ else
+ ast_build_string(&max, &max_left, "unlimited");
+ sl = 0;
+ if (q->callscompleted > 0)
+ sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
+ if (s)
+ astman_append(s, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
+ q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight,
+ q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
+ else
+ ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
+ q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
+ if (q->members) {
+ if (s)
+ astman_append(s, " Members: %s", term);
+ else
+ ast_cli(fd, " Members: %s", term);
+ for (mem = q->members; mem; mem = mem->next) {
+ max_buf[0] = '\0';
+ max = max_buf;
+ max_left = sizeof(max_buf);
+ if (mem->penalty)
+ ast_build_string(&max, &max_left, " with penalty %d", mem->penalty);
+ if (mem->dynamic)
+ ast_build_string(&max, &max_left, " (dynamic)");
+ if (mem->paused)
+ ast_build_string(&max, &max_left, " (paused)");
+ ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status));
+ if (mem->calls) {
+ ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)",
+ mem->calls, (long) (time(NULL) - mem->lastcall));
+ } else
+ ast_build_string(&max, &max_left, " has taken no calls yet");
+ if (s)
+ astman_append(s, " %s%s%s", mem->interface, max_buf, term);
+ else
+ ast_cli(fd, " %s%s%s", mem->interface, max_buf, term);
+ }
+ } else if (s)
+ astman_append(s, " No Members%s", term);
+ else
+ ast_cli(fd, " No Members%s", term);
+ if (q->head) {
+ pos = 1;
+ if (s)
+ astman_append(s, " Callers: %s", term);
+ else
+ ast_cli(fd, " Callers: %s", term);
+ for (qe = q->head; qe; qe = qe->next) {
+ if (s)
+ astman_append(s, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s",
+ pos++, qe->chan->name, (long) (now - qe->start) / 60,
+ (long) (now - qe->start) % 60, qe->prio, term);
+ else
+ ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++,
+ qe->chan->name, (long) (now - qe->start) / 60,
+ (long) (now - qe->start) % 60, qe->prio, term);
+ }
+ } else if (s)
+ astman_append(s, " No Callers%s", term);
+ else
+ ast_cli(fd, " No Callers%s", term);
+ if (s)
+ astman_append(s, "%s", term);
+ else
+ ast_cli(fd, "%s", term);
+}
+
+static int __queues_show(struct mansession *s, int manager, int fd, int argc, char **argv)
+{
+ struct call_queue *q;
+ int queue_show;
char *term = manager ? "\r\n" : "\n";
-
- time(&now);
+ ao2_iterator i;
+
if (argc == 2)
queue_show = 0;
else if (argc == 3)
@@ -3961,9 +4056,9 @@
if (queue_show)
load_realtime_queue(argv[2]);
- AST_LIST_LOCK(&queues);
- if (AST_LIST_EMPTY(&queues)) {
- AST_LIST_UNLOCK(&queues);
+ ao2_lock(queues);
+ if (!ao2_container_count(queues)) {
+ ao2_unlock(queues);
if (queue_show) {
if (s)
astman_append(s, "No such queue: %s.%s",argv[2], term);
@@ -3977,94 +4072,26 @@
}
return RESULT_SUCCESS;
}
- AST_LIST_TRAVERSE(&queues, q, list) {
- ast_mutex_lock(&q->lock);
- if (queue_show) {
- if (strcasecmp(q->name, argv[2]) != 0) {
- ast_mutex_unlock(&q->lock);
- if (!AST_LIST_NEXT(q, list)) {
- ast_cli(fd, "No such queue: %s.%s",argv[2], term);
- break;
- }
- continue;
- }
- }
- max_buf[0] = '\0';
- max = max_buf;
- max_left = sizeof(max_buf);
- if (q->maxlen)
- ast_build_string(&max, &max_left, "%d", q->maxlen);
- else
- ast_build_string(&max, &max_left, "unlimited");
- sl = 0;
- if (q->callscompleted > 0)
- sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
- if (s)
- astman_append(s, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
- q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight,
- q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
- else
- ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
- q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
- if (q->members) {
- if (s)
- astman_append(s, " Members: %s", term);
- else
- ast_cli(fd, " Members: %s", term);
- for (mem = q->members; mem; mem = mem->next) {
- max_buf[0] = '\0';
- max = max_buf;
- max_left = sizeof(max_buf);
- if (mem->penalty)
- ast_build_string(&max, &max_left, " with penalty %d", mem->penalty);
- if (mem->dynamic)
- ast_build_string(&max, &max_left, " (dynamic)");
- if (mem->paused)
- ast_build_string(&max, &max_left, " (paused)");
- ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status));
- if (mem->calls) {
- ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)",
- mem->calls, (long) (time(NULL) - mem->lastcall));
- } else
- ast_build_string(&max, &max_left, " has taken no calls yet");
- if (s)
- astman_append(s, " %s%s%s", mem->interface, max_buf, term);
- else
- ast_cli(fd, " %s%s%s", mem->interface, max_buf, term);
- }
- } else if (s)
- astman_append(s, " No Members%s", term);
- else
- ast_cli(fd, " No Members%s", term);
- if (q->head) {
- pos = 1;
- if (s)
- astman_append(s, " Callers: %s", term);
- else
- ast_cli(fd, " Callers: %s", term);
- for (qe = q->head; qe; qe = qe->next) {
- if (s)
- astman_append(s, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s",
- pos++, qe->chan->name, (long) (now - qe->start) / 60,
- (long) (now - qe->start) % 60, qe->prio, term);
- else
- ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++,
- qe->chan->name, (long) (now - qe->start) / 60,
- (long) (now - qe->start) % 60, qe->prio, term);
- }
- } else if (s)
- astman_append(s, " No Callers%s", term);
- else
- ast_cli(fd, " No Callers%s", term);
- if (s)
- astman_append(s, "%s", term);
- else
- ast_cli(fd, "%s", term);
- ast_mutex_unlock(&q->lock);
- if (queue_show)
- break;
- }
- AST_LIST_UNLOCK(&queues);
+ ao2_unlock(queues);
+
+ if(queue_show) {
+ struct call_queue tmpq;
+ ast_copy_string(tmpq.name, argv[2], sizeof(tmpq.name));
+ if(!(q = ao2_find(queues, &tmpq, OBJ_POINTER)))
+ ast_cli(fd, "No such queue: %s.%s", argv[2], term);
+ else {
+ show(q, fd, argv, s, term);
+ ao2_ref(q, -1);
+ }
+ } else {
+ i = ao2_iterator_init(queues, 0);
+ while ((q = ao2_iterator_next(&i))) {
+ ast_mutex_lock(&q->lock);
+ show(q, fd, argv, s, term);
+ ast_mutex_unlock(&q->lock);
+ ao2_ref(q, -1);
+ }
+ }
return RESULT_SUCCESS;
}
@@ -4079,15 +4106,17 @@
char *ret = NULL;
int which = 0;
int wordlen = strlen(word);
+ ao2_iterator i;
- AST_LIST_LOCK(&queues);
- AST_LIST_TRAVERSE(&queues, q, list) {
+ i = ao2_iterator_init(queues, 0);
+ while((q = ao2_iterator_next(&i))) {
if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
- ret = ast_strdup(q->name);
+ ret = ast_strdup(q->name);
+ ao2_ref(q, -1);
break;
}
- }
- AST_LIST_UNLOCK(&queues);
+ ao2_ref(q, -1);
+ }
return ret;
}
@@ -4125,14 +4154,15 @@
struct queue_ent *qe;
float sl = 0;
struct member *mem;
+ ao2_iterator i;
astman_send_ack(s, m, "Queue status will follow");
time(&now);
- AST_LIST_LOCK(&queues);
if (!ast_strlen_zero(id))
snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
- AST_LIST_TRAVERSE(&queues, q, list) {
+ i = ao2_iterator_init(queues,0);
+ while((q = ao2_iterator_next(&i))) {
ast_mutex_lock(&q->lock);
/* List queue properties */
@@ -4189,6 +4219,7 @@
}
}
ast_mutex_unlock(&q->lock);
+ ao2_ref(q, -1);
}
astman_append(s,
@@ -4196,7 +4227,6 @@
"%s"
"\r\n",idText);
- AST_LIST_UNLOCK(&queues);
return RESULT_SUCCESS;
@@ -4433,6 +4463,7 @@
int which = 0;
struct call_queue *q;
struct member *m;
+ ao2_iterator i;
/* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
if (pos > 5 || pos < 3)
@@ -4444,17 +4475,18 @@
return complete_queue(line, word, pos, state);
/* here is the case for 3, <member> */
- if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */
- AST_LIST_TRAVERSE(&queues, q, list) {
- ast_mutex_lock(&q->lock);
- for (m = q->members ; m ; m = m->next) {
- if (++which > state) {
- ast_mutex_unlock(&q->lock);
- return ast_strdup(m->interface);
- }
- }
- ast_mutex_unlock(&q->lock);
- }
+ i = ao2_iterator_init(queues, 0);
+ while((q = ao2_iterator_next(&i))) {
+ ast_mutex_lock(&q->lock);
+ for (m = q->members ; m ; m = m->next) {
+ if (++which > state) {
+ ast_mutex_unlock(&q->lock);
+ ao2_ref(q, -1);
+ return ast_strdup(m->interface);
+ }
+ }
+ ast_mutex_unlock(&q->lock);
+ ao2_ref(q, -1);
}
return NULL;
@@ -4531,12 +4563,15 @@
clear_and_free_interfaces();
+ ao2_ref(queues, -1);
+
return res;
}
static int load_module(void)
{
int res;
+ queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
if(!reload_queues())
return AST_MODULE_LOAD_DECLINE;
if (queue_persistent_members)
More information about the asterisk-commits
mailing list