mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-07 10:28:32 +00:00
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: https://origsvn.digium.com/svn/asterisk/branches/1.2@30546 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
175
apps/app_queue.c
175
apps/app_queue.c
@@ -303,6 +303,13 @@ struct member {
|
|||||||
struct member *next; /*!< Next 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 */
|
/* values used in multi-bit flags in ast_call_queue */
|
||||||
#define QUEUE_EMPTY_NORMAL 1
|
#define QUEUE_EMPTY_NORMAL 1
|
||||||
#define QUEUE_EMPTY_STRICT 2
|
#define QUEUE_EMPTY_STRICT 2
|
||||||
@@ -458,6 +465,7 @@ static void *changethread(void *data)
|
|||||||
struct ast_call_queue *q;
|
struct ast_call_queue *q;
|
||||||
struct statechange *sc = data;
|
struct statechange *sc = data;
|
||||||
struct member *cur;
|
struct member *cur;
|
||||||
|
struct ast_member_interfaces *curint;
|
||||||
char *loc;
|
char *loc;
|
||||||
char *technology;
|
char *technology;
|
||||||
|
|
||||||
@@ -470,36 +478,50 @@ static void *changethread(void *data)
|
|||||||
free(sc);
|
free(sc);
|
||||||
return NULL;
|
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_LIST_LOCK(&interfaces);
|
||||||
ast_mutex_lock(&qlock);
|
AST_LIST_TRAVERSE(&interfaces, curint, list) {
|
||||||
for (q = queues; q; q = q->next) {
|
if (!strcasecmp(curint->interface, sc->dev))
|
||||||
ast_mutex_lock(&q->lock);
|
break;
|
||||||
cur = q->members;
|
}
|
||||||
while(cur) {
|
AST_LIST_UNLOCK(&interfaces);
|
||||||
if (!strcasecmp(sc->dev, cur->interface)) {
|
|
||||||
if (cur->status != sc->state) {
|
if (curint) {
|
||||||
cur->status = sc->state;
|
|
||||||
if (!q->maskmemberstatus) {
|
if (option_debug)
|
||||||
manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
|
ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
|
||||||
"Queue: %s\r\n"
|
ast_mutex_lock(&qlock);
|
||||||
"Location: %s\r\n"
|
for (q = queues; q; q = q->next) {
|
||||||
"Membership: %s\r\n"
|
ast_mutex_lock(&q->lock);
|
||||||
"Penalty: %d\r\n"
|
cur = q->members;
|
||||||
"CallsTaken: %d\r\n"
|
while(cur) {
|
||||||
"LastCall: %d\r\n"
|
if (!strcasecmp(sc->dev, cur->interface)) {
|
||||||
"Status: %d\r\n"
|
if (cur->status != sc->state) {
|
||||||
"Paused: %d\r\n",
|
cur->status = sc->state;
|
||||||
q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
|
if (!q->maskmemberstatus) {
|
||||||
cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
|
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);
|
||||||
}
|
} else {
|
||||||
ast_mutex_unlock(&qlock);
|
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);
|
free(sc);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -596,6 +618,89 @@ static void clear_queue(struct ast_call_queue *q)
|
|||||||
q->wrapuptime = 0;
|
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.
|
/*! \brief Configure a queue parameter.
|
||||||
\par
|
\par
|
||||||
For error reporting, line number is passed for .conf static configuration.
|
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);
|
m = create_queue_member(interface, penalty, 0);
|
||||||
if (m) {
|
if (m) {
|
||||||
m->dead = 0;
|
m->dead = 0;
|
||||||
|
add_to_interfaces(interface);
|
||||||
if (prev_m) {
|
if (prev_m) {
|
||||||
prev_m->next = m;
|
prev_m->next = m;
|
||||||
} else {
|
} else {
|
||||||
@@ -770,6 +876,7 @@ static void free_members(struct ast_call_queue *q, int all)
|
|||||||
prev->next = next;
|
prev->next = next;
|
||||||
else
|
else
|
||||||
q->members = next;
|
q->members = next;
|
||||||
|
remove_from_interfaces(curm->interface);
|
||||||
free(curm);
|
free(curm);
|
||||||
} else
|
} else
|
||||||
prev = curm;
|
prev = curm;
|
||||||
@@ -917,6 +1024,7 @@ static struct ast_call_queue *find_queue_by_name_rt(const char *queuename, struc
|
|||||||
} else {
|
} else {
|
||||||
q->members = next_m;
|
q->members = next_m;
|
||||||
}
|
}
|
||||||
|
remove_from_interfaces(m->interface);
|
||||||
free(m);
|
free(m);
|
||||||
} else {
|
} else {
|
||||||
prev_m = m;
|
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_num ? qe->chan->cid.cid_num : "unknown",
|
||||||
qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
|
qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
|
||||||
q->name, qe->pos, q->count );
|
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 );
|
if (option_debug)
|
||||||
#endif
|
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(&q->lock);
|
||||||
ast_mutex_unlock(&qlock);
|
ast_mutex_unlock(&qlock);
|
||||||
@@ -2421,6 +2529,8 @@ static int remove_from_queue(char *queuename, char *interface)
|
|||||||
}
|
}
|
||||||
ast_mutex_unlock(&q->lock);
|
ast_mutex_unlock(&q->lock);
|
||||||
}
|
}
|
||||||
|
if (res == RES_OKAY)
|
||||||
|
remove_from_interfaces(interface);
|
||||||
ast_mutex_unlock(&qlock);
|
ast_mutex_unlock(&qlock);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -2440,6 +2550,9 @@ static int add_to_queue(char *queuename, char *interface, int penalty, int pause
|
|||||||
if (q) {
|
if (q) {
|
||||||
ast_mutex_lock(&q->lock);
|
ast_mutex_lock(&q->lock);
|
||||||
if (interface_exists(q, interface) == NULL) {
|
if (interface_exists(q, interface) == NULL) {
|
||||||
|
|
||||||
|
add_to_interfaces(interface);
|
||||||
|
|
||||||
new_member = create_queue_member(interface, penalty, paused);
|
new_member = create_queue_member(interface, penalty, paused);
|
||||||
|
|
||||||
if (new_member != NULL) {
|
if (new_member != NULL) {
|
||||||
@@ -3251,6 +3364,8 @@ static void reload_queues(void)
|
|||||||
}
|
}
|
||||||
free(cur);
|
free(cur);
|
||||||
} else {
|
} else {
|
||||||
|
/* Add them to the master int list if necessary */
|
||||||
|
add_to_interfaces(interface);
|
||||||
newm->next = q->members;
|
newm->next = q->members;
|
||||||
q->members = newm;
|
q->members = newm;
|
||||||
}
|
}
|
||||||
@@ -3275,6 +3390,7 @@ static void reload_queues(void)
|
|||||||
q->members = cur->next;
|
q->members = cur->next;
|
||||||
newm = cur;
|
newm = cur;
|
||||||
}
|
}
|
||||||
|
remove_from_interfaces(cur->interface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!new)
|
if (!new)
|
||||||
@@ -3827,6 +3943,7 @@ int unload_module(void)
|
|||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
|
clear_and_free_interfaces();
|
||||||
res = ast_cli_unregister(&cli_show_queue);
|
res = ast_cli_unregister(&cli_show_queue);
|
||||||
res |= ast_cli_unregister(&cli_show_queues);
|
res |= ast_cli_unregister(&cli_show_queues);
|
||||||
res |= ast_cli_unregister(&cli_add_queue_member);
|
res |= ast_cli_unregister(&cli_add_queue_member);
|
||||||
|
|||||||
Reference in New Issue
Block a user