[Asterisk-bsd] How to implement locking in channel drivers

Hans Petter Selasky hselasky at c2i.net
Tue Aug 2 13:46:34 CDT 2005


Hi,

I sent this mail to "asterisk-dev at lists.digium.com", but it hasn't passed the 
moderator yet, so I'm posting it here meanwhile:


I'm writing a channel driver for asterisk and I have hit some problems.

1)

I want to have my channel driver under a BSD license, but I see no
ASTERISK_BSD_KEY. Must all code be under GPL or is BSD also allowed?


2)

From what I see, "ast_hangup()" does not perform any race condition checks. It 
is not impossible that two threads can call this function in parallell, and 
succeed until "ast_channel_free()" is called, which handle races.

I'm trying to stay straight with mutexes, and as you probably know, locking 
order cannot be reversed. That will lead to a deadlock. My code looks like 
this:

struct call_desc { // private structure associated with ast_channel

struct ast_channel *p_ch;
astmutex_t *p_mtx;

} *cd;


When I setup things I do like this:

cd->p_ch = ast_channel_alloc(1);

cd->p_mtx = &cd->p_ch->lock;


Then I have a routine to lookup call descriptors by number:

/*---------------------------------------------------------------------------*
 *      cd_by_cid - find call descriptor by ID;
 *
 * NOTE: returns with "cd->mtx" locked
 *---------------------------------------------------------------------------*/
static struct call_desc *
cd_by_cid(u_int32_t cid)
{
    struct call_desc *cd;

    ast_mutex_lock(&cd_global_lock);
    cd = cd_root;
    ast_mutex_unlock(&cd_global_lock);

    while(cd)
    {
  ast_mutex_lock(&cd->p_mtx);

  if((cd->cid != 0) &&
      (((cd->cid ^ cid) & 0xFFFF) == 0))
  {
      break;
  }

  ast_mutex_unlock(&cd->p_mtx);
  cd = cd->next;
    }
    return cd;
}


The problem is that asterisk destroys it's channel mutex when "ast_hangup()" 
is called. But this mutex must be present even after that the channel has 
been freed, hence code might be about to lock that mutex and access struct 
ast_channel. Also struct ast_channel must be static and not freed by free().

One solution is to use a single lock for all of my channel driver, but that is 
not what I want. Does anyone have a solution for this problem?

Another solution is to allocate my own mutex, but then I end up with locking 
order reversal between my mutex and "p_ch->lock".

--HPS


More information about the Asterisk-BSD mailing list