Merged revisions 122130 via svnmerge from
authorTilghman Lesher <tilghman@meg.abyt.es>
Thu, 12 Jun 2008 15:14:37 +0000 (15:14 +0000)
committerTilghman Lesher <tilghman@meg.abyt.es>
Thu, 12 Jun 2008 15:14:37 +0000 (15:14 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
r122130 | tilghman | 2008-06-12 10:11:30 -0500 (Thu, 12 Jun 2008) | 4 lines

Occasionally, the alertpipe loses its nonblocking status, so detect and correct
that situation before it causes a deadlock.  (Reported and tested by ctooley
via #asterisk-dev)

........

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@122131 65c4cc65-6c06-0410-ace0-fbb531ad65f3

main/channel.c

index 1409ef0..287fcdd 100644 (file)
@@ -824,6 +824,7 @@ struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_
        if (needqueue) {
                if (pipe(tmp->alertpipe)) {
                        ast_log(LOG_WARNING, "Channel allocation failed: Can't create alert pipe!\n");
        if (needqueue) {
                if (pipe(tmp->alertpipe)) {
                        ast_log(LOG_WARNING, "Channel allocation failed: Can't create alert pipe!\n");
+alertpipe_failed:
 #ifdef HAVE_ZAPTEL
                        if (tmp->timingfd > -1)
                                close(tmp->timingfd);
 #ifdef HAVE_ZAPTEL
                        if (tmp->timingfd > -1)
                                close(tmp->timingfd);
@@ -834,9 +835,19 @@ struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_
                        return NULL;
                } else {
                        flags = fcntl(tmp->alertpipe[0], F_GETFL);
                        return NULL;
                } else {
                        flags = fcntl(tmp->alertpipe[0], F_GETFL);
-                       fcntl(tmp->alertpipe[0], F_SETFL, flags | O_NONBLOCK);
+                       if (fcntl(tmp->alertpipe[0], F_SETFL, flags | O_NONBLOCK) < 0) {
+                               ast_log(LOG_WARNING, "Channel allocation failed: Unable to set alertpipe nonblocking! (%d: %s)\n", errno, strerror(errno));
+                               close(tmp->alertpipe[0]);
+                               close(tmp->alertpipe[1]);
+                               goto alertpipe_failed;
+                       }
                        flags = fcntl(tmp->alertpipe[1], F_GETFL);
                        flags = fcntl(tmp->alertpipe[1], F_GETFL);
-                       fcntl(tmp->alertpipe[1], F_SETFL, flags | O_NONBLOCK);
+                       if (fcntl(tmp->alertpipe[1], F_SETFL, flags | O_NONBLOCK) < 0) {
+                               ast_log(LOG_WARNING, "Channel allocation failed: Unable to set alertpipe nonblocking! (%d: %s)\n", errno, strerror(errno));
+                               close(tmp->alertpipe[0]);
+                               close(tmp->alertpipe[1]);
+                               goto alertpipe_failed;
+                       }
                }
        } else  /* Make sure we've got it done right if they don't */
                tmp->alertpipe[0] = tmp->alertpipe[1] = -1;
                }
        } else  /* Make sure we've got it done right if they don't */
                tmp->alertpipe[0] = tmp->alertpipe[1] = -1;
@@ -2385,8 +2396,20 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
        
        /* Read and ignore anything on the alertpipe, but read only
           one sizeof(blah) per frame that we send from it */
        
        /* Read and ignore anything on the alertpipe, but read only
           one sizeof(blah) per frame that we send from it */
-       if (chan->alertpipe[0] > -1)
+       if (chan->alertpipe[0] > -1) {
+               int flags = fcntl(chan->alertpipe[0], F_GETFL);
+               /* For some odd reason, the alertpipe occasionally loses nonblocking status,
+                * which immediately causes a deadlock scenario.  Detect and prevent this. */
+               if ((flags & O_NONBLOCK) == 0) {
+                       ast_log(LOG_ERROR, "Alertpipe on channel %s lost O_NONBLOCK?!!\n", chan->name);
+                       if (fcntl(chan->alertpipe[0], F_SETFL, flags | O_NONBLOCK) < 0) {
+                               ast_log(LOG_WARNING, "Unable to set alertpipe nonblocking! (%d: %s)\n", errno, strerror(errno));
+                               f = &ast_null_frame;
+                               goto done;
+                       }
+               }
                read(chan->alertpipe[0], &blah, sizeof(blah));
                read(chan->alertpipe[0], &blah, sizeof(blah));
+       }
 
 #ifdef HAVE_ZAPTEL
        if (chan->timingfd > -1 && chan->fdno == AST_TIMING_FD && ast_test_flag(chan, AST_FLAG_EXCEPTION)) {
 
 #ifdef HAVE_ZAPTEL
        if (chan->timingfd > -1 && chan->fdno == AST_TIMING_FD && ast_test_flag(chan, AST_FLAG_EXCEPTION)) {