Fri Jun 19 12:10:07 2009

Asterisk developer's documentation


astobj2.c File Reference

#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/astobj2.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include <execinfo.h>

Go to the source code of this file.

Data Structures

struct  __priv_data
struct  ao2_container
struct  astobj2
struct  bucket
struct  bucket_list

Defines

#define AO2_MAGIC   0xa570b123
#define EXTERNAL_OBJ(_p)   ((_p) == NULL ? NULL : (_p)->user_data)
 convert from a pointer _p to an astobj2 object
#define N1   20
#define REF_FILE   "/tmp/refs"

Functions

static void * __ao2_alloc (size_t data_size, ao2_destructor_fn destructor_fn)
static void * __ao2_callback (struct ao2_container *c, const enum search_flags flags, ao2_callback_fn *cb_fn, void *arg, char *tag, char *file, int line, const char *funcname)
static struct ao2_container__ao2_container_alloc (struct ao2_container *c, const unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn)
static struct ao2_container__ao2_container_alloc (struct ao2_container *c, const uint n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn)
static void * __ao2_iterator_next (struct ao2_iterator *a, struct bucket_list **q)
static struct bucket_list__ao2_link (struct ao2_container *c, void *user_data)
static int __ao2_ref (void *user_data, const int delta)
void * _ao2_alloc (size_t data_size, ao2_destructor_fn destructor_fn)
void * _ao2_alloc_debug (size_t data_size, ao2_destructor_fn destructor_fn, char *tag, char *file, int line, const char *funcname)
void * _ao2_callback (struct ao2_container *c, const enum search_flags flags, ao2_callback_fn *cb_fn, void *arg)
void * _ao2_callback_debug (struct ao2_container *c, const enum search_flags flags, ao2_callback_fn *cb_fn, void *arg, char *tag, char *file, int line, const char *funcname)
ao2_container_ao2_container_alloc (const unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn)
ao2_container_ao2_container_alloc_debug (const unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn, char *tag, char *file, int line, const char *funcname)
void * _ao2_find (struct ao2_container *c, void *arg, enum search_flags flags)
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_iterator_next (struct ao2_iterator *a)
void * _ao2_iterator_next_debug (struct ao2_iterator *a, char *tag, char *file, int line, const char *funcname)
void * _ao2_link (struct ao2_container *c, void *user_data)
void * _ao2_link_debug (struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname)
int _ao2_ref (void *user_data, const int delta)
int _ao2_ref_debug (void *user_data, const int delta, char *tag, char *file, int line, const char *funcname)
void * _ao2_unlink (struct ao2_container *c, void *user_data)
void * _ao2_unlink_debug (struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname)
void ao2_bt (void)
int ao2_container_count (struct ao2_container *c)
 Returns the number of elements in a container.
ao2_iterator ao2_iterator_init (struct ao2_container *c, int flags)
int ao2_lock (void *user_data)
 Lock an object.
int ao2_match_by_addr (void *user_data, void *arg, int flags)
 another convenience function is a callback that matches on address
void * ao2_object_get_lockaddr (void *obj)
 Return the lock address of an object.
int ao2_trylock (void *user_data)
 Try locking-- (don't block if fail).
int ao2_unlock (void *user_data)
 Unlock an object.
int astobj2_init (void)
static int cb_true (void *user_data, void *arg, int flags)
 special callback that matches all
static int cd_cb (void *obj, void *arg, int flag)
static int cd_cb_debug (void *obj, void *arg, int flag)
static void container_destruct (void *c)
static void container_destruct_debug (void *c)
static int hash_zero (const void *user_obj, const int flags)
 always zero hash function
static struct astobj2INTERNAL_OBJ (void *user_data)
 convert from a pointer _p to a user-defined object


Define Documentation

#define AO2_MAGIC   0xa570b123

Definition at line 51 of file astobj2.c.

Referenced by __ao2_alloc(), and INTERNAL_OBJ().

#define EXTERNAL_OBJ ( _p   )     ((_p) == NULL ? NULL : (_p)->user_data)

convert from a pointer _p to an astobj2 object

Returns:
the pointer to the user-defined portion.

Definition at line 128 of file astobj2.c.

Referenced by __ao2_alloc(), and __ao2_callback().

#define N1   20

Referenced by ao2_bt().

#define REF_FILE   "/tmp/refs"

Definition at line 28 of file astobj2.c.

Referenced by _ao2_alloc_debug(), and _ao2_ref_debug().


Function Documentation

static void * __ao2_alloc ( size_t  data_size,
ao2_destructor_fn  destructor_fn 
) [static]

Definition at line 301 of file astobj2.c.

References AO2_MAGIC, ast_atomic_fetchadd_int(), ast_calloc, ast_mutex_init(), and EXTERNAL_OBJ.

Referenced by _ao2_alloc(), and _ao2_alloc_debug().

00302 {
00303    /* allocation */
00304    struct astobj2 *obj;
00305 
00306    if (data_size < sizeof(void *))
00307       data_size = sizeof(void *);
00308 
00309    obj = ast_calloc(1, sizeof(*obj) + data_size);
00310 
00311    if (obj == NULL)
00312       return NULL;
00313 
00314    ast_mutex_init(&obj->priv_data.lock);
00315    obj->priv_data.magic = AO2_MAGIC;
00316    obj->priv_data.data_size = data_size;
00317    obj->priv_data.ref_counter = 1;
00318    obj->priv_data.destructor_fn = destructor_fn;   /* can be NULL */
00319 
00320 #ifdef AO2_DEBUG
00321    ast_atomic_fetchadd_int(&ao2.total_objects, 1);
00322    ast_atomic_fetchadd_int(&ao2.total_mem, data_size);
00323    ast_atomic_fetchadd_int(&ao2.total_refs, 1);
00324 #endif
00325 
00326    /* return a pointer to the user data */
00327    return EXTERNAL_OBJ(obj);
00328 }

static void * __ao2_callback ( struct ao2_container c,
const enum search_flags  flags,
ao2_callback_fn cb_fn,
void *  arg,
char *  tag,
char *  file,
int  line,
const char *  funcname 
) [static]

Browse the container using different stategies accoding the flags.

Returns:
Is a pointer to an object or to a list of object if OBJ_MULTIPLE is specified. Luckily, for debug purposes, the added args (tag, file, line, funcname) aren't an excessive load to the system, as the callback should not be called as often as, say, the ao2_ref func is called.

Definition at line 585 of file astobj2.c.

References _ao2_ref(), _ao2_ref_debug(), ao2_lock(), ao2_unlock(), ast_atomic_fetchadd_int(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), bucket_list::astobj, ao2_container::buckets, cb_true(), CMP_MATCH, CMP_STOP, ao2_container::elements, bucket_list::entry, EXTERNAL_OBJ, free, ao2_container::hash_fn, INTERNAL_OBJ(), last, LOG_WARNING, match(), ao2_container::n_buckets, OBJ_MULTIPLE, OBJ_NODATA, OBJ_POINTER, OBJ_UNLINK, and ao2_container::version.

Referenced by _ao2_callback(), and _ao2_callback_debug().

00588 {
00589    int i, last;   /* search boundaries */
00590    void *ret = NULL;
00591 
00592    if (INTERNAL_OBJ(c) == NULL)  /* safety check on the argument */
00593       return NULL;
00594 
00595    if ((flags & (OBJ_MULTIPLE | OBJ_NODATA)) == OBJ_MULTIPLE) {
00596       ast_log(LOG_WARNING, "multiple data return not implemented yet (flags %x)\n", flags);
00597       return NULL;
00598    }
00599 
00600    /* override the match function if necessary */
00601    if (cb_fn == NULL)   /* if NULL, match everything */
00602       cb_fn = cb_true;
00603    /*
00604     * XXX this can be optimized.
00605     * If we have a hash function and lookup by pointer,
00606     * run the hash function. Otherwise, scan the whole container
00607     * (this only for the time being. We need to optimize this.)
00608     */
00609    if ((flags & OBJ_POINTER)) /* we know hash can handle this case */
00610       i = c->hash_fn(arg, flags & OBJ_POINTER) % c->n_buckets;
00611    else        /* don't know, let's scan all buckets */
00612       i = -1;     /* XXX this must be fixed later. */
00613 
00614    /* determine the search boundaries: i..last-1 */
00615    if (i < 0) {
00616       i = 0;
00617       last = c->n_buckets;
00618    } else {
00619       last = i + 1;
00620    }
00621 
00622    ao2_lock(c);   /* avoid modifications to the content */
00623 
00624    for (; i < last ; i++) {
00625       /* scan the list with prev-cur pointers */
00626       struct bucket_list *cur;
00627 
00628       AST_LIST_TRAVERSE_SAFE_BEGIN(&c->buckets[i], cur, entry) {
00629          int match = cb_fn(EXTERNAL_OBJ(cur->astobj), arg, flags) & (CMP_MATCH | CMP_STOP);
00630 
00631          /* we found the object, performing operations according flags */
00632          if (match == 0) { /* no match, no stop, continue */
00633             continue;
00634          } else if (match == CMP_STOP) {  /* no match but stop, we are done */
00635             i = last;
00636             break;
00637          }
00638          /* we have a match (CMP_MATCH) here */
00639          if (!(flags & OBJ_NODATA)) {  /* if must return the object, record the value */
00640             /* it is important to handle this case before the unlink */
00641             ret = EXTERNAL_OBJ(cur->astobj);
00642             if (tag)
00643                _ao2_ref_debug(ret, 1, tag, file, line, funcname);
00644             else
00645                _ao2_ref(ret, 1);
00646          }
00647 
00648          if (flags & OBJ_UNLINK) {  /* must unlink */
00649             struct bucket_list *x = cur;
00650 
00651             /* we are going to modify the container, so update version */
00652             ast_atomic_fetchadd_int(&c->version, 1);
00653             AST_LIST_REMOVE_CURRENT(entry);
00654             /* update number of elements and version */
00655             ast_atomic_fetchadd_int(&c->elements, -1);
00656             if (tag)
00657                _ao2_ref_debug(EXTERNAL_OBJ(x->astobj), -1, tag, file, line, funcname);
00658             else
00659                _ao2_ref(EXTERNAL_OBJ(x->astobj), -1);
00660             free(x); /* free the link record */
00661          }
00662 
00663          if ((match & CMP_STOP) || (flags & OBJ_MULTIPLE) == 0) {
00664             /* We found the only match we need */
00665             i = last;   /* force exit from outer loop */
00666             break;
00667          }
00668          if (!(flags & OBJ_NODATA)) {
00669 #if 0 /* XXX to be completed */
00670             /*
00671              * This is the multiple-return case. We need to link
00672              * the object in a list. The refcount is already increased.
00673              */
00674 #endif
00675          }
00676       }
00677       AST_LIST_TRAVERSE_SAFE_END;
00678    }
00679    ao2_unlock(c);
00680    return ret;
00681 }

static struct ao2_container* __ao2_container_alloc ( struct ao2_container c,
const unsigned int  n_buckets,
ao2_hash_fn hash_fn,
ao2_callback_fn cmp_fn 
) [static]

Definition at line 416 of file astobj2.c.

References ast_atomic_fetchadd_int(), ao2_container::cmp_fn, ao2_container::hash_fn, hash_zero(), ao2_container::n_buckets, and ao2_container::version.

00418 {
00419    /* XXX maybe consistency check on arguments ? */
00420    /* compute the container size */
00421 
00422    if (!c)
00423       return NULL;
00424    
00425    c->version = 1;   /* 0 is a reserved value here */
00426    c->n_buckets = n_buckets;
00427    c->hash_fn = hash_fn ? hash_fn : hash_zero;
00428    c->cmp_fn = cmp_fn;
00429 
00430 #ifdef AO2_DEBUG
00431    ast_atomic_fetchadd_int(&ao2.total_containers, 1);
00432 #endif
00433 
00434    return c;
00435 }

static struct ao2_container* __ao2_container_alloc ( struct ao2_container c,
const uint  n_buckets,
ao2_hash_fn hash_fn,
ao2_callback_fn cmp_fn 
) [static]

Referenced by _ao2_container_alloc(), and _ao2_container_alloc_debug().

static void * __ao2_iterator_next ( struct ao2_iterator a,
struct bucket_list **  q 
) [static]

Definition at line 726 of file astobj2.c.

References ao2_lock(), AST_LIST_NEXT, AST_LIST_TRAVERSE, ao2_iterator::bucket, ao2_container::buckets, ao2_iterator::c, ao2_iterator::c_version, bucket_list::entry, F_AO2I_DONTLOCK, ao2_iterator::flags, INTERNAL_OBJ(), ao2_container::n_buckets, ao2_iterator::obj, bucket_list::version, ao2_iterator::version, and ao2_container::version.

Referenced by _ao2_iterator_next(), and _ao2_iterator_next_debug().

00727 {
00728    int lim;
00729    struct bucket_list *p = NULL;
00730    void *ret = NULL;
00731 
00732    *q = NULL;
00733    
00734    if (INTERNAL_OBJ(a->c) == NULL)
00735       return NULL;
00736 
00737    if (!(a->flags & F_AO2I_DONTLOCK))
00738       ao2_lock(a->c);
00739 
00740    /* optimization. If the container is unchanged and
00741     * we have a pointer, try follow it
00742     */
00743    if (a->c->version == a->c_version && (p = a->obj) ) {
00744       if ( (p = AST_LIST_NEXT(p, entry)) )
00745          goto found;
00746       /* nope, start from the next bucket */
00747       a->bucket++;
00748       a->version = 0;
00749       a->obj = NULL;
00750    }
00751 
00752    lim = a->c->n_buckets;
00753 
00754    /* Browse the buckets array, moving to the next
00755     * buckets if we don't find the entry in the current one.
00756     * Stop when we find an element with version number greater
00757     * than the current one (we reset the version to 0 when we
00758     * switch buckets).
00759     */
00760    for (; a->bucket < lim; a->bucket++, a->version = 0) {
00761       /* scan the current bucket */
00762       AST_LIST_TRAVERSE(&a->c->buckets[a->bucket], p, entry) {
00763          if (p->version > a->version)
00764             goto found;
00765       }
00766    }
00767 
00768 found:
00769    if (p) {
00770       a->version = p->version;
00771       a->obj = p;
00772       a->c_version = a->c->version;
00773       ret = EXTERNAL_OBJ(p->astobj);
00774       /* inc refcount of returned object */
00775       *q = p;
00776    }
00777 
00778    return ret;
00779 }

static struct bucket_list * __ao2_link ( struct ao2_container c,
void *  user_data 
) [static]

Definition at line 484 of file astobj2.c.

References ao2_lock(), ast_atomic_fetchadd_int(), ast_calloc, AST_LIST_INSERT_TAIL, bucket_list::entry, INTERNAL_OBJ(), and OBJ_POINTER.

Referenced by _ao2_link(), and _ao2_link_debug().

00485 {
00486    int i;
00487    /* create a new list entry */
00488    struct bucket_list *p;
00489    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00490    
00491    if (!obj)
00492       return NULL;
00493 
00494    if (INTERNAL_OBJ(c) == NULL)
00495       return NULL;
00496 
00497    p = ast_calloc(1, sizeof(*p));
00498    if (!p)
00499       return NULL;
00500 
00501    i = c->hash_fn(user_data, OBJ_POINTER);
00502 
00503    ao2_lock(c);
00504    i %= c->n_buckets;
00505    p->astobj = obj;
00506    p->version = ast_atomic_fetchadd_int(&c->version, 1);
00507    AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
00508    ast_atomic_fetchadd_int(&c->elements, 1);
00509 
00510    /* the last two operations (ao2_ref, ao2_unlock) must be done by the calling func */
00511    return p;
00512 }

static int __ao2_ref ( void *  user_data,
const int  delta 
) [static]

Definition at line 255 of file astobj2.c.

References ast_atomic_fetchadd_int(), ast_log(), ast_mutex_destroy(), __priv_data::data_size, __priv_data::destructor_fn, free, INTERNAL_OBJ(), __priv_data::lock, LOG_ERROR, astobj2::priv_data, and __priv_data::ref_counter.

Referenced by _ao2_ref(), and _ao2_ref_debug().

00256 {
00257    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00258    int current_value;
00259    int ret;
00260 
00261    /* if delta is 0, just return the refcount */
00262    if (delta == 0)
00263       return (obj->priv_data.ref_counter);
00264 
00265    /* we modify with an atomic operation the reference counter */
00266    ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta);
00267    current_value = ret + delta;
00268 
00269 #ifdef AO2_DEBUG  
00270    ast_atomic_fetchadd_int(&ao2.total_refs, delta);
00271 #endif
00272 
00273    /* this case must never happen */
00274    if (current_value < 0)
00275       ast_log(LOG_ERROR, "refcount %d on object %p\n", current_value, user_data);
00276 
00277    if (current_value <= 0) { /* last reference, destroy the object */
00278       if (obj->priv_data.destructor_fn != NULL) {
00279          obj->priv_data.destructor_fn(user_data);
00280       }
00281 
00282       ast_mutex_destroy(&obj->priv_data.lock);
00283 #ifdef AO2_DEBUG
00284       ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size);
00285       ast_atomic_fetchadd_int(&ao2.total_objects, -1);
00286 #endif
00287       /* for safety, zero-out the astobj2 header and also the
00288        * first word of the user-data, which we make sure is always
00289        * allocated. */
00290       memset(obj, '\0', sizeof(struct astobj2 *) + sizeof(void *) );
00291       free(obj);
00292    }
00293 
00294    return ret;
00295 }

void* _ao2_alloc ( size_t  data_size,
ao2_destructor_fn  destructor_fn 
)

Definition at line 350 of file astobj2.c.

References __ao2_alloc().

Referenced by _ao2_container_alloc().

00351 {
00352    return __ao2_alloc(data_size, destructor_fn);
00353 }

void* _ao2_alloc_debug ( size_t  data_size,
ao2_destructor_fn  destructor_fn,
char *  tag,
char *  file,
int  line,
const char *  funcname 
)

Definition at line 330 of file astobj2.c.

References __ao2_alloc(), and REF_FILE.

Referenced by _ao2_container_alloc_debug().

00331 {
00332    /* allocation */
00333    void *obj;
00334    FILE *refo = fopen(REF_FILE,"a");
00335 
00336    obj = __ao2_alloc(data_size, destructor_fn);
00337 
00338    if (obj == NULL)
00339       return NULL;
00340    
00341    if (refo) {
00342       fprintf(refo, "%p =1   %s:%d:%s (%s)\n", obj, file, line, funcname, tag);
00343       fclose(refo);
00344    }
00345 
00346    /* return a pointer to the user data */
00347    return obj;
00348 }

void* _ao2_callback ( struct ao2_container c,
const enum search_flags  flags,
ao2_callback_fn cb_fn,
void *  arg 
)

Definition at line 691 of file astobj2.c.

References __ao2_callback().

Referenced by _ao2_find(), _ao2_unlink(), and container_destruct().

00693 {
00694    return __ao2_callback(c,flags, cb_fn, arg, NULL, NULL, 0, NULL);
00695 }

void* _ao2_callback_debug ( struct ao2_container c,
const enum search_flags  flags,
ao2_callback_fn cb_fn,
void *  arg,
char *  tag,
char *  file,
int  line,
const char *  funcname 
)

Definition at line 683 of file astobj2.c.

References __ao2_callback().

Referenced by _ao2_find_debug(), _ao2_unlink_debug(), and container_destruct_debug().

00687 {
00688    return __ao2_callback(c,flags, cb_fn, arg, tag, file, line, funcname);
00689 }

struct ao2_container* _ao2_container_alloc ( const unsigned int  n_buckets,
ao2_hash_fn hash_fn,
ao2_callback_fn cmp_fn 
)

Definition at line 449 of file astobj2.c.

References __ao2_container_alloc(), _ao2_alloc(), container_destruct(), and ao2_container::n_buckets.

00451 {
00452    /* XXX maybe consistency check on arguments ? */
00453    /* compute the container size */
00454 
00455    size_t container_size = sizeof(struct ao2_container) + n_buckets * sizeof(struct bucket);
00456    struct ao2_container *c = _ao2_alloc(container_size, container_destruct);
00457 
00458    return __ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn);
00459 }

struct ao2_container* _ao2_container_alloc_debug ( const unsigned int  n_buckets,
ao2_hash_fn hash_fn,
ao2_callback_fn cmp_fn,
char *  tag,
char *  file,
int  line,
const char *  funcname 
)

Definition at line 437 of file astobj2.c.

References __ao2_container_alloc(), _ao2_alloc_debug(), container_destruct_debug(), and ao2_container::n_buckets.

00439 {
00440    /* XXX maybe consistency check on arguments ? */
00441    /* compute the container size */
00442    size_t container_size = sizeof(struct ao2_container) + n_buckets * sizeof(struct bucket);
00443    struct ao2_container *c = _ao2_alloc_debug(container_size, container_destruct_debug, tag, file, line, funcname);
00444 
00445    return __ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn);
00446 }

void* _ao2_find ( struct ao2_container c,
void *  arg,
enum search_flags  flags 
)

Definition at line 705 of file astobj2.c.

References _ao2_callback(), and ao2_container::cmp_fn.

00706 {
00707    return _ao2_callback(c, flags, c->cmp_fn, arg);
00708 }

void* _ao2_find_debug ( struct ao2_container c,
void *  arg,
enum search_flags  flags,
char *  tag,
char *  file,
int  line,
const char *  funcname 
)

the find function just invokes the default callback with some reasonable flags.

Definition at line 700 of file astobj2.c.

References _ao2_callback_debug(), and ao2_container::cmp_fn.

00701 {
00702    return _ao2_callback_debug(c, flags, c->cmp_fn, arg, tag, file, line, funcname);
00703 }

void* _ao2_iterator_next ( struct ao2_iterator a  ) 

Definition at line 799 of file astobj2.c.

References __ao2_iterator_next(), _ao2_ref(), ao2_unlock(), ao2_iterator::c, F_AO2I_DONTLOCK, and ao2_iterator::flags.

00800 {
00801    struct bucket_list *p = NULL;
00802    void *ret = NULL;
00803 
00804    ret = __ao2_iterator_next(a, &p);
00805    
00806    if (p) {
00807       /* inc refcount of returned object */
00808       _ao2_ref(ret, 1);
00809    }
00810 
00811    if (!(a->flags & F_AO2I_DONTLOCK))
00812       ao2_unlock(a->c);
00813 
00814    return ret;
00815 }

void* _ao2_iterator_next_debug ( struct ao2_iterator a,
char *  tag,
char *  file,
int  line,
const char *  funcname 
)

Definition at line 781 of file astobj2.c.

References __ao2_iterator_next(), _ao2_ref_debug(), ao2_unlock(), ao2_iterator::c, F_AO2I_DONTLOCK, and ao2_iterator::flags.

00782 {
00783    struct bucket_list *p;
00784    void *ret = NULL;
00785 
00786    ret = __ao2_iterator_next(a, &p);
00787    
00788    if (p) {
00789       /* inc refcount of returned object */
00790       _ao2_ref_debug(ret, 1, tag, file, line, funcname);
00791    }
00792 
00793    if (!(a->flags & F_AO2I_DONTLOCK))
00794       ao2_unlock(a->c);
00795 
00796    return ret;
00797 }

void* _ao2_link ( struct ao2_container c,
void *  user_data 
)

Definition at line 525 of file astobj2.c.

References __ao2_link(), _ao2_ref(), and ao2_unlock().

00526 {
00527    struct bucket_list *p = __ao2_link(c, user_data);
00528    
00529    if (p) {
00530       _ao2_ref(user_data, +1);
00531       ao2_unlock(c);
00532    }
00533    return p;
00534 }

void* _ao2_link_debug ( struct ao2_container c,
void *  user_data,
char *  tag,
char *  file,
int  line,
const char *  funcname 
)

Definition at line 514 of file astobj2.c.

References __ao2_link(), _ao2_ref_debug(), and ao2_unlock().

00515 {
00516    struct bucket_list *p = __ao2_link(c, user_data);
00517    
00518    if (p) {
00519       _ao2_ref_debug(user_data, +1, tag, file, line, funcname);
00520       ao2_unlock(c);
00521    }
00522    return p;
00523 }

int _ao2_ref ( void *  user_data,
const int  delta 
)

Definition at line 245 of file astobj2.c.

References __ao2_ref(), and INTERNAL_OBJ().

Referenced by __ao2_callback(), _ao2_iterator_next(), _ao2_link(), and cd_cb().

00246 {
00247    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00248 
00249    if (obj == NULL)
00250       return -1;
00251 
00252    return __ao2_ref(user_data, delta);
00253 }

int _ao2_ref_debug ( void *  user_data,
const int  delta,
char *  tag,
char *  file,
int  line,
const char *  funcname 
)

Definition at line 225 of file astobj2.c.

References __ao2_ref(), __priv_data::destructor_fn, INTERNAL_OBJ(), astobj2::priv_data, __priv_data::ref_counter, and REF_FILE.

Referenced by __ao2_callback(), _ao2_iterator_next_debug(), _ao2_link_debug(), and cd_cb_debug().

00226 {
00227    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00228    
00229    if (obj == NULL)
00230       return -1;
00231 
00232    if (delta != 0) {
00233       FILE *refo = fopen(REF_FILE,"a");
00234       fprintf(refo, "%p %s%d   %s:%d:%s (%s) [@%d]\n", user_data, (delta<0? "":"+"), delta, file, line, funcname, tag, obj->priv_data.ref_counter);
00235       fclose(refo);
00236    }
00237    if (obj->priv_data.ref_counter + delta == 0 && obj->priv_data.destructor_fn != NULL) { /* this isn't protected with lock; just for o/p */
00238          FILE *refo = fopen(REF_FILE,"a");    
00239          fprintf(refo, "%p **call destructor** %s:%d:%s (%s)\n", user_data, file, line, funcname, tag);   
00240          fclose(refo);
00241    }
00242    return __ao2_ref(user_data, delta);
00243 }

void* _ao2_unlink ( struct ao2_container c,
void *  user_data 
)

Definition at line 559 of file astobj2.c.

References _ao2_callback(), ao2_match_by_addr, INTERNAL_OBJ(), OBJ_NODATA, OBJ_POINTER, and OBJ_UNLINK.

00560 {
00561    if (INTERNAL_OBJ(user_data) == NULL)   /* safety check on the argument */
00562       return NULL;
00563 
00564    _ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data);
00565 
00566    return NULL;
00567 }

void* _ao2_unlink_debug ( struct ao2_container c,
void *  user_data,
char *  tag,
char *  file,
int  line,
const char *  funcname 
)

Definition at line 548 of file astobj2.c.

References _ao2_callback_debug(), ao2_match_by_addr, INTERNAL_OBJ(), OBJ_NODATA, OBJ_POINTER, and OBJ_UNLINK.

00550 {
00551    if (INTERNAL_OBJ(user_data) == NULL)   /* safety check on the argument */
00552       return NULL;
00553 
00554    _ao2_callback_debug(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data, tag, file, line, funcname);
00555 
00556    return NULL;
00557 }

void ao2_bt ( void   ) 

Definition at line 83 of file astobj2.c.

References ast_verbose, free, and N1.

00084 {
00085    int c, i;
00086 #define N1  20
00087    void *addresses[N1];
00088    char **strings;
00089 
00090    c = backtrace(addresses, N1);
00091    strings = backtrace_symbols(addresses,c);
00092    ast_verbose("backtrace returned: %d\n", c);
00093    for(i = 0; i < c; i++) {
00094       ast_verbose("%d: %p %s\n", i, addresses[i], strings[i]);
00095    }
00096    free(strings);
00097 }

int ao2_container_count ( struct ao2_container c  ) 

Returns the number of elements in a container.

return the number of elements in the container

Definition at line 464 of file astobj2.c.

References ao2_container::elements.

Referenced by __queues_show(), _sip_show_peers(), cli_tps_report(), do_timing(), and pthread_timer_open().

00465 {
00466    return c->elements;
00467 }

struct ao2_iterator ao2_iterator_init ( struct ao2_container c,
int  flags 
)

initialize an iterator so we start from the first object

Definition at line 713 of file astobj2.c.

References ao2_iterator::c, and ao2_iterator::flags.

Referenced by __iax2_show_peers(), __queues_show(), _sip_show_peers(), ast_odbc_request_obj(), authenticate_reply(), check_access(), cli_console_active(), cli_list_devices(), cli_tps_report(), compare_weight(), complete_iax2_peers(), complete_iax2_unregister(), complete_queue(), complete_queue_remove_member(), complete_sip_peer(), complete_sip_registered_peer(), complete_sip_user(), complete_sipch(), delete_profiles(), delete_routes(), delete_users(), destroy_pvts(), dialgroup_read(), do_parking_thread(), dump_queue_members(), free_members(), get_member_status(), handle_cli_iax2_show_users(), handle_cli_moh_show_classes(), handle_cli_moh_show_files(), handle_cli_odbc_show(), handle_feature_show(), handle_parkedcalls(), handle_request_subscribe(), handle_show_routes(), iax2_getpeername(), iax2_getpeertrunk(), interface_exists(), interface_exists_global(), manager_iax2_show_peer_list(), manager_parking_status(), manager_queues_status(), manager_queues_summary(), num_available_members(), poke_all_peers(), pp_each_user_exec(), prune_peers(), prune_users(), queue_function_qac(), queue_function_qac_dep(), queue_function_queuememberlist(), reload(), reload_queues(), rt_handle_member_record(), set_member_paused(), set_member_penalty(), sip_poke_all_peers(), sip_prune_realtime(), sip_show_channel(), sip_show_history(), sip_show_inuse(), sip_show_users(), stop_streams(), tps_taskprocessor_tab_complete(), try_calling(), unload_module(), update_queue(), update_realtime_members(), and update_status().

00714 {
00715    struct ao2_iterator a = {
00716       .c = c,
00717       .flags = flags
00718    };
00719    
00720    return a;
00721 }

int ao2_lock ( void *  a  ) 

Lock an object.

Parameters:
a A pointer to the object we want to lock.
Returns:
0 on success, other values on error.

Definition at line 143 of file astobj2.c.

References ast_atomic_fetchadd_int(), ast_mutex_lock(), INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.

Referenced by __ao2_callback(), __ao2_iterator_next(), __ao2_link(), __queues_show(), _sip_show_peers(), add_to_queue(), ast_taskprocessor_get(), ast_taskprocessor_unreference(), build_parkinglot(), compare_weight(), complete_queue_remove_member(), complete_sip_user(), dialog_needdestroy(), end_bridge_callback(), find_call(), find_queue_by_name_rt(), get_member_penalty(), get_member_status(), handle_request_subscribe(), interface_exists_global(), is_our_turn(), join_queue(), leave_queue(), load_config(), load_realtime_queue(), manager_queues_status(), manager_queues_summary(), moh_release(), mohalloc(), monmp3thread(), mwi_event_cb(), pthread_timer_disable_continuous(), pthread_timer_enable_continuous(), pthread_timer_open(), pthread_timer_set_rate(), queue_function_qac(), queue_function_qac_dep(), queue_function_queuememberlist(), queue_function_queuewaitingcount(), queue_function_var(), recalc_holdtime(), record_abandoned(), reload_queue_members(), reload_queues(), remove_from_queue(), ring_entry(), run_timer(), set_member_paused(), set_member_penalty(), sip_poke_all_peers(), sip_prune_realtime(), sip_show_inuse(), sip_show_user(), sip_show_users(), try_calling(), update_call_counter(), update_queue(), update_realtime_members(), and update_status().

00147 {
00148    struct astobj2 *p = INTERNAL_OBJ(user_data);
00149 
00150    if (p == NULL)
00151       return -1;
00152 
00153 #ifdef AO2_DEBUG
00154    ast_atomic_fetchadd_int(&ao2.total_locked, 1);
00155 #endif
00156 
00157 #ifndef DEBUG_THREADS
00158    return ast_mutex_lock(&p->priv_data.lock);
00159 #else
00160    return __ast_pthread_mutex_lock(file, line, func, var, &p->priv_data.lock);
00161 #endif
00162 }

int ao2_match_by_addr ( void *  user_data,
void *  arg,
int  flags 
)

another convenience function is a callback that matches on address

Definition at line 539 of file astobj2.c.

References CMP_MATCH, and CMP_STOP.

00540 {
00541    return (user_data == arg) ? (CMP_MATCH | CMP_STOP) : 0;
00542 }

void* ao2_object_get_lockaddr ( void *  obj  ) 

Return the lock address of an object.

Parameters:
[in] obj A pointer to the object we want.
Returns:
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.

Since:
1.6.1

Definition at line 210 of file astobj2.c.

References INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.

00211 {
00212    struct astobj2 *p = INTERNAL_OBJ(obj);
00213    
00214    if (p == NULL)
00215       return NULL;
00216 
00217    return &p->priv_data.lock;
00218 }

int ao2_trylock ( void *  a  ) 

Try locking-- (don't block if fail).

Parameters:
a A pointer to the object we want to lock.
Returns:
0 on success, other values on error.

Definition at line 187 of file astobj2.c.

References ast_atomic_fetchadd_int(), ast_mutex_trylock(), INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.

00191 {
00192    struct astobj2 *p = INTERNAL_OBJ(user_data);
00193    int ret;
00194    
00195    if (p == NULL)
00196       return -1;
00197 #ifndef DEBUG_THREADS
00198    ret = ast_mutex_trylock(&p->priv_data.lock);
00199 #else
00200    ret = __ast_pthread_mutex_trylock(file, line, func, var, &p->priv_data.lock);
00201 #endif
00202 
00203 #ifdef AO2_DEBUG
00204    if (!ret)
00205       ast_atomic_fetchadd_int(&ao2.total_locked, 1);
00206 #endif
00207    return ret;
00208 }

int ao2_unlock ( void *  a  ) 

Unlock an object.

Parameters:
a A pointer to the object we want unlock.
Returns:
0 on success, other values on error.

Definition at line 165 of file astobj2.c.

References ast_atomic_fetchadd_int(), ast_mutex_unlock(), INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.

Referenced by __ao2_callback(), __queues_show(), _ao2_iterator_next(), _ao2_iterator_next_debug(), _ao2_link(), _ao2_link_debug(), _sip_show_peers(), add_to_queue(), ast_taskprocessor_get(), ast_taskprocessor_unreference(), build_parkinglot(), compare_weight(), complete_queue_remove_member(), complete_sip_user(), dialog_needdestroy(), end_bridge_callback(), find_call(), find_queue_by_name_rt(), get_member_penalty(), get_member_status(), handle_request_subscribe(), interface_exists_global(), is_our_turn(), join_queue(), leave_queue(), load_config(), load_realtime_queue(), manager_queues_status(), manager_queues_summary(), moh_release(), mohalloc(), monmp3thread(), mwi_event_cb(), pthread_timer_disable_continuous(), pthread_timer_enable_continuous(), pthread_timer_open(), pthread_timer_set_rate(), queue_function_qac(), queue_function_qac_dep(), queue_function_queuememberlist(), queue_function_queuewaitingcount(), queue_function_var(), recalc_holdtime(), record_abandoned(), reload_queue_members(), reload_queues(), remove_from_queue(), ring_entry(), run_timer(), set_member_paused(), set_member_penalty(), sip_poke_all_peers(), sip_prune_realtime(), sip_show_inuse(), sip_show_user(), sip_show_users(), try_calling(), update_call_counter(), update_queue(), update_realtime_members(), and update_status().

00169 {
00170    struct astobj2 *p = INTERNAL_OBJ(user_data);
00171 
00172    if (p == NULL)
00173       return -1;
00174 
00175 #ifdef AO2_DEBUG
00176    ast_atomic_fetchadd_int(&ao2.total_locked, -1);
00177 #endif
00178 
00179 #ifndef DEBUG_THREADS
00180    return ast_mutex_unlock(&p->priv_data.lock);
00181 #else
00182    return __ast_pthread_mutex_unlock(file, line, func, var, &p->priv_data.lock);
00183 #endif
00184 }

int astobj2_init ( void   ) 

Provided by astobj2.c

Definition at line 1003 of file astobj2.c.

References ARRAY_LEN, and ast_cli_register_multiple().

Referenced by main().

01004 {
01005 #ifdef AO2_DEBUG
01006    ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
01007 #endif
01008 
01009    return 0;
01010 }

static int cb_true ( void *  user_data,
void *  arg,
int  flags 
) [static]

special callback that matches all

Definition at line 572 of file astobj2.c.

References CMP_MATCH.

Referenced by __ao2_callback().

00573 {
00574    return CMP_MATCH;
00575 }

static int cd_cb ( void *  obj,
void *  arg,
int  flag 
) [static]

Definition at line 820 of file astobj2.c.

References _ao2_ref().

Referenced by container_destruct().

00821 {
00822    _ao2_ref(obj, -1);
00823    return 0;
00824 }

static int cd_cb_debug ( void *  obj,
void *  arg,
int  flag 
) [static]

Definition at line 826 of file astobj2.c.

References _ao2_ref_debug().

Referenced by container_destruct_debug().

00827 {
00828    _ao2_ref_debug(obj, -1, "deref object via container destroy",  __FILE__, __LINE__, __PRETTY_FUNCTION__);
00829    return 0;
00830 }

static void container_destruct ( void *  c  )  [static]

Definition at line 832 of file astobj2.c.

References _ao2_callback(), ast_free, AST_LIST_REMOVE_HEAD, ao2_container::buckets, cd_cb(), bucket_list::entry, ao2_container::n_buckets, and OBJ_UNLINK.

Referenced by _ao2_container_alloc().

00833 {
00834    struct ao2_container *c = _c;
00835    int i;
00836 
00837    _ao2_callback(c, OBJ_UNLINK, cd_cb, NULL);
00838 
00839    for (i = 0; i < c->n_buckets; i++) {
00840       struct bucket_list *current;
00841 
00842       while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) {
00843          ast_free(current);
00844       }
00845    }
00846 
00847 #ifdef AO2_DEBUG
00848    ast_atomic_fetchadd_int(&ao2.total_containers, -1);
00849 #endif
00850 }

static void container_destruct_debug ( void *  c  )  [static]

Definition at line 852 of file astobj2.c.

References _ao2_callback_debug(), ast_free, AST_LIST_REMOVE_HEAD, ao2_container::buckets, cd_cb_debug(), ao2_container::n_buckets, and OBJ_UNLINK.

Referenced by _ao2_container_alloc_debug().

00853 {
00854    struct ao2_container *c = _c;
00855    int i;
00856 
00857    _ao2_callback_debug(c, OBJ_UNLINK, cd_cb_debug, NULL, "container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__);
00858 
00859    for (i = 0; i < c->n_buckets; i++) {
00860       struct bucket_list *current;
00861 
00862       while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) {
00863          ast_free(current);
00864       }
00865    }
00866 
00867 #ifdef AO2_DEBUG
00868    ast_atomic_fetchadd_int(&ao2.total_containers, -1);
00869 #endif
00870 }

static int hash_zero ( const void *  user_obj,
const int  flags 
) [static]

always zero hash function

it is convenient to have a hash function that always returns 0. This is basically used when we want to have a container that is a simple linked list.

Returns:
0

Definition at line 408 of file astobj2.c.

Referenced by __ao2_container_alloc().

00409 {
00410    return 0;
00411 }

static struct astobj2* INTERNAL_OBJ ( void *  user_data  )  [inline, static]

convert from a pointer _p to a user-defined object

Returns:
the pointer to the astobj2 structure

Definition at line 105 of file astobj2.c.

References AO2_MAGIC, ast_log(), and LOG_ERROR.

Referenced by __ao2_callback(), __ao2_iterator_next(), __ao2_link(), __ao2_ref(), _ao2_ref(), _ao2_ref_debug(), _ao2_unlink(), _ao2_unlink_debug(), ao2_lock(), ao2_object_get_lockaddr(), ao2_trylock(), and ao2_unlock().

00106 {
00107    struct astobj2 *p;
00108 
00109    if (!user_data) {
00110       ast_log(LOG_ERROR, "user_data is NULL\n");
00111       return NULL;
00112    }
00113 
00114    p = (struct astobj2 *) ((char *) user_data - sizeof(*p));
00115    if (AO2_MAGIC != (p->priv_data.magic) ) {
00116       ast_log(LOG_ERROR, "bad magic number 0x%x for %p\n", p->priv_data.magic, p);
00117       p = NULL;
00118    }
00119 
00120    return p;
00121 }


Generated on Fri Jun 19 12:10:07 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7