diff options
author | jpeeler <jpeeler@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-01-12 20:26:22 +0000 |
---|---|---|
committer | jpeeler <jpeeler@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-01-12 20:26:22 +0000 |
commit | ae5d77905b37c81b6744175b4d3afbe6af6736d5 (patch) | |
tree | 4c07104cfb2a9c0b47e183cd4e7ee184607cb936 /channels | |
parent | 48c6f97b71b1e2bc53cc8efc9d3108d76147289e (diff) |
(closes issue #12269)
Reported by: IgorG
Tested by: denisgalvao
This gits rid of the notion of an owning_app allowing the request and hangup to be initiated by different threads. Originating from an active agent channel requires this. The implementation primarily changes __login_exec to wait on a condition variable rather than a lock.
Review: http://reviewboard.digium.com/r/35/
git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@168507 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_agent.c | 47 |
1 files changed, 28 insertions, 19 deletions
diff --git a/channels/chan_agent.c b/channels/chan_agent.c index 9d93f9c15..daa8a9d08 100644 --- a/channels/chan_agent.c +++ b/channels/chan_agent.c @@ -195,7 +195,8 @@ struct agent_pvt { char name[AST_MAX_AGENT]; int inherited_devicestate; /*!< Does the underlying channel have a devicestate to pass? */ ast_mutex_t app_lock; /**< Synchronization between owning applications */ - volatile pthread_t owning_app; /**< Owning application thread id */ + int app_lock_flag; + ast_cond_t app_complete_cond; volatile int app_sleep_cond; /**< Sleep condition for the login app */ struct ast_channel *owner; /**< Agent */ char loginchan[80]; /**< channel they logged in from */ @@ -380,7 +381,8 @@ static struct agent_pvt *add_agent(char *agent, int pending) ast_copy_string(p->agent, agt, sizeof(p->agent)); ast_mutex_init(&p->lock); ast_mutex_init(&p->app_lock); - p->owning_app = (pthread_t) -1; + ast_cond_init(&p->app_complete_cond, NULL); + p->app_lock_flag = 0; p->app_sleep_cond = 1; p->group = group; p->pending = pending; @@ -428,12 +430,14 @@ static int agent_cleanup(struct agent_pvt *p) chan->tech_pvt = NULL; p->app_sleep_cond = 1; /* Release ownership of the agent to other threads (presumably running the login app). */ - ast_mutex_unlock(&p->app_lock); + p->app_lock_flag = 0; + ast_cond_signal(&p->app_complete_cond); if (chan) ast_channel_free(chan); if (p->dead) { ast_mutex_destroy(&p->lock); ast_mutex_destroy(&p->app_lock); + ast_cond_destroy(&p->app_complete_cond); free(p); } return 0; @@ -930,6 +934,7 @@ static int agent_hangup(struct ast_channel *ast) } else if (p->dead) { ast_mutex_destroy(&p->lock); ast_mutex_destroy(&p->app_lock); + ast_cond_destroy(&p->app_complete_cond); free(p); } else { if (p->chan) { @@ -940,8 +945,10 @@ static int agent_hangup(struct ast_channel *ast) ast_mutex_unlock(&p->lock); } /* Release ownership of the agent to other threads (presumably running the login app). */ - if (ast_strlen_zero(p->loginchan)) - ast_mutex_unlock(&p->app_lock); + if (ast_strlen_zero(p->loginchan)) { + p->app_lock_flag = 0; + ast_cond_signal(&p->app_complete_cond); + } } return 0; } @@ -1029,6 +1036,7 @@ static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct static struct ast_channel *agent_new(struct agent_pvt *p, int state) { struct ast_channel *tmp; + int alreadylocked; #if 0 if (!p->chan) { ast_log(LOG_WARNING, "No channel? :(\n"); @@ -1079,11 +1087,15 @@ static struct ast_channel *agent_new(struct agent_pvt *p, int state) * implemented in the kernel for this. */ p->app_sleep_cond = 0; - if(ast_strlen_zero(p->loginchan) && ast_mutex_trylock(&p->app_lock)) { + + alreadylocked = p->app_lock_flag; + p->app_lock_flag = 1; + + if(ast_strlen_zero(p->loginchan) && alreadylocked) { if (p->chan) { ast_queue_frame(p->chan, &ast_null_frame); ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ - ast_mutex_lock(&p->app_lock); + p->app_lock_flag = 1; ast_mutex_lock(&p->lock); } else { ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n"); @@ -1092,7 +1104,8 @@ static struct ast_channel *agent_new(struct agent_pvt *p, int state) p->app_sleep_cond = 1; ast_channel_free( tmp ); ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ - ast_mutex_unlock(&p->app_lock); + p->app_lock_flag = 0; + ast_cond_signal(&p->app_complete_cond); return NULL; } } else if (!ast_strlen_zero(p->loginchan)) { @@ -1110,14 +1123,6 @@ static struct ast_channel *agent_new(struct agent_pvt *p, int state) } if (p->chan) ast_indicate(p->chan, AST_CONTROL_UNHOLD); - p->owning_app = pthread_self(); - /* After the above step, there should not be any blockers. */ - if (p->chan) { - if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) { - ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" ); - ast_assert(ast_test_flag(p->chan, AST_FLAG_BLOCKING) == 0); - } - } return tmp; } @@ -1262,6 +1267,7 @@ static int read_agent_config(void) if (!p->chan) { ast_mutex_destroy(&p->lock); ast_mutex_destroy(&p->app_lock); + ast_cond_destroy(&p->app_complete_cond); free(p); } else { /* Cause them to hang up */ @@ -2255,15 +2261,17 @@ static int __login_exec(struct ast_channel *chan, void *data, int callbackmode) ast_mutex_unlock(&p->lock); AST_LIST_UNLOCK(&agents); /* Synchronize channel ownership between call to agent and itself. */ - ast_mutex_lock( &p->app_lock ); + ast_mutex_lock(&p->app_lock); + if (p->app_lock_flag == 1) { + ast_cond_wait(&p->app_complete_cond, &p->app_lock); + } + ast_mutex_unlock(&p->app_lock); ast_mutex_lock(&p->lock); - p->owning_app = pthread_self(); ast_mutex_unlock(&p->lock); if (p->ackcall > 1) res = agent_ack_sleep(p); else res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p ); - ast_mutex_unlock( &p->app_lock ); if ((p->ackcall > 1) && (res == 1)) { AST_LIST_LOCK(&agents); ast_mutex_lock(&p->lock); @@ -2299,6 +2307,7 @@ static int __login_exec(struct ast_channel *chan, void *data, int callbackmode) if (p->dead && !p->owner) { ast_mutex_destroy(&p->lock); ast_mutex_destroy(&p->app_lock); + ast_cond_destroy(&p->app_complete_cond); free(p); } } |