@ -64,12 +64,7 @@ On return from ao2_alloc():
ao2_ref ( o , - 1 )
causing the destructor to be called ( and then memory freed ) when
the refcount goes to 0. This is also available as ao2_unref ( o ) ,
and returns NULL as a convenience , so you can do things like
o = ao2_unref ( o ) ;
and clean the original pointer to prevent errors .
the refcount goes to 0.
- ao2_ref ( o , + 1 ) can be used to modify the refcount on the
object in case we want to pass it around .
@ -121,6 +116,8 @@ Once done, we can link an object to a container with
The function returns NULL in case of errors ( and the object
is not inserted in the container ) . Other values mean success
( we are not supposed to use the value as a pointer to anything ) .
Linking an object to a container increases its refcount by 1
automatically .
\ note While an object o is in a container , we expect that
my_hash_fn ( o ) will always return the same value . The function
@ -137,6 +134,245 @@ list. However there is no ordering among elements.
*/
/*
\ note DEBUGGING REF COUNTS BIBLE :
An interface to help debug refcounting is provided
in this package . It is dependent on the REF_DEBUG macro being
defined in a source file , before the # include of astobj2 . h ,
and in using variants of the normal ao2_xxxx functions
that are named ao2_t_xxxx instead , with an extra argument , a string ,
that will be printed out into / tmp / refs when the refcount for an
object is changed .
these ao2_t_xxxx variants are provided :
ao2_t_alloc ( arg1 , arg2 , arg3 )
ao2_t_ref ( arg1 , arg2 , arg3 )
ao2_t_container_alloc ( arg1 , arg2 , arg3 , arg4 )
ao2_t_link ( arg1 , arg2 , arg3 )
ao2_t_unlink ( arg1 , arg2 , arg3 )
ao2_t_callback ( arg1 , arg2 , arg3 , arg4 , arg5 )
ao2_t_find ( arg1 , arg2 , arg3 , arg4 )
ao2_t_iterator_next ( arg1 , arg2 )
If you study each argument list , you will see that these functions all have
one extra argument that their ao2_xxx counterpart . The last argument in
each case is supposed to be a string pointer , a " tag " , that should contain
enough of an explanation , that you can pair operations that increment the
ref count , with operations that are meant to decrement the refcount .
Each of these calls will generate at least one line of output in / tmp / refs .
These lines look like this :
. . .
0x8756f00 = 1 chan_sip . c : 22240 : load_module ( allocate users )
0x86e3408 = 1 chan_sip . c : 22241 : load_module ( allocate peers )
0x86dd380 = 1 chan_sip . c : 22242 : load_module ( allocate peers_by_ip )
0x822d020 = 1 chan_sip . c : 22243 : load_module ( allocate dialogs )
0x8930fd8 = 1 chan_sip . c : 20025 : build_peer ( allocate a peer struct )
0x8930fd8 + 1 chan_sip . c : 21467 : reload_config ( link peer into peer table ) [ @ 1 ]
0x8930fd8 - 1 chan_sip . c : 2370 : unref_peer ( unref_peer : from reload_config ) [ @ 2 ]
0x89318b0 = 1 chan_sip . c : 20025 : build_peer ( allocate a peer struct )
0x89318b0 + 1 chan_sip . c : 21467 : reload_config ( link peer into peer table ) [ @ 1 ]
0x89318b0 - 1 chan_sip . c : 2370 : unref_peer ( unref_peer : from reload_config ) [ @ 2 ]
0x8930218 = 1 chan_sip . c : 20025 : build_peer ( allocate a peer struct )
0x8930218 + 1 chan_sip . c : 21539 : reload_config ( link peer into peers table ) [ @ 1 ]
0x868c040 - 1 chan_sip . c : 2424 : dialog_unlink_all ( unset the relatedpeer - > call field in tandem with relatedpeer field itself ) [ @ 2 ]
0x868c040 - 1 chan_sip . c : 2443 : dialog_unlink_all ( Let ' s unbump the count in the unlink so the poor pvt can disappear if it is time ) [ @ 1 ]
0x868c040 * * call destructor * * chan_sip . c : 2443 : dialog_unlink_all ( Let ' s unbump the count in the unlink so the poor pvt can disappear if it is time )
0x8cc07e8 - 1 chan_sip . c : 2370 : unref_peer ( unsetting a dialog relatedpeer field in sip_destroy ) [ @ 3 ]
0x8cc07e8 + 1 chan_sip . c : 3876 : find_peer ( ao2_find in peers table ) [ @ 2 ]
0x8cc07e8 - 1 chan_sip . c : 2370 : unref_peer ( unref_peer , from sip_devicestate , release ref from find_peer ) [ @ 3 ]
. . .
The first column is the object address .
The second column reflects how the operation affected the ref count
for that object . Creation sets the ref count to 1 ( = 1 ) .
increment or decrement and amount are specified ( - 1 / + 1 ) .
The remainder of the line specifies where in the file the call was made ,
and the function name , and the tag supplied in the function call .
The * * call destructor * * is specified when the the destroy routine is
run for an object . It does not affect the ref count , but is important
in debugging , because it is possible to have the astobj2 system run it
multiple times on the same object , commonly fatal to asterisk .
Sometimes you have some helper functions to do object ref / unref
operations . Using these normally hides the place where these
functions were called . To get the location where these functions
were called to appear in / tmp / refs , you can do this sort of thing :
# ifdef REF_DEBUG
# define dialog_ref(arg1,arg2) dialog_ref_debug((arg1),(arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
# define dialog_unref(arg1,arg2) dialog_unref_debug((arg1),(arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
static struct sip_pvt * dialog_ref_debug ( struct sip_pvt * p , char * tag , char * file , int line , const char * func )
{
if ( p )
ao2_ref_debug ( p , 1 , tag , file , line , func ) ;
else
ast_log ( LOG_ERROR , " Attempt to Ref a null pointer \n " ) ;
return p ;
}
static struct sip_pvt * dialog_unref_debug ( struct sip_pvt * p , char * tag , char * file , int line , const char * func )
{
if ( p )
ao2_ref_debug ( p , - 1 , tag , file , line , func ) ;
return NULL ;
}
# else
static struct sip_pvt * dialog_ref ( struct sip_pvt * p , char * tag )
{
if ( p )
ao2_ref ( p , 1 ) ;
else
ast_log ( LOG_ERROR , " Attempt to Ref a null pointer \n " ) ;
return p ;
}
static struct sip_pvt * dialog_unref ( struct sip_pvt * p , char * tag )
{
if ( p )
ao2_ref ( p , - 1 ) ;
return NULL ;
}
# endif
In the above code , note that the " normal " helper funcs call ao2_ref ( ) as
normal , and the " helper " functions call ao2_ref_debug directly with the
file , function , and line number info provided . You might find this
well worth the effort to help track these function calls in the code .
To find out why objects are not destroyed ( a common bug ) , you can
edit the source file to use the ao2_t_ * variants , add the # define REF_DEBUG 1
before the # include " asterisk/astobj2.h " line , and add a descriptive
tag to each call . Recompile , and run Asterisk , exit asterisk with
" stop gracefully " , which should result in every object being destroyed .
Then , you can " sort -k 1 /tmp/refs > x1 " to get a sorted list of
all the objects , or you can use " util/refcounter " to scan the file
for you and output any problems it finds .
The above may seem astronomically more work than it is worth to debug
reference counts , which may be true in " simple " situations , but for
more complex situations , it is easily worth 100 times this effort to
help find problems .
To debug , pair all calls so that each call that increments the
refcount is paired with a corresponding call that decrements the
count for the same reason . Hopefully , you will be left with one
or more unpaired calls . This is where you start your search !
For instance , here is an example of this for a dialog object in
chan_sip , that was not getting destroyed , after I moved the lines around
to pair operations :
0x83787a0 = 1 chan_sip . c : 5733 : sip_alloc ( allocate a dialog ( pvt ) struct )
0x83787a0 - 1 chan_sip . c : 19173 : sip_poke_peer ( unref dialog at end of sip_poke_peer , obtained from sip_alloc , just before it goes out of scope ) [ @ 4 ]
0x83787a0 + 1 chan_sip . c : 5854 : sip_alloc ( link pvt into dialogs table ) [ @ 1 ]
0x83787a0 - 1 chan_sip . c : 19150 : sip_poke_peer ( About to change the callid - - remove the old name ) [ @ 3 ]
0x83787a0 + 1 chan_sip . c : 19152 : sip_poke_peer ( Linking in under new name ) [ @ 2 ]
0x83787a0 - 1 chan_sip . c : 2399 : dialog_unlink_all ( unlinking dialog via ao2_unlink ) [ @ 5 ]
0x83787a0 + 1 chan_sip . c : 19130 : sip_poke_peer ( copy sip alloc from p to peer - > call ) [ @ 2 ]
0x83787a0 + 1 chan_sip . c : 2996 : __sip_reliable_xmit ( __sip_reliable_xmit : setting pkt - > owner ) [ @ 3 ]
0x83787a0 - 1 chan_sip . c : 2425 : dialog_unlink_all ( remove all current packets in this dialog , and the pointer to the dialog too as part of __sip_destroy ) [ @ 4 ]
0x83787a0 + 1 chan_sip . c : 22356 : unload_module ( iterate thru dialogs ) [ @ 4 ]
0x83787a0 - 1 chan_sip . c : 22359 : unload_module ( toss dialog ptr from iterator_next ) [ @ 5 ]
0x83787a0 + 1 chan_sip . c : 22373 : unload_module ( iterate thru dialogs ) [ @ 3 ]
0x83787a0 - 1 chan_sip . c : 22375 : unload_module ( throw away iterator result ) [ @ 2 ]
0x83787a0 + 1 chan_sip . c : 2397 : dialog_unlink_all ( Let ' s bump the count in the unlink so it doesn ' t accidentally become dead before we are done ) [ @ 4 ]
0x83787a0 - 1 chan_sip . c : 2436 : dialog_unlink_all ( Let ' s unbump the count in the unlink so the poor pvt can disappear if it is time ) [ @ 3 ]
As you can see , only one unbalanced operation is in the list , a ref count increment when
the peer - > call was set , but no corresponding decrement was made . . .
Hopefully this helps you narrow your search and find those bugs .
THE ART OF REFERENCE COUNTING
( by Steve Murphy )
SOME TIPS for complicated code , and ref counting :
1. Theoretically , passing a refcounted object pointer into a function
call is an act of copying the reference , and could be refcounted .
But , upon examination , this sort of refcounting will explode the amount
of code you have to enter , and for no tangible benefit , beyond
creating more possible failure points / bugs . It will even
complicate your code and make debugging harder , slow down your program
doing useless increments and decrements of the ref counts .
2. It is better to track places where a ref counted pointer
is copied into a structure or stored . Make sure to decrement the refcount
of any previous pointer that might have been there , if setting
this field might erase a previous pointer . ao2_find and iterate_next
internally increment the ref count when they return a pointer , so
you need to decrement the count before the pointer goes out of scope .
3. Any time you decrement a ref count , it may be possible that the
object will be destroyed ( freed ) immediately by that call . If you
are destroying a series of fields in a refcounted object , and
any of the unref calls might possibly result in immediate destruction ,
you can first increment the count to prevent such behavior , then
after the last test , decrement the pointer to allow the object
to be destroyed , if the refcount would be zero .
Example :
dialog_ref ( dialog , " Let's bump the count in the unlink so it doesn't accidentally become dead before we are done " ) ;
ao2_t_unlink ( dialogs , dialog , " unlinking dialog via ao2_unlink " ) ;
*/ /* Unlink us from the owner (channel) if we have one */ /*
if ( dialog - > owner ) {
if ( lockowner )
ast_channel_lock ( dialog - > owner ) ;
ast_debug ( 1 , " Detaching from channel %s \n " , dialog - > owner - > name ) ;
dialog - > owner - > tech_pvt = dialog_unref ( dialog - > owner - > tech_pvt , " resetting channel dialog ptr in unlink_all " ) ;
if ( lockowner )
ast_channel_unlock ( dialog - > owner ) ;
}
if ( dialog - > registry ) {
if ( dialog - > registry - > call = = dialog )
dialog - > registry - > call = dialog_unref ( dialog - > registry - > call , " nulling out the registry's call dialog field in unlink_all " ) ;
dialog - > registry = registry_unref ( dialog - > registry , " delete dialog->registry " ) ;
}
. . .
dialog_unref ( dialog , " Let's unbump the count in the unlink so the poor pvt can disappear if it is time " ) ;
In the above code , the ao2_t_unlink could end up destroying the dialog
object ; if this happens , then the subsequent usages of the dialog
pointer could result in a core dump . So , we ' bump ' the
count upwards before beginning , and then decrementing the count when
we are finished . This is analogous to ' locking ' or ' protecting ' operations
for a short while .
4. One of the most insidious problems I ' ve run into when converting
code to do ref counted automatic destruction , is in the destruction
routines . Where a " destroy " routine had previously been called to
get rid of an object in non - refcounted code , the new regime demands
that you tear that " destroy " routine into two pieces , one that will
tear down the links and ' unref ' them , and the other to actually free
and reset fields . A destroy routine that does any reference deletion
for its own object , will never be called . Another insidious problem
occurs in mutually referenced structures . As an example , a dialog contains
a pointer to a peer , and a peer contains a pointer to a dialog . Watch
out that the destruction of one doesn ' t depend on the destruction of the
other , as in this case a dependency loop will result in neither being
destroyed !
Given the above , you should be ready to do a good job !
murf
*/
/*! \brief
* Typedef for an object destructor . This is called just before freeing
* the memory for the object . It is passed a pointer to the user - defined
@ -160,7 +396,22 @@ typedef void (*ao2_destructor_fn)(void *);
* - the returned pointer cannot be free ( ) ' d or realloc ( ) ' ed ;
* rather , we just call ao2_ref ( o , - 1 ) ;
*/
void * ao2_alloc ( const size_t data_size , ao2_destructor_fn destructor_fn ) ;
# ifdef REF_DEBUG
# define ao2_t_alloc(arg1, arg2, arg3) _ao2_alloc_debug((arg1), (arg2), (arg3), __FILE__, __LINE__, __PRETTY_FUNCTION__)
# define ao2_alloc(arg1, arg2) _ao2_alloc_debug((arg1), (arg2), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
# else
# define ao2_t_alloc(arg1,arg2,arg3) _ao2_alloc((arg1), (arg2))
# define ao2_alloc(arg1,arg2) _ao2_alloc((arg1), (arg2))
# endif
void * _ao2_alloc_debug ( const size_t data_size , ao2_destructor_fn destructor_fn , char * tag , char * file , int line , const char * funcname ) ;
void * _ao2_alloc ( const size_t data_size , ao2_destructor_fn destructor_fn ) ;
/*! \brief
* Reference / unreference an object and return the old refcount .
@ -182,12 +433,21 @@ void *ao2_alloc(const size_t data_size, ao2_destructor_fn destructor_fn);
* can go away is when we release our reference , and it is
* the last one in existence .
*/
int ao2_ref ( void * o , int delta ) ;
# ifdef REF_DEBUG
# define ao2_t_ref(arg1,arg2,arg3) _ao2_ref_debug((arg1), (arg2), (arg3), __FILE__, __LINE__, __PRETTY_FUNCTION__)
# define ao2_ref(arg1,arg2) _ao2_ref_debug((arg1), (arg2), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
# else
# define ao2_t_ref(arg1,arg2,arg3) _ao2_ref((arg1), (arg2))
# define ao2_ref(arg1,arg2) _ao2_ref((arg1), (arg2))
# endif
int _ao2_ref_debug ( void * o , int delta , char * tag , char * file , int line , const char * funcname ) ;
int _ao2_ref ( void * o , int delta ) ;
/*! \brief
* Lock an object .
*
* \ param a A pointer to the object we want lock .
* \ param a A pointer to the object we want to lock.
* \ return 0 on success , other values on error .
*/
int ao2_lock ( void * a ) ;
@ -200,8 +460,28 @@ int ao2_lock(void *a);
*/
int ao2_unlock ( void * a ) ;
/*!
/*! \brief
* Try locking - - ( don ' t block if fail )
*
* \ param a A pointer to the object we want to lock .
* \ return 0 on success , other values on error .
*/
int ao2_trylock ( void * a ) ;
/*! \brief
* Return the lock address of an object
*
* \ param a A pointer to the object we want .
* \ return the address of the lock , else NULL .
*
* This function comes in handy mainly for debugging locking
* situations , where the locking trace code reports the
* lock address , this allows you to correlate against
* object address , to match objects to reported locks .
*/
void * ao2_object_get_lockaddr ( void * obj ) ;
/*!
\ page AstObj2_Containers AstObj2 Containers
Containers are data structures meant to store several objects ,
@ -217,17 +497,44 @@ Operations on container include:
- c = \ b ao2_container_alloc ( size , cmp_fn , hash_fn )
allocate a container with desired size and default compare
and hash function
- The compare function returns an int , which
can be 0 for not found , CMP_STOP to stop end a traversal ,
or CMP_MATCH if they are equal
- The hash function returns an int . The hash function
takes two argument , the object pointer and a flags field ,
- \ b ao2_find ( c , arg , flags )
returns zero or more element matching a given criteria
( specified as arg ) . Flags indicate how many results we
want ( only one or all matching entries ) , and whether we
should unlink the object from the container .
( specified as arg ) . ' c ' is the container pointer . Flags
can be :
OBJ_UNLINK - to remove the object , once found , from the container .
OBJ_NODATA - don ' t return the object if found ( no ref count change )
OBJ_MULTIPLE - don ' t stop at first match ( not implemented )
OBJ_POINTER - if set , ' arg ' is an object pointer , and a hashtable
search will be done . If not , a traversal is done .
- \ b ao2_callback ( c , flags , fn , arg )
apply fn ( obj , arg ) to all objects in the container .
Similar to find . fn ( ) can tell when to stop , and
do anything with the object including unlinking it .
- c is the container ;
- flags can be
OBJ_UNLINK - to remove the object , once found , from the container .
OBJ_NODATA - don ' t return the object if found ( no ref count change )
OBJ_MULTIPLE - don ' t stop at first match ( not implemented )
OBJ_POINTER - if set , ' arg ' is an object pointer , and a hashtable
search will be done . If not , a traversal is done through
all the hashtable ' buckets ' . .
- fn is a func that returns int , and takes 3 args :
( void * obj , void * arg , int flags ) ;
obj is an object
arg is the same as arg passed into ao2_callback
flags is the same as flags passed into ao2_callback
fn returns :
0 : no match , keep going
CMP_STOP : stop search , no match
CMP_MATCH : This object is matched .
Note that the entire operation is run with the container
locked , so noone else can change its content while we work on it .
However , we pay this with the fact that doing
@ -343,8 +650,19 @@ struct ao2_container;
*
* destructor is set implicitly .
*/
struct ao2_container * ao2_container_alloc ( const uint n_buckets ,
ao2_hash_fn * hash_fn , ao2_callback_fn * cmp_fn ) ;
# ifdef REF_DEBUG
# define ao2_t_container_alloc(arg1,arg2,arg3,arg4) _ao2_container_alloc_debug((arg1), (arg2), (arg3), (arg4), __FILE__, __LINE__, __PRETTY_FUNCTION__)
# define ao2_container_alloc(arg1,arg2,arg3) _ao2_container_alloc_debug((arg1), (arg2), (arg3), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
# else
# define ao2_t_container_alloc(arg1,arg2,arg3,arg4) _ao2_container_alloc((arg1), (arg2), (arg3))
# define ao2_container_alloc(arg1,arg2,arg3) _ao2_container_alloc((arg1), (arg2), (arg3))
# endif
struct ao2_container * _ao2_container_alloc ( const uint n_buckets ,
ao2_hash_fn * hash_fn , ao2_callback_fn * cmp_fn ) ;
struct ao2_container * _ao2_container_alloc_debug ( const uint n_buckets ,
ao2_hash_fn * hash_fn , ao2_callback_fn * cmp_fn ,
char * tag , char * file , int line , const char * funcname ) ;
/*! \brief
* Returns the number of elements in a container .
@ -376,7 +694,16 @@ int ao2_container_count(struct ao2_container *c);
* \ note This function automatically increases the reference count to account
* for the reference that the container now holds to the object .
*/
void * ao2_link ( struct ao2_container * c , void * newobj ) ;
# ifdef REF_DEBUG
# define ao2_t_link(arg1, arg2, arg3) _ao2_link_debug((arg1), (arg2), (arg3), __FILE__, __LINE__, __PRETTY_FUNCTION__)
# define ao2_link(arg1, arg2) _ao2_link_debug((arg1), (arg2), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
# else
# define ao2_t_link(arg1, arg2, arg3) _ao2_link((arg1), (arg2))
# define ao2_link(arg1, arg2) _ao2_link((arg1), (arg2))
# endif
void * _ao2_link_debug ( struct ao2_container * c , void * new_obj , char * tag , char * file , int line , const char * funcname ) ;
void * _ao2_link ( struct ao2_container * c , void * newobj ) ;
/*!
* \ brief Remove an object from the container
@ -391,9 +718,19 @@ void *ao2_link(struct ao2_container *c, void *newobj);
* be called .
*
* \ note If the object gets unlinked from the container , the container ' s
* reference to the object will be automatically released .
* reference to the object will be automatically released . ( The
* refcount will be decremented ) .
*/
void * ao2_unlink ( struct ao2_container * c , void * obj ) ;
# ifdef REF_DEBUG
# define ao2_t_unlink(arg1, arg2, arg3) _ao2_unlink_debug((arg1), (arg2), (arg3), __FILE__, __LINE__, __PRETTY_FUNCTION__)
# define ao2_unlink(arg1, arg2) _ao2_unlink_debug((arg1), (arg2), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
# else
# define ao2_t_unlink(arg1, arg2, arg3) _ao2_unlink((arg1), (arg2))
# define ao2_unlink(arg1, arg2) _ao2_unlink((arg1), (arg2))
# endif
void * _ao2_unlink_debug ( struct ao2_container * c , void * obj , char * tag , char * file , int line , const char * funcname ) ;
void * _ao2_unlink ( struct ao2_container * c , void * obj ) ;
/*! \brief Used as return value if the flag OBJ_MULTIPLE is set */
struct ao2_list {
@ -407,10 +744,30 @@ struct ao2_list {
* in a container , as described below .
*
* \ param c A pointer to the container to operate on .
* \ param arg passed to the callback .
* \ param flags A set of flags specifying the operation to perform ,
partially used by the container code , but also passed to
the callback .
- If OBJ_NODATA is set , ao2_callback will return NULL . No refcounts
of any of the traversed objects will be incremented .
On the converse , if it is NOT set ( the default ) , The ref count
of each object for which CMP_MATCH was set will be incremented ,
and you will have no way of knowing which those are , until
the multiple - object - return functionality is implemented .
- If OBJ_POINTER is set , the traversed items will be restricted
to the objects in the bucket that the object key hashes to .
* \ param cb_fn A function pointer , that will be called on all
objects , to see if they match . This function returns CMP_MATCH
if the object is matches the criteria ; CMP_STOP if the traversal
should immediately stop , or both ( via bitwise ORing ) , if you find a
match and want to end the traversal , and 0 if the object is not a match ,
but the traversal should continue . This is the function that is applied
to each object traversed . It ' s arguments are :
( void * obj , void * arg , int flags ) , where :
obj is an object
arg is the same as arg passed into ao2_callback
flags is the same as flags passed into ao2_callback ( flags are
also used by ao2_callback ) .
* \ param arg passed to the callback .
* \ return A pointer to the object found / marked ,
* a pointer to a list of objects matching comparison function ,
* NULL if not found .
@ -459,14 +816,32 @@ struct ao2_list {
* \ note When the returned object is no longer in use , ao2_ref ( ) should
* be used to free the additional reference possibly created by this function .
*/
void * ao2_callback ( struct ao2_container * c ,
enum search_flags flags ,
ao2_callback_fn * cb_fn , void * arg ) ;
# ifdef REF_DEBUG
# define ao2_t_callback(arg1,arg2,arg3,arg4,arg5) _ao2_callback_debug((arg1), (arg2), (arg3), (arg4), (arg5), __FILE__, __LINE__, __PRETTY_FUNCTION__)
# define ao2_callback(arg1,arg2,arg3,arg4) _ao2_callback_debug((arg1), (arg2), (arg3), (arg4), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
# else
# define ao2_t_callback(arg1,arg2,arg3,arg4,arg5) _ao2_callback((arg1), (arg2), (arg3), (arg4))
# define ao2_callback(arg1,arg2,arg3,arg4) _ao2_callback((arg1), (arg2), (arg3), (arg4))
# endif
void * _ao2_callback_debug ( struct ao2_container * c , enum search_flags flags ,
ao2_callback_fn * cb_fn , void * arg , char * tag ,
char * file , int line , const char * funcname ) ;
void * _ao2_callback ( struct ao2_container * c ,
enum search_flags flags ,
ao2_callback_fn * cb_fn , void * arg ) ;
/*! ao2_find() is a short hand for ao2_callback(c, flags, c->cmp_fn, arg)
* XXX possibly change order of arguments ?
*/
void * ao2_find ( struct ao2_container * c , void * arg , enum search_flags flags ) ;
# ifdef REF_DEBUG
# define ao2_t_find(arg1,arg2,arg3,arg4) _ao2_find_debug((arg1), (arg2), (arg3), (arg4), __FILE__, __LINE__, __PRETTY_FUNCTION__)
# define ao2_find(arg1,arg2,arg3) _ao2_find_debug((arg1), (arg2), (arg3), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
# else
# define ao2_t_find(arg1,arg2,arg3,arg4) _ao2_find((arg1), (arg2), (arg3))
# define ao2_find(arg1,arg2,arg3) _ao2_find((arg1), (arg2), (arg3))
# endif
void * _ao2_find_debug ( struct ao2_container * c , void * arg , enum search_flags flags , char * tag , char * file , int line , const char * funcname ) ;
void * _ao2_find ( struct ao2_container * c , void * arg , enum search_flags flags ) ;
/*! \brief
*
@ -559,9 +934,20 @@ struct ao2_iterator {
uint version ;
} ;
struct ao2_iterator ao2_iterator_init ( struct ao2_container * c , int flags ) ;
/* the flags field can contain F_AO2I_DONTLOCK, which will prevent
ao2_iterator_next calls from locking the container while it
searches for the next pointer */
void * ao2_iterator_next ( struct ao2_iterator * a ) ;
struct ao2_iterator ao2_iterator_init ( struct ao2_container * c , int flags ) ;
# ifdef REF_DEBUG
# define ao2_t_iterator_next(arg1, arg2) _ao2_iterator_next_debug((arg1), (arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
# define ao2_iterator_next(arg1) _ao2_iterator_next_debug((arg1), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
# else
# define ao2_t_iterator_next(arg1, arg2) _ao2_iterator_next((arg1))
# define ao2_iterator_next(arg1) _ao2_iterator_next((arg1))
# endif
void * _ao2_iterator_next_debug ( struct ao2_iterator * a , char * tag , char * file , int line , const char * funcname ) ;
void * _ao2_iterator_next ( struct ao2_iterator * a ) ;
/* extra functions */
void ao2_bt ( void ) ; /* backtrace */