[Asterisk-Dev] what can i do on an unlocked ast_channel ?

Luigi Rizzo rizzo at icir.org
Sat May 14 15:20:45 MST 2005


as a followup to myself... can you people have a look at the last note in
http://bugs.digium.com/view.php?id=4265    (bugnote id 27249)
as a possible deadlock-free solution to channel locking ?

The relevant text is attached below for convenience:
	cheers
	luigi

----------------------

One possibility would be the introduction of refcounts in the
the ast_channel objects, protected by either chan->lock        
or (better) by 'chlock' so that chan->lock can be left to
its intended (i presume) purpose of implementing 'ownership'
of the object.

Then we would have the following interface, a lot simpler and 
without risks of deadlock.

    /* increments the refcount to create a new reference */
    ast_channel_addref(chan) {
        ast_mutex_lock(&chlock);
        chan->refcount++;
        ast_mutex_unlock(&chlock);
    }

    /* decrement the refcount to return a reference */
    ast_channel_remref(chan) {
        ast_mutex_lock(&chlock);
        i = --chan->refcount;
        ast_mutex_unlock(&chlock);
        if (i == 0)  
            ast_channel_free(chan); /* delete on last ref. */
    }

    /* optimized walk function, returns a new reference */
    ast_channel_walk(prev) {
        ast_mutex_lock(&chlock);
        if (prev == NULL) /* we want the first item */
            c = channels;
        else { 
            /* make sure 'prev' still on the list */
            for (c = channels; c && c != prev; c = c->next)  
                ;
            if (c) /* yes, so get the next element */
                c = c->next;
        }
        if (c)  /* the object exists, increment the refcount */
            c->refcount++;
        ast_mutex_unlock(&chlock);
        return c;
    }      

ast_channel_find_by_name(name) is similarly simple.

It is up to the caller to keep or release the reference on 'prev'.
It can release it even before calling ast_channel_walk() because
once again, prev is never dereferenced.

--------------------
On Sat, May 14, 2005 at 07:30:25AM -0700, Luigi Rizzo wrote:
> I was wondering what is the locking scheme used for struct ast_channel.
> I cannot find anything in the source (channel.h, channel.c) except
> figuring out (from the code) that:
> 
>  - chlock protects the two lists 'channels' and 'backends'.
>    So if I hold chlock, nobody else should free() any of the objects
>    on the 'channels' list (not sure about 'backends' though
>    maybe there is no contention on those objects by separate threads.
> 
>  - c->lock "lock a channel for some operations" (from channel.h)
> 
> I have no idea of the meaning of the latter.
> But looking at ast_channel_free() it seems that
> there is a risk that a struct ast_channel can get freed if
> noone holds that mutex.
> 
> The question arises because there is some code in e.g.
> apps/app_chanspy.c::local_channel_walk() that returns a
> pointer to an unlocked channel, and then dereferences it
> without apparently holding any lock. How do we guarantee
> that this does not result in dereferencing an invalid pointer ?
> Perhaps because it is guaranteed that such ops and
> the call to ast_channel_free() cannot occur in different
> threads ?
> 
> 	cheers
> 	luigi
> _______________________________________________
> Asterisk-Dev mailing list
> Asterisk-Dev at lists.digium.com
> http://lists.digium.com/mailman/listinfo/asterisk-dev
> To UNSUBSCRIBE or update options visit:
>    http://lists.digium.com/mailman/listinfo/asterisk-dev



More information about the asterisk-dev mailing list