aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbweschke <bweschke@f38db490-d61c-443f-a65b-d21fe96a405b>2006-05-26 17:09:51 +0000
committerbweschke <bweschke@f38db490-d61c-443f-a65b-d21fe96a405b>2006-05-26 17:09:51 +0000
commit9edd593f9dc3d21576ec29a100ab65705c0182a2 (patch)
treec42f4a34ad725b31632a6a4d94d09935973d9697
parent280d46f7c6b72b8f2a91a2f1d6c1072e58acbe11 (diff)
A new way to try and deal with deadlocks that occur in app_queue at present. Using this approach, we only manipulate the main queue mutexes when we get a dev state change on a device that is actually a member of a queue. Backported from /trunk for the "bug fix".
git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.2@30546 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--apps/app_queue.c175
1 files changed, 146 insertions, 29 deletions
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 58a85813c..5e41b990d 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -303,6 +303,13 @@ struct member {
struct member *next; /*!< Next member */
};
+struct ast_member_interfaces {
+ char interface[80];
+ AST_LIST_ENTRY(ast_member_interfaces) list; /*!< Next call queue */
+};
+
+static AST_LIST_HEAD_STATIC(interfaces, ast_member_interfaces);
+
/* values used in multi-bit flags in ast_call_queue */
#define QUEUE_EMPTY_NORMAL 1
#define QUEUE_EMPTY_STRICT 2
@@ -458,6 +465,7 @@ static void *changethread(void *data)
struct ast_call_queue *q;
struct statechange *sc = data;
struct member *cur;
+ struct ast_member_interfaces *curint;
char *loc;
char *technology;
@@ -470,36 +478,50 @@ static void *changethread(void *data)
free(sc);
return NULL;
}
- if (option_debug)
- ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
- ast_mutex_lock(&qlock);
- for (q = queues; q; q = q->next) {
- ast_mutex_lock(&q->lock);
- cur = q->members;
- while(cur) {
- if (!strcasecmp(sc->dev, cur->interface)) {
- if (cur->status != sc->state) {
- cur->status = sc->state;
- if (!q->maskmemberstatus) {
- manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
- "Queue: %s\r\n"
- "Location: %s\r\n"
- "Membership: %s\r\n"
- "Penalty: %d\r\n"
- "CallsTaken: %d\r\n"
- "LastCall: %d\r\n"
- "Status: %d\r\n"
- "Paused: %d\r\n",
- q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
- cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
+
+ AST_LIST_LOCK(&interfaces);
+ AST_LIST_TRAVERSE(&interfaces, curint, list) {
+ if (!strcasecmp(curint->interface, sc->dev))
+ break;
+ }
+ AST_LIST_UNLOCK(&interfaces);
+
+ if (curint) {
+
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
+ ast_mutex_lock(&qlock);
+ for (q = queues; q; q = q->next) {
+ ast_mutex_lock(&q->lock);
+ cur = q->members;
+ while(cur) {
+ if (!strcasecmp(sc->dev, cur->interface)) {
+ if (cur->status != sc->state) {
+ cur->status = sc->state;
+ if (!q->maskmemberstatus) {
+ manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
+ "Queue: %s\r\n"
+ "Location: %s\r\n"
+ "Membership: %s\r\n"
+ "Penalty: %d\r\n"
+ "CallsTaken: %d\r\n"
+ "LastCall: %d\r\n"
+ "Status: %d\r\n"
+ "Paused: %d\r\n",
+ q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
+ cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
+ }
}
}
+ cur = cur->next;
}
- cur = cur->next;
+ ast_mutex_unlock(&q->lock);
}
- ast_mutex_unlock(&q->lock);
- }
- ast_mutex_unlock(&qlock);
+ ast_mutex_unlock(&qlock);
+ } else {
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", technology, loc, sc->state, devstate2str(sc->state));
+ }
free(sc);
return NULL;
}
@@ -596,6 +618,89 @@ static void clear_queue(struct ast_call_queue *q)
q->wrapuptime = 0;
}
+static int add_to_interfaces(char *interface)
+{
+ struct ast_member_interfaces *curint, *newint;
+
+ AST_LIST_LOCK(&interfaces);
+ AST_LIST_TRAVERSE(&interfaces, curint, list) {
+ if (!strcasecmp(curint->interface, interface))
+ break;
+ }
+
+ if (!curint) {
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
+
+ if ((newint = malloc(sizeof(*newint)))) {
+ memset(newint, 0, sizeof(*newint));
+ ast_copy_string(newint->interface, interface, sizeof(newint->interface));
+ AST_LIST_INSERT_HEAD(&interfaces, newint, list);
+ }
+ }
+ AST_LIST_UNLOCK(&interfaces);
+
+ return 0;
+}
+
+static int interface_exists_global(char *interface)
+{
+ struct ast_call_queue *q;
+ struct member *mem;
+ int ret = 0;
+
+ ast_mutex_lock(&qlock);
+ for (q = queues; q && !ret; q = q->next) {
+ ast_mutex_lock(&q->lock);
+ mem = q->members;
+ while(mem) {
+ if (!strcasecmp(interface, mem->interface)) {
+ ret = 1;
+ break;
+ }
+ }
+ ast_mutex_unlock(&q->lock);
+ }
+ ast_mutex_unlock(&qlock);
+
+ return ret;
+}
+
+
+static int remove_from_interfaces(char *interface)
+{
+ struct ast_member_interfaces *curint;
+
+ AST_LIST_LOCK(&interfaces);
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
+ if (!strcasecmp(curint->interface, interface) && !interface_exists_global(interface)) {
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
+ AST_LIST_REMOVE_CURRENT(&interfaces, list);
+ free(curint);
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+ AST_LIST_UNLOCK(&interfaces);
+
+ return 0;
+}
+
+static void clear_and_free_interfaces(void)
+{
+ struct ast_member_interfaces *curint;
+
+ AST_LIST_LOCK(&interfaces);
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
+ AST_LIST_REMOVE_CURRENT(&interfaces, list);
+ free(curint);
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+ AST_LIST_UNLOCK(&interfaces);
+
+ return;
+}
+
/*! \brief Configure a queue parameter.
\par
For error reporting, line number is passed for .conf static configuration.
@@ -746,6 +851,7 @@ static void rt_handle_member_record(struct ast_call_queue *q, char *interface, c
m = create_queue_member(interface, penalty, 0);
if (m) {
m->dead = 0;
+ add_to_interfaces(interface);
if (prev_m) {
prev_m->next = m;
} else {
@@ -770,6 +876,7 @@ static void free_members(struct ast_call_queue *q, int all)
prev->next = next;
else
q->members = next;
+ remove_from_interfaces(curm->interface);
free(curm);
} else
prev = curm;
@@ -917,6 +1024,7 @@ static struct ast_call_queue *find_queue_by_name_rt(const char *queuename, struc
} else {
q->members = next_m;
}
+ remove_from_interfaces(m->interface);
free(m);
} else {
prev_m = m;
@@ -1033,9 +1141,9 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *
qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown",
qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
q->name, qe->pos, q->count );
-#if 0
-ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
-#endif
+
+ if (option_debug)
+ 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_mutex_unlock(&qlock);
@@ -2421,6 +2529,8 @@ static int remove_from_queue(char *queuename, char *interface)
}
ast_mutex_unlock(&q->lock);
}
+ if (res == RES_OKAY)
+ remove_from_interfaces(interface);
ast_mutex_unlock(&qlock);
return res;
}
@@ -2440,6 +2550,9 @@ static int add_to_queue(char *queuename, char *interface, int penalty, int pause
if (q) {
ast_mutex_lock(&q->lock);
if (interface_exists(q, interface) == NULL) {
+
+ add_to_interfaces(interface);
+
new_member = create_queue_member(interface, penalty, paused);
if (new_member != NULL) {
@@ -3251,6 +3364,8 @@ static void reload_queues(void)
}
free(cur);
} else {
+ /* Add them to the master int list if necessary */
+ add_to_interfaces(interface);
newm->next = q->members;
q->members = newm;
}
@@ -3275,6 +3390,7 @@ static void reload_queues(void)
q->members = cur->next;
newm = cur;
}
+ remove_from_interfaces(cur->interface);
}
}
if (!new)
@@ -3827,6 +3943,7 @@ int unload_module(void)
{
int res;
+ clear_and_free_interfaces();
res = ast_cli_unregister(&cli_show_queue);
res |= ast_cli_unregister(&cli_show_queues);
res |= ast_cli_unregister(&cli_add_queue_member);