mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-19 08:11:21 +00:00
Fix race in Agents
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1173 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -79,6 +79,7 @@ static struct agent_pvt {
|
|||||||
pthread_mutex_t lock; /* Channel private lock */
|
pthread_mutex_t lock; /* Channel private lock */
|
||||||
int dead; /* Poised for destruction? */
|
int dead; /* Poised for destruction? */
|
||||||
int pending; /* Not a real agent -- just pending a match */
|
int pending; /* Not a real agent -- just pending a match */
|
||||||
|
int abouttograb; /* About to grab */
|
||||||
unsigned int group; /* Group memberships */
|
unsigned int group; /* Group memberships */
|
||||||
char moh[80]; /* Which music on hold */
|
char moh[80]; /* Which music on hold */
|
||||||
char agent[AST_MAX_AGENT]; /* Agent ID */
|
char agent[AST_MAX_AGENT]; /* Agent ID */
|
||||||
@@ -175,6 +176,21 @@ static struct agent_pvt *add_agent(char *agent, int pending)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int agent_cleanup(struct agent_pvt *p)
|
||||||
|
{
|
||||||
|
struct ast_channel *chan = p->owner;
|
||||||
|
p->owner = NULL;
|
||||||
|
chan->pvt->pvt = NULL;
|
||||||
|
p->app_sleep_cond = 1;
|
||||||
|
/* Release ownership of the agent to other threads (presumably running the login app). */
|
||||||
|
ast_pthread_mutex_unlock(&p->app_lock);
|
||||||
|
if (chan)
|
||||||
|
ast_channel_free(chan);
|
||||||
|
if (p->dead)
|
||||||
|
free(p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int check_availability(struct agent_pvt *newlyavailable, int needlock);
|
static int check_availability(struct agent_pvt *newlyavailable, int needlock);
|
||||||
|
|
||||||
static int agent_answer(struct ast_channel *ast)
|
static int agent_answer(struct ast_channel *ast)
|
||||||
@@ -352,9 +368,13 @@ static int agent_hangup(struct ast_channel *ast)
|
|||||||
agent_unlink(p);
|
agent_unlink(p);
|
||||||
ast_pthread_mutex_unlock(&agentlock);
|
ast_pthread_mutex_unlock(&agentlock);
|
||||||
}
|
}
|
||||||
if (p->dead)
|
if (p->abouttograb) {
|
||||||
|
/* Let the "about to grab" thread know this isn't valid anymore, and let it
|
||||||
|
kill it later */
|
||||||
|
p->abouttograb = 0;
|
||||||
|
} else if (p->dead) {
|
||||||
free(p);
|
free(p);
|
||||||
else {
|
} else {
|
||||||
/* Not dead -- check availability now */
|
/* Not dead -- check availability now */
|
||||||
ast_pthread_mutex_lock(&p->lock);
|
ast_pthread_mutex_lock(&p->lock);
|
||||||
check_availability(p, 1);
|
check_availability(p, 1);
|
||||||
@@ -549,6 +569,7 @@ static int check_availability(struct agent_pvt *newlyavailable, int needlock)
|
|||||||
/* We found a pending call, time to merge */
|
/* We found a pending call, time to merge */
|
||||||
chan = agent_new(newlyavailable, AST_STATE_DOWN);
|
chan = agent_new(newlyavailable, AST_STATE_DOWN);
|
||||||
parent = p->owner;
|
parent = p->owner;
|
||||||
|
p->abouttograb = 1;
|
||||||
ast_pthread_mutex_unlock(&p->lock);
|
ast_pthread_mutex_unlock(&p->lock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -566,13 +587,20 @@ static int check_availability(struct agent_pvt *newlyavailable, int needlock)
|
|||||||
ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
|
ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
|
||||||
}
|
}
|
||||||
if (!res) {
|
if (!res) {
|
||||||
ast_setstate(parent, AST_STATE_UP);
|
/* Note -- parent may have disappeared */
|
||||||
ast_setstate(chan, AST_STATE_UP);
|
if (p->abouttograb) {
|
||||||
ast_channel_masquerade(parent, chan);
|
ast_setstate(parent, AST_STATE_UP);
|
||||||
ast_hangup(chan);
|
ast_setstate(chan, AST_STATE_UP);
|
||||||
|
ast_channel_masquerade(parent, chan);
|
||||||
|
p->abouttograb = 0;
|
||||||
|
ast_hangup(chan);
|
||||||
|
} else {
|
||||||
|
ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
|
||||||
|
agent_cleanup(newlyavailable);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ast_log(LOG_NOTICE, "Not sure this will always work..\n");
|
ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n");
|
||||||
ast_hangup(chan);
|
agent_cleanup(newlyavailable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user