Wed Aug 18 22:34:04 2010

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, const char *file, int line, const char *funcname)
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, const char *file, int line, const char *funcname, int ref_debug)
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, int ref_debug)
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_lock (void *user_data, const char *file, const char *func, int line, const char *var)
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)
int _ao2_trylock (void *user_data, const char *file, const char *func, int line, const char *var)
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)
int _ao2_unlock (void *user_data, const char *file, const char *func, int line, const char *var)
void ao2_bt (void)
int ao2_container_count (struct ao2_container *c)
 Returns the number of elements in a container.
void ao2_iterator_destroy (struct ao2_iterator *i)
 Destroy a container iterator.
ao2_iterator ao2_iterator_init (struct ao2_container *c, int flags)
 Create an iterator for a container.
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,
const char *  file,
int  line,
const char *  funcname 
) [static]

Definition at line 342 of file astobj2.c.

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

Referenced by _ao2_alloc(), and _ao2_alloc_debug().

00343 {
00344    /* allocation */
00345    struct astobj2 *obj;
00346 
00347    if (data_size < sizeof(void *))
00348       data_size = sizeof(void *);
00349 
00350 #if defined(__AST_DEBUG_MALLOC)
00351    obj = __ast_calloc(1, sizeof(*obj) + data_size, file, line, funcname);
00352 #else
00353    obj = ast_calloc(1, sizeof(*obj) + data_size);
00354 #endif
00355 
00356    if (obj == NULL)
00357       return NULL;
00358 
00359    ast_mutex_init(&obj->priv_data.lock);
00360    obj->priv_data.magic = AO2_MAGIC;
00361    obj->priv_data.data_size = data_size;
00362    obj->priv_data.ref_counter = 1;
00363    obj->priv_data.destructor_fn = destructor_fn;   /* can be NULL */
00364 
00365 #ifdef AO2_DEBUG
00366    ast_atomic_fetchadd_int(&ao2.total_objects, 1);
00367    ast_atomic_fetchadd_int(&ao2.total_mem, data_size);
00368    ast_atomic_fetchadd_int(&ao2.total_refs, 1);
00369 #endif
00370 
00371    /* return a pointer to the user data */
00372    return EXTERNAL_OBJ(obj);
00373 }

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 632 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_CONTINUE, OBJ_MULTIPLE, OBJ_NODATA, OBJ_POINTER, OBJ_UNLINK, and ao2_container::version.

Referenced by _ao2_callback(), and _ao2_callback_debug().

00635 {
00636    int i, start, last;  /* search boundaries */
00637    void *ret = NULL;
00638 
00639    if (INTERNAL_OBJ(c) == NULL)  /* safety check on the argument */
00640       return NULL;
00641 
00642    if ((flags & (OBJ_MULTIPLE | OBJ_NODATA)) == OBJ_MULTIPLE) {
00643       ast_log(LOG_WARNING, "multiple data return not implemented yet (flags %x)\n", flags);
00644       return NULL;
00645    }
00646 
00647    /* override the match function if necessary */
00648    if (cb_fn == NULL)   /* if NULL, match everything */
00649       cb_fn = cb_true;
00650    /*
00651     * XXX this can be optimized.
00652     * If we have a hash function and lookup by pointer,
00653     * run the hash function. Otherwise, scan the whole container
00654     * (this only for the time being. We need to optimize this.)
00655     */
00656    if ((flags & OBJ_POINTER)) /* we know hash can handle this case */
00657       start = i = c->hash_fn(arg, flags & OBJ_POINTER) % c->n_buckets;
00658    else        /* don't know, let's scan all buckets */
00659       start = i = -1;      /* XXX this must be fixed later. */
00660 
00661    /* determine the search boundaries: i..last-1 */
00662    if (i < 0) {
00663       start = i = 0;
00664       last = c->n_buckets;
00665    } else if ((flags & OBJ_CONTINUE)) {
00666       last = c->n_buckets;
00667    } else {
00668       last = i + 1;
00669    }
00670 
00671    ao2_lock(c);   /* avoid modifications to the content */
00672 
00673    for (; i < last ; i++) {
00674       /* scan the list with prev-cur pointers */
00675       struct bucket_list *cur;
00676 
00677       AST_LIST_TRAVERSE_SAFE_BEGIN(&c->buckets[i], cur, entry) {
00678          int match = cb_fn(EXTERNAL_OBJ(cur->astobj), arg, flags) & (CMP_MATCH | CMP_STOP);
00679 
00680          /* we found the object, performing operations according flags */
00681          if (match == 0) { /* no match, no stop, continue */
00682             continue;
00683          } else if (match == CMP_STOP) {  /* no match but stop, we are done */
00684             i = last;
00685             break;
00686          }
00687          /* we have a match (CMP_MATCH) here */
00688          if (!(flags & OBJ_NODATA)) {  /* if must return the object, record the value */
00689             /* it is important to handle this case before the unlink */
00690             ret = EXTERNAL_OBJ(cur->astobj);
00691             if (tag)
00692                _ao2_ref_debug(ret, 1, tag, file, line, funcname);
00693             else
00694                _ao2_ref(ret, 1);
00695          }
00696 
00697          if (flags & OBJ_UNLINK) {  /* must unlink */
00698             struct bucket_list *x = cur;
00699 
00700             /* we are going to modify the container, so update version */
00701             ast_atomic_fetchadd_int(&c->version, 1);
00702             AST_LIST_REMOVE_CURRENT(entry);
00703             /* update number of elements and version */
00704             ast_atomic_fetchadd_int(&c->elements, -1);
00705             if (tag)
00706                _ao2_ref_debug(EXTERNAL_OBJ(x->astobj), -1, tag, file, line, funcname);
00707             else
00708                _ao2_ref(EXTERNAL_OBJ(x->astobj), -1);
00709             free(x); /* free the link record */
00710          }
00711 
00712          if ((match & CMP_STOP) || (flags & OBJ_MULTIPLE) == 0) {
00713             /* We found the only match we need */
00714             i = last;   /* force exit from outer loop */
00715             break;
00716          }
00717          if (!(flags & OBJ_NODATA)) {
00718 #if 0 /* XXX to be completed */
00719             /*
00720              * This is the multiple-return case. We need to link
00721              * the object in a list. The refcount is already increased.
00722              */
00723 #endif
00724          }
00725       }
00726       AST_LIST_TRAVERSE_SAFE_END;
00727 
00728       if (ret) {
00729          /* This assumes OBJ_MULTIPLE with !OBJ_NODATA is still not implemented */
00730          break;
00731       }
00732 
00733       if (i == c->n_buckets - 1 && (flags & OBJ_POINTER) && (flags & OBJ_CONTINUE)) {
00734          /* Move to the beginning to ensure we check every bucket */
00735          i = -1;
00736          last = start;
00737       }
00738    }
00739    ao2_unlock(c);
00740    return ret;
00741 }

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 462 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.

00464 {
00465    /* XXX maybe consistency check on arguments ? */
00466    /* compute the container size */
00467 
00468    if (!c)
00469       return NULL;
00470    
00471    c->version = 1;   /* 0 is a reserved value here */
00472    c->n_buckets = n_buckets;
00473    c->hash_fn = hash_fn ? hash_fn : hash_zero;
00474    c->cmp_fn = cmp_fn;
00475 
00476 #ifdef AO2_DEBUG
00477    ast_atomic_fetchadd_int(&ao2.total_containers, 1);
00478 #endif
00479 
00480    return c;
00481 }

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 797 of file astobj2.c.

References AO2_ITERATOR_DONTLOCK, ao2_lock(), AST_LIST_NEXT, AST_LIST_TRAVERSE, ao2_iterator::bucket, ao2_container::buckets, ao2_iterator::c, ao2_iterator::c_version, bucket_list::entry, 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().

00798 {
00799    int lim;
00800    struct bucket_list *p = NULL;
00801    void *ret = NULL;
00802 
00803    *q = NULL;
00804    
00805    if (INTERNAL_OBJ(a->c) == NULL)
00806       return NULL;
00807 
00808    if (!(a->flags & AO2_ITERATOR_DONTLOCK))
00809       ao2_lock(a->c);
00810 
00811    /* optimization. If the container is unchanged and
00812     * we have a pointer, try follow it
00813     */
00814    if (a->c->version == a->c_version && (p = a->obj) ) {
00815       if ( (p = AST_LIST_NEXT(p, entry)) )
00816          goto found;
00817       /* nope, start from the next bucket */
00818       a->bucket++;
00819       a->version = 0;
00820       a->obj = NULL;
00821    }
00822 
00823    lim = a->c->n_buckets;
00824 
00825    /* Browse the buckets array, moving to the next
00826     * buckets if we don't find the entry in the current one.
00827     * Stop when we find an element with version number greater
00828     * than the current one (we reset the version to 0 when we
00829     * switch buckets).
00830     */
00831    for (; a->bucket < lim; a->bucket++, a->version = 0) {
00832       /* scan the current bucket */
00833       AST_LIST_TRAVERSE(&a->c->buckets[a->bucket], p, entry) {
00834          if (p->version > a->version)
00835             goto found;
00836       }
00837    }
00838 
00839 found:
00840    if (p) {
00841       a->version = p->version;
00842       a->obj = p;
00843       a->c_version = a->c->version;
00844       ret = EXTERNAL_OBJ(p->astobj);
00845       /* inc refcount of returned object */
00846       *q = p;
00847    }
00848 
00849    return ret;
00850 }

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

Definition at line 531 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().

00532 {
00533    int i;
00534    /* create a new list entry */
00535    struct bucket_list *p;
00536    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00537    
00538    if (obj == NULL)
00539       return NULL;
00540 
00541    if (INTERNAL_OBJ(c) == NULL)
00542       return NULL;
00543 
00544    p = ast_calloc(1, sizeof(*p));
00545    if (!p)
00546       return NULL;
00547 
00548    i = abs(c->hash_fn(user_data, OBJ_POINTER));
00549 
00550    ao2_lock(c);
00551    i %= c->n_buckets;
00552    p->astobj = obj;
00553    p->version = ast_atomic_fetchadd_int(&c->version, 1);
00554    AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
00555    ast_atomic_fetchadd_int(&c->elements, 1);
00556 
00557    /* the last two operations (ao2_ref, ao2_unlock) must be done by the calling func */
00558    return p;
00559 }

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

Definition at line 293 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().

00294 {
00295    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00296    int current_value;
00297    int ret;
00298 
00299    if (obj == NULL)
00300       return -1;
00301 
00302    /* if delta is 0, just return the refcount */
00303    if (delta == 0)
00304       return (obj->priv_data.ref_counter);
00305 
00306    /* we modify with an atomic operation the reference counter */
00307    ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta);
00308    current_value = ret + delta;
00309 
00310 #ifdef AO2_DEBUG  
00311    ast_atomic_fetchadd_int(&ao2.total_refs, delta);
00312 #endif
00313 
00314    /* this case must never happen */
00315    if (current_value < 0)
00316       ast_log(LOG_ERROR, "refcount %d on object %p\n", current_value, user_data);
00317 
00318    if (current_value <= 0) { /* last reference, destroy the object */
00319       if (obj->priv_data.destructor_fn != NULL) {
00320          obj->priv_data.destructor_fn(user_data);
00321       }
00322 
00323       ast_mutex_destroy(&obj->priv_data.lock);
00324 #ifdef AO2_DEBUG
00325       ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size);
00326       ast_atomic_fetchadd_int(&ao2.total_objects, -1);
00327 #endif
00328       /* for safety, zero-out the astobj2 header and also the
00329        * first word of the user-data, which we make sure is always
00330        * allocated. */
00331       memset(obj, '\0', sizeof(struct astobj2 *) + sizeof(void *) );
00332       free(obj);
00333    }
00334 
00335    return ret;
00336 }

void* _ao2_alloc ( size_t  data_size,
ao2_destructor_fn  destructor_fn 
)

Definition at line 396 of file astobj2.c.

References __ao2_alloc().

Referenced by _ao2_container_alloc().

00397 {
00398    return __ao2_alloc(data_size, destructor_fn, __FILE__, __LINE__, __FUNCTION__);
00399 }

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

Definition at line 375 of file astobj2.c.

References __ao2_alloc(), and REF_FILE.

Referenced by _ao2_container_alloc_debug(), and _moh_class_malloc().

00377 {
00378    /* allocation */
00379    void *obj;
00380    FILE *refo = ref_debug ? fopen(REF_FILE,"a") : NULL;
00381 
00382    obj = __ao2_alloc(data_size, destructor_fn, file, line, funcname);
00383 
00384    if (obj == NULL)
00385       return NULL;
00386    
00387    if (refo) {
00388       fprintf(refo, "%p =1   %s:%d:%s (%s)\n", obj, file, line, funcname, tag);
00389       fclose(refo);
00390    }
00391 
00392    /* return a pointer to the user data */
00393    return obj;
00394 }

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

Definition at line 751 of file astobj2.c.

References __ao2_callback().

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

00753 {
00754    return __ao2_callback(c,flags, cb_fn, arg, NULL, NULL, 0, NULL);
00755 }

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 743 of file astobj2.c.

References __ao2_callback().

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

00747 {
00748    return __ao2_callback(c,flags, cb_fn, arg, tag, file, line, funcname);
00749 }

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

Definition at line 496 of file astobj2.c.

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

00498 {
00499    /* XXX maybe consistency check on arguments ? */
00500    /* compute the container size */
00501 
00502    size_t container_size = sizeof(struct ao2_container) + n_buckets * sizeof(struct bucket);
00503    struct ao2_container *c = _ao2_alloc(container_size, container_destruct);
00504 
00505    return __ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn);
00506 }

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,
int  ref_debug 
)

Definition at line 483 of file astobj2.c.

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

00486 {
00487    /* XXX maybe consistency check on arguments ? */
00488    /* compute the container size */
00489    size_t container_size = sizeof(struct ao2_container) + n_buckets * sizeof(struct bucket);
00490    struct ao2_container *c = _ao2_alloc_debug(container_size, container_destruct_debug, tag, file, line, funcname, ref_debug);
00491 
00492    return __ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn);
00493 }

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

Definition at line 765 of file astobj2.c.

References _ao2_callback(), and ao2_container::cmp_fn.

Referenced by _get_mohbyname().

00766 {
00767    return _ao2_callback(c, flags, c->cmp_fn, arg);
00768 }

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 760 of file astobj2.c.

References _ao2_callback_debug(), and ao2_container::cmp_fn.

Referenced by _get_mohbyname().

00761 {
00762    return _ao2_callback_debug(c, flags, c->cmp_fn, arg, tag, file, line, funcname);
00763 }

void* _ao2_iterator_next ( struct ao2_iterator a  ) 

Definition at line 870 of file astobj2.c.

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

00871 {
00872    struct bucket_list *p = NULL;
00873    void *ret = NULL;
00874 
00875    ret = __ao2_iterator_next(a, &p);
00876    
00877    if (p) {
00878       /* inc refcount of returned object */
00879       _ao2_ref(ret, 1);
00880    }
00881 
00882    if (!(a->flags & AO2_ITERATOR_DONTLOCK))
00883       ao2_unlock(a->c);
00884 
00885    return ret;
00886 }

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

Definition at line 852 of file astobj2.c.

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

00853 {
00854    struct bucket_list *p;
00855    void *ret = NULL;
00856 
00857    ret = __ao2_iterator_next(a, &p);
00858    
00859    if (p) {
00860       /* inc refcount of returned object */
00861       _ao2_ref_debug(ret, 1, tag, file, line, funcname);
00862    }
00863 
00864    if (!(a->flags & AO2_ITERATOR_DONTLOCK))
00865       ao2_unlock(a->c);
00866 
00867    return ret;
00868 }

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

Definition at line 572 of file astobj2.c.

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

00573 {
00574    struct bucket_list *p = __ao2_link(c, user_data);
00575    
00576    if (p) {
00577       _ao2_ref(user_data, +1);
00578       ao2_unlock(c);
00579    }
00580    return p;
00581 }

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

Definition at line 561 of file astobj2.c.

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

00562 {
00563    struct bucket_list *p = __ao2_link(c, user_data);
00564    
00565    if (p) {
00566       _ao2_ref_debug(user_data, +1, tag, file, line, funcname);
00567       ao2_unlock(c);
00568    }
00569    return p;
00570 }

int _ao2_lock ( void *  user_data,
const char *  file,
const char *  func,
int  line,
const char *  var 
)

Definition at line 162 of file astobj2.c.

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

00163 {
00164    struct astobj2 *p = INTERNAL_OBJ(user_data);
00165 
00166    if (p == NULL)
00167       return -1;
00168 
00169 #ifdef AO2_DEBUG
00170    ast_atomic_fetchadd_int(&ao2.total_locked, 1);
00171 #endif
00172 
00173 #ifndef DEBUG_THREADS
00174    return ast_mutex_lock(&p->priv_data.lock);
00175 #else
00176    return __ast_pthread_mutex_lock(file, line, func, var, &p->priv_data.lock);
00177 #endif
00178 }

int _ao2_ref ( void *  user_data,
const int  delta 
)

Definition at line 283 of file astobj2.c.

References __ao2_ref(), and INTERNAL_OBJ().

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

00284 {
00285    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00286 
00287    if (obj == NULL)
00288       return -1;
00289 
00290    return __ao2_ref(user_data, delta);
00291 }

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

Definition at line 263 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().

00264 {
00265    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00266    
00267    if (obj == NULL)
00268       return -1;
00269 
00270    if (delta != 0) {
00271       FILE *refo = fopen(REF_FILE,"a");
00272       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);
00273       fclose(refo);
00274    }
00275    if (obj->priv_data.ref_counter + delta == 0 && obj->priv_data.destructor_fn != NULL) { /* this isn't protected with lock; just for o/p */
00276          FILE *refo = fopen(REF_FILE,"a");    
00277          fprintf(refo, "%p **call destructor** %s:%d:%s (%s)\n", user_data, file, line, funcname, tag);   
00278          fclose(refo);
00279    }
00280    return __ao2_ref(user_data, delta);
00281 }

int _ao2_trylock ( void *  user_data,
const char *  file,
const char *  func,
int  line,
const char *  var 
)

Definition at line 228 of file astobj2.c.

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

00229 {
00230    struct astobj2 *p = INTERNAL_OBJ(user_data);
00231    int ret;
00232    
00233    if (p == NULL)
00234       return -1;
00235 #ifndef DEBUG_THREADS
00236    ret = ast_mutex_trylock(&p->priv_data.lock);
00237 #else
00238    ret = __ast_pthread_mutex_trylock(file, line, func, var, &p->priv_data.lock);
00239 #endif
00240 
00241 #ifdef AO2_DEBUG
00242    if (!ret)
00243       ast_atomic_fetchadd_int(&ao2.total_locked, 1);
00244 #endif
00245    return ret;
00246 }

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

Definition at line 606 of file astobj2.c.

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

00607 {
00608    if (INTERNAL_OBJ(user_data) == NULL)   /* safety check on the argument */
00609       return NULL;
00610 
00611    _ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data);
00612 
00613    return NULL;
00614 }

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

Definition at line 595 of file astobj2.c.

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

00597 {
00598    if (INTERNAL_OBJ(user_data) == NULL)   /* safety check on the argument */
00599       return NULL;
00600 
00601    _ao2_callback_debug(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data, tag, file, line, funcname);
00602 
00603    return NULL;
00604 }

int _ao2_unlock ( void *  user_data,
const char *  file,
const char *  func,
int  line,
const char *  var 
)

Definition at line 194 of file astobj2.c.

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

00195 {
00196    struct astobj2 *p = INTERNAL_OBJ(user_data);
00197 
00198    if (p == NULL)
00199       return -1;
00200 
00201 #ifdef AO2_DEBUG
00202    ast_atomic_fetchadd_int(&ao2.total_locked, -1);
00203 #endif
00204 
00205 #ifndef DEBUG_THREADS
00206    return ast_mutex_unlock(&p->priv_data.lock);
00207 #else
00208    return __ast_pthread_mutex_unlock(file, line, func, var, &p->priv_data.lock);
00209 #endif
00210 }

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 511 of file astobj2.c.

References ao2_container::elements.

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

00512 {
00513    return c->elements;
00514 }

void ao2_iterator_destroy ( struct ao2_iterator i  ) 

Destroy a container iterator.

destroy an iterator

Definition at line 788 of file astobj2.c.

References ao2_ref, and ao2_iterator::c.

Referenced by __iax2_show_peers(), __queues_show(), _sip_show_peers(), authenticate_reply(), check_access(), cli_console_active(), cli_list_devices(), 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(), dump_queue_members(), free_members(), get_member_status(), handle_cli_iax2_show_callno_limits(), handle_cli_iax2_show_users(), handle_cli_moh_show_classes(), handle_cli_moh_show_files(), handle_cli_odbc_show(), handle_request_subscribe(), handle_show_routes(), iax2_getpeername(), iax2_getpeertrunk(), interface_exists(), interface_exists_global(), manager_iax2_show_peer_list(), 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(), 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_tcp(), sip_show_users(), stop_streams(), try_calling(), unload_module(), update_queue(), and update_realtime_members().

00789 {
00790    ao2_ref(i->c, -1);
00791    i->c = NULL;
00792 }

struct ao2_iterator ao2_iterator_init ( struct ao2_container c,
int  flags 
)

Create an iterator for a container.

initialize an iterator so we start from the first object

Definition at line 773 of file astobj2.c.

References ao2_ref, 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_callno_limits(), 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_tcp(), sip_show_users(), stop_streams(), tps_taskprocessor_tab_complete(), try_calling(), unload_module(), update_queue(), update_realtime_members(), and update_status().

00774 {
00775    struct ao2_iterator a = {
00776       .c = c,
00777       .flags = flags
00778    };
00779 
00780    ao2_ref(c, +1);
00781    
00782    return a;
00783 }

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 148 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(), _sip_tcp_helper_thread(), add_calltoken_ignore(), add_to_queue(), ast_taskprocessor_get(), ast_taskprocessor_unreference(), build_callno_limits(), 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(), get_unused_callno(), handle_request_subscribe(), inprocess_count(), 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(), peercnt_add(), peercnt_remove(), pthread_timer_ack(), pthread_timer_disable_continuous(), pthread_timer_enable_continuous(), pthread_timer_get_event(), 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(), replace_callno(), 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(), sip_tcptls_write(), try_calling(), update_call_counter(), update_queue(), update_realtime_members(), and update_status().

00149 {
00150    struct astobj2 *p = INTERNAL_OBJ(user_data);
00151 
00152    if (p == NULL)
00153       return -1;
00154 
00155 #ifdef AO2_DEBUG
00156    ast_atomic_fetchadd_int(&ao2.total_locked, 1);
00157 #endif
00158 
00159    return ast_mutex_lock(&p->priv_data.lock);
00160 }

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 586 of file astobj2.c.

References CMP_MATCH, and CMP_STOP.

00587 {
00588    return (user_data == arg) ? (CMP_MATCH | CMP_STOP) : 0;
00589 }

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 248 of file astobj2.c.

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

00249 {
00250    struct astobj2 *p = INTERNAL_OBJ(obj);
00251    
00252    if (p == NULL)
00253       return NULL;
00254 
00255    return &p->priv_data.lock;
00256 }

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 212 of file astobj2.c.

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

00213 {
00214    struct astobj2 *p = INTERNAL_OBJ(user_data);
00215    int ret;
00216    
00217    if (p == NULL)
00218       return -1;
00219    ret = ast_mutex_trylock(&p->priv_data.lock);
00220 
00221 #ifdef AO2_DEBUG
00222    if (!ret)
00223       ast_atomic_fetchadd_int(&ao2.total_locked, 1);
00224 #endif
00225    return ret;
00226 }

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 180 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(), _sip_tcp_helper_thread(), add_calltoken_ignore(), add_to_queue(), ast_taskprocessor_get(), ast_taskprocessor_unreference(), build_callno_limits(), 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(), get_unused_callno(), handle_request_subscribe(), inprocess_count(), 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(), peercnt_add(), peercnt_remove(), pthread_timer_ack(), pthread_timer_disable_continuous(), pthread_timer_enable_continuous(), pthread_timer_get_event(), 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(), replace_callno(), 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(), sip_tcptls_write(), try_calling(), update_call_counter(), update_queue(), update_realtime_members(), and update_status().

00181 {
00182    struct astobj2 *p = INTERNAL_OBJ(user_data);
00183 
00184    if (p == NULL)
00185       return -1;
00186 
00187 #ifdef AO2_DEBUG
00188    ast_atomic_fetchadd_int(&ao2.total_locked, -1);
00189 #endif
00190 
00191    return ast_mutex_unlock(&p->priv_data.lock);
00192 }

int astobj2_init ( void   ) 

Provided by astobj2.c

Definition at line 1074 of file astobj2.c.

References ARRAY_LEN, and ast_cli_register_multiple().

Referenced by main().

01075 {
01076 #ifdef AO2_DEBUG
01077    ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
01078 #endif
01079 
01080    return 0;
01081 }

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

special callback that matches all

Definition at line 619 of file astobj2.c.

References CMP_MATCH.

Referenced by __ao2_callback().

00620 {
00621    return CMP_MATCH;
00622 }

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

Definition at line 891 of file astobj2.c.

References _ao2_ref().

Referenced by container_destruct().

00892 {
00893    _ao2_ref(obj, -1);
00894    return 0;
00895 }

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

Definition at line 897 of file astobj2.c.

References _ao2_ref_debug().

Referenced by container_destruct_debug().

00898 {
00899    _ao2_ref_debug(obj, -1, "deref object via container destroy",  __FILE__, __LINE__, __PRETTY_FUNCTION__);
00900    return 0;
00901 }

static void container_destruct ( void *  c  )  [static]

Definition at line 903 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().

00904 {
00905    struct ao2_container *c = _c;
00906    int i;
00907 
00908    _ao2_callback(c, OBJ_UNLINK, cd_cb, NULL);
00909 
00910    for (i = 0; i < c->n_buckets; i++) {
00911       struct bucket_list *current;
00912 
00913       while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) {
00914          ast_free(current);
00915       }
00916    }
00917 
00918 #ifdef AO2_DEBUG
00919    ast_atomic_fetchadd_int(&ao2.total_containers, -1);
00920 #endif
00921 }

static void container_destruct_debug ( void *  c  )  [static]

Definition at line 923 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().

00924 {
00925    struct ao2_container *c = _c;
00926    int i;
00927 
00928    _ao2_callback_debug(c, OBJ_UNLINK, cd_cb_debug, NULL, "container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__);
00929 
00930    for (i = 0; i < c->n_buckets; i++) {
00931       struct bucket_list *current;
00932 
00933       while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) {
00934          ast_free(current);
00935       }
00936    }
00937 
00938 #ifdef AO2_DEBUG
00939    ast_atomic_fetchadd_int(&ao2.total_containers, -1);
00940 #endif
00941 }

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 454 of file astobj2.c.

Referenced by __ao2_container_alloc().

00455 {
00456    return 0;
00457 }

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_lock(), _ao2_ref(), _ao2_ref_debug(), _ao2_trylock(), _ao2_unlink(), _ao2_unlink_debug(), _ao2_unlock(), 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 Wed Aug 18 22:34:04 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7