[asterisk-dev] Query about CHECK_BLOCKING(chan) in ast_write()

Tony Mountifield tony at softins.clara.co.uk
Wed Jan 16 06:09:16 CST 2008

Yesterday I ported the MeetMe 'F' option (pass through DTMF) back to 1.2,
and it seems to function, but it flagged up a more general issue that I
would like some feedback on, either to aid my understanding or to confirm
that there is a problem that needs addressing.

Each time I sent a DTMF keypress through the conference, although it
worked, I had the following message logged to the console:

Jan 16 10:51:46 WARNING[10600]: channel.c:2262 ast_write: Thread 6750223 Blocking 'IAX2/h1peer-19', already blocked by thread 6864913 in procedure ast_waitfor_nandfds

There are only two channels in the conference: a local SIP phone in
RFC2833 mode on which I am pressing DTMF keys, and in the above case
IAX2/h1peer-19 is the channel receiving the passed-through DTMF in
ast_write() called from MeetMe.

Looking at line 2262 of channel.c showed the following:

        switch(fr->frametype) {
        case AST_FRAME_DTMF:
                ast_clear_flag(chan, AST_FLAG_BLOCKING);
                res = do_senddigit(chan,fr->subclass);

Trunk is essentially the same, except that it uses ast_channel_lock() and
has code for audio hooks, so I believe my questions are still relevant to
current code.

CHECK_BLOCKING() itself is defined as follows:

#define CHECK_BLOCKING(c) \
{ \
  if (ast_test_flag(c, AST_FLAG_BLOCKING)) { \
    ast_log(LOG_WARNING, "Thread %ld Blocking '%s', already blocked by thread %ld in procedure %s\n", (long) pthread_self(), (c)->name, (long) (c)->blocker, %(c)->blockproc); \
    CRASH; \
  } else { \
    (c)->blocker = pthread_self(); \
    (c)->blockproc = __PRETTY_FUNCTION__; \
    ast_set_flag(c, AST_FLAG_BLOCKING); \

Again, Trunk is identical except that is is wrapped in do ... while(0).

So the operation of CHECK_BLOCKING() is this: if the channel is not
blocked, note the current thread and function, and set the blocking flag,
but otherwise, just issue a warning message, and optionally crash.

Looking back at the code in ast_write(), the first thing it does for
AST_FRAME_DTMF is to clear the blocking flag, WITHOUT checking that it
owns it. I.e. in the case it was already blocked, it clears the original
blocker's flag. This seems wrong to me. In fact, if CHECK_BLOCKING() had
NOT found the channel already blocked, this flag would already have been
clear anyway!

I also wonder why this check is made at all. It stands to reason that the
IAX channel will spend most of its time in ast_waitfor_nandfds() or
similar, waiting for either a channel to be ready, or data to be available
from the IAX socket. It would seem reasonable that another thread should
be able to queue DTMF packets on the channel during that time, without any
kind of blocking conflict.

So, what am I missing? I feel I need to understand the issues more before
I could come up with a fix. Yes, I know I'm talking about the obsolete 1.2
version, but a cursory comparison with Trunk suggests that there have been
no substantial changes to this particular functionality.

Tony Mountifield
Work: tony at softins.co.uk - http://www.softins.co.uk
Play: tony at mountifield.org - http://tony.mountifield.org

More information about the asterisk-dev mailing list