From cc826d9442fbb2a9673df71b3ea77de9744a5bf3 Mon Sep 17 00:00:00 2001 From: tilghman Date: Thu, 12 Jun 2008 15:14:37 +0000 Subject: [PATCH] Merged revisions 122130 via svnmerge from 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: http://svn.digium.com/svn/asterisk/trunk@122131 f38db490-d61c-443f-a65b-d21fe96a405b --- main/channel.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/main/channel.c b/main/channel.c index 1409ef095..287fcdda8 100644 --- a/main/channel.c +++ b/main/channel.c @@ -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"); +alertpipe_failed: #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); - 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); - 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; @@ -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 */ - 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)); + } #ifdef HAVE_ZAPTEL if (chan->timingfd > -1 && chan->fdno == AST_TIMING_FD && ast_test_flag(chan, AST_FLAG_EXCEPTION)) {