From c11f4d9df6342635987cca10e8c0bae1f329669b Mon Sep 17 00:00:00 2001 From: Mark Spencer Date: Wed, 9 Jul 2003 22:41:51 +0000 Subject: Fix race in Agents git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1173 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/chan_agent.c | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/channels/chan_agent.c b/channels/chan_agent.c index d487428e5..b514043fb 100755 --- a/channels/chan_agent.c +++ b/channels/chan_agent.c @@ -79,6 +79,7 @@ static struct agent_pvt { pthread_mutex_t lock; /* Channel private lock */ int dead; /* Poised for destruction? */ int pending; /* Not a real agent -- just pending a match */ + int abouttograb; /* About to grab */ unsigned int group; /* Group memberships */ char moh[80]; /* Which music on hold */ char agent[AST_MAX_AGENT]; /* Agent ID */ @@ -175,6 +176,21 @@ static struct agent_pvt *add_agent(char *agent, int pending) 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 agent_answer(struct ast_channel *ast) @@ -352,9 +368,13 @@ static int agent_hangup(struct ast_channel *ast) agent_unlink(p); 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); - else { + } else { /* Not dead -- check availability now */ ast_pthread_mutex_lock(&p->lock); 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 */ chan = agent_new(newlyavailable, AST_STATE_DOWN); parent = p->owner; + p->abouttograb = 1; ast_pthread_mutex_unlock(&p->lock); 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); } if (!res) { - ast_setstate(parent, AST_STATE_UP); - ast_setstate(chan, AST_STATE_UP); - ast_channel_masquerade(parent, chan); - ast_hangup(chan); + /* Note -- parent may have disappeared */ + if (p->abouttograb) { + ast_setstate(parent, AST_STATE_UP); + 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 { - ast_log(LOG_NOTICE, "Not sure this will always work..\n"); - ast_hangup(chan); + ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n"); + agent_cleanup(newlyavailable); } } return 0; -- cgit v1.2.3