Merged revisions 179532 via svnmerge from
authorRussell Bryant <>
Mon, 2 Mar 2009 23:36:38 +0000 (23:36 +0000)
committerRussell Bryant <>
Mon, 2 Mar 2009 23:36:38 +0000 (23:36 +0000)

r179532 | russell | 2009-03-02 17:34:13 -0600 (Mon, 02 Mar 2009) | 40 lines

Move ast_waitfor() down to avoid the results of the API call becoming stale.

This call to ast_waitfor() was being done way too soon in this section of code.
Specifically, there was code in between the call to waitfor and the code that
uses the result that puts the channel in autoservice.  By putting the channel
in autoservice, the previous results of ast_waitfor() become meaningless,
as the autoservice thread will do it's own ast_waitfor() and ast_read()
on the channel.

So, when we came back out of autoservice and eventually hit the block of code
that calls ast_read() on the channel, there may not actually be any input on
the channel available.  Even though the previous call to ast_waitfor() in
app_meetme said there was input, the autoservice thread has since serviced
the channel for some period of time.

This bug manifested itself while dvossel was doing some testing of MeetMe in
Asterisk trunk.  He was using the timerfd timing module.  When the code hit
ast_read() erroneously, it determined that it must have been called because of
input on the timer fd, as chan->fdno was set to AST_TIMING_FD, since that was
the cause of the last legitimate call to ast_read() done by autoservice.

In this test, an IAX2 channel was calling into the MeetMe conference.  It was
_much_ more likely to be seen with an IAX2 channel because of the way audio
is handled.  Every audio frame that comes in results in a call to
ast_queue_frame(), which then uses ast_timer_enable_continuous() to notify
the channel thread that a frame is waiting to be handled.  So, the chances
of ast_waitfor() indicating that a channel needs servicing due to a timer
event on an IAX2 event is very high.

Finally, it is interesting to note that if a different timing interface was
being used, this bug would probably not be noticed.  When ast_read() is called
and erroneously thinks that there is a timer event to handle, it calls the
ast_timer_ack() function.  The pthread and dahdi timing modules handle the
ack() function being called when there is no event by simply ignoring it.
In the case of the timerfd module, it results in a read() on the timer fd
that will block forever, as there is no data to read.  This caused Asterisk
to lock up very quickly.

Thanks to dvossel and mmichelson for the fun debugging session.  :-)


git-svn-id: 65c4cc65-6c06-0410-ace0-fbb531ad65f3


index 67ab096..e3b1541 100644 (file)
@@ -2659,8 +2659,6 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
-                       c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
                        /* Update the struct with the actual confflags */
                        user->userflags = confflags;
@@ -2823,6 +2821,8 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
+                       c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
                        if (c) {
                                char dtmfstr[2] = "";