Merged revisions 168507 via svnmerge from
authorJeff Peeler <jpeeler@digium.com>
Mon, 12 Jan 2009 20:53:04 +0000 (20:53 +0000)
committerJeff Peeler <jpeeler@digium.com>
Mon, 12 Jan 2009 20:53:04 +0000 (20:53 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
  r168507 | jpeeler | 2009-01-12 14:26:22 -0600 (Mon, 12 Jan 2009) | 9 lines

  (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: https://origsvn.digium.com/svn/asterisk/trunk@168508 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_agent.c

index ded6225..c4ae81e 100644 (file)
@@ -256,7 +256,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 */
        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 */
        volatile int app_sleep_cond;   /**< Sleep condition for the login app */
        struct ast_channel *owner;     /**< Agent */
        char loginchan[80];            /**< channel they logged in from */
@@ -451,7 +452,8 @@ static struct agent_pvt *add_agent(const char *agent, int pending)
                ast_copy_string(p->agent, agt, sizeof(p->agent));
                ast_mutex_init(&p->lock);
                ast_mutex_init(&p->app_lock);
                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;
                p->app_sleep_cond = 1;
                p->group = group;
                p->pending = pending;
@@ -509,12 +511,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). */
        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);
        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);
                ast_free(p);
         }
        return 0;
                ast_free(p);
         }
        return 0;
@@ -1001,6 +1005,7 @@ static int agent_hangup(struct ast_channel *ast)
        } else if (p->dead) {
                ast_mutex_destroy(&p->lock);
                ast_mutex_destroy(&p->app_lock);
        } else if (p->dead) {
                ast_mutex_destroy(&p->lock);
                ast_mutex_destroy(&p->app_lock);
+               ast_cond_destroy(&p->app_complete_cond);
                ast_free(p);
        } else {
                if (p->chan) {
                ast_free(p);
        } else {
                if (p->chan) {
@@ -1011,8 +1016,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). */
                        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;
 }
        }
        return 0;
 }
@@ -1099,6 +1106,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;
 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");
 #if 0
        if (!p->chan) {
                ast_log(LOG_WARNING, "No channel? :(\n");
@@ -1144,11 +1152,15 @@ static struct ast_channel *agent_new(struct agent_pvt *p, int state)
         * implemented in the kernel for this.
         */
        p->app_sleep_cond = 0;
         * 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. */
                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");
                        ast_mutex_lock(&p->lock);
                } else {
                        ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
@@ -1157,7 +1169,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. */
                        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)) {
                        return NULL;
                }
        } else if (!ast_strlen_zero(p->loginchan)) {
@@ -1175,14 +1188,6 @@ static struct ast_channel *agent_new(struct agent_pvt *p, int state)
        } 
        if (p->chan)
                ast_indicate(p->chan, AST_CONTROL_UNHOLD);
        } 
        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;
 }
 
        return tmp;
 }
 
@@ -1347,6 +1352,7 @@ static int read_agent_config(int reload)
                                if (!p->chan) {
                                        ast_mutex_destroy(&p->lock);
                                        ast_mutex_destroy(&p->app_lock);
                                if (!p->chan) {
                                        ast_mutex_destroy(&p->lock);
                                        ast_mutex_destroy(&p->app_lock);
+                                       ast_cond_destroy(&p->app_complete_cond);
                                        ast_free(p);
                                } else {
                                        /* Cause them to hang up */
                                        ast_free(p);
                                } else {
                                        /* Cause them to hang up */
@@ -2233,15 +2239,17 @@ static int login_exec(struct ast_channel *chan, void *data)
                                                        ast_mutex_unlock(&p->lock);
                                                        AST_LIST_UNLOCK(&agents);
                                                        /*      Synchronize channel ownership between call to agent and itself. */
                                                        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);
                                                        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->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);
                                                        if ((p->ackcall > 1)  && (res == 1)) {
                                                                AST_LIST_LOCK(&agents);
                                                                ast_mutex_lock(&p->lock);
@@ -2276,6 +2284,7 @@ static int login_exec(struct ast_channel *chan, void *data)
                                                if (p->dead && !p->owner) {
                                                        ast_mutex_destroy(&p->lock);
                                                        ast_mutex_destroy(&p->app_lock);
                                                if (p->dead && !p->owner) {
                                                        ast_mutex_destroy(&p->lock);
                                                        ast_mutex_destroy(&p->app_lock);
+                                                       ast_cond_destroy(&p->app_complete_cond);
                                                        ast_free(p);
                                                }
                                        }
                                                        ast_free(p);
                                                }
                                        }