Fri Nov 12 11:53:25 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>
Include dependency graph for astobj2.c:

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"

Enumerations

enum  ao2_callback_type { DEFAULT, WITH_DATA }

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, void *cb_fn, void *arg, void *data, enum ao2_callback_type type, 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, const char *file, int line, const char *func)
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_data (struct ao2_container *c, const enum search_flags flags, ao2_callback_data_fn *cb_fn, void *arg, void *data)
void * _ao2_callback_data_debug (struct ao2_container *c, const enum search_flags flags, ao2_callback_data_fn *cb_fn, void *arg, void *data, char *tag, char *file, int line, const char *funcname)
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)
struct ao2_container_ao2_container_alloc (const unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn)
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)
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.
void ao2_iterator_destroy (struct ao2_iterator *i)
 Destroy a container iterator.
struct 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 cb_true_data (void *user_data, void *arg, void *data, int flags)
 similar to cb_true, but is an ao2_callback_data_fn instead
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 133 of file astobj2.c.

Referenced by __ao2_alloc(), __ao2_callback(), and __ao2_iterator_next().

#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().


Enumeration Type Documentation

Enumerator:
DEFAULT 
WITH_DATA 

Definition at line 123 of file astobj2.c.

00123                        {
00124    DEFAULT,
00125    WITH_DATA,
00126 };


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

References __ast_calloc(), AO2_MAGIC, ast_atomic_fetchadd_int(), ast_calloc, ast_mutex_init(), __priv_data::data_size, __priv_data::destructor_fn, EXTERNAL_OBJ, __priv_data::lock, __priv_data::magic, astobj2::priv_data, and __priv_data::ref_counter.

Referenced by _ao2_alloc(), and _ao2_alloc_debug().

00306 {
00307    /* allocation */
00308    struct astobj2 *obj;
00309 
00310    if (data_size < sizeof(void *))
00311       data_size = sizeof(void *);
00312 
00313 #if defined(__AST_DEBUG_MALLOC)
00314    obj = __ast_calloc(1, sizeof(*obj) + data_size, file, line, funcname);
00315 #else
00316    obj = ast_calloc(1, sizeof(*obj) + data_size);
00317 #endif
00318 
00319    if (obj == NULL)
00320       return NULL;
00321 
00322    ast_mutex_init(&obj->priv_data.lock);
00323    obj->priv_data.magic = AO2_MAGIC;
00324    obj->priv_data.data_size = data_size;
00325    obj->priv_data.ref_counter = 1;
00326    obj->priv_data.destructor_fn = destructor_fn;   /* can be NULL */
00327 
00328 #ifdef AO2_DEBUG
00329    ast_atomic_fetchadd_int(&ao2.total_objects, 1);
00330    ast_atomic_fetchadd_int(&ao2.total_mem, data_size);
00331    ast_atomic_fetchadd_int(&ao2.total_refs, 1);
00332 #endif
00333 
00334    /* return a pointer to the user data */
00335    return EXTERNAL_OBJ(obj);
00336 }

static void * __ao2_callback ( struct ao2_container c,
const enum search_flags  flags,
void *  cb_fn,
void *  arg,
void *  data,
enum ao2_callback_type  type,
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 603 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(), cb_true_data(), 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, ao2_container::version, and WITH_DATA.

Referenced by _ao2_callback(), _ao2_callback_data(), _ao2_callback_data_debug(), and _ao2_callback_debug().

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

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, read]

Definition at line 425 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.

00427 {
00428    /* XXX maybe consistency check on arguments ? */
00429    /* compute the container size */
00430 
00431    if (!c)
00432       return NULL;
00433    
00434    c->version = 1;   /* 0 is a reserved value here */
00435    c->n_buckets = n_buckets;
00436    c->hash_fn = hash_fn ? hash_fn : hash_zero;
00437    c->cmp_fn = cmp_fn;
00438 
00439 #ifdef AO2_DEBUG
00440    ast_atomic_fetchadd_int(&ao2.total_containers, 1);
00441 #endif
00442 
00443    return c;
00444 }

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, read]
static void * __ao2_iterator_next ( struct ao2_iterator a,
struct bucket_list **  q 
) [static]

Definition at line 804 of file astobj2.c.

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

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

static struct bucket_list * __ao2_link ( struct ao2_container c,
void *  user_data,
const char *  file,
int  line,
const char *  func 
) [static, read]

Definition at line 494 of file astobj2.c.

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

Referenced by _ao2_link(), and _ao2_link_debug().

00495 {
00496    int i;
00497    /* create a new list entry */
00498    struct bucket_list *p;
00499    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00500 
00501    if (!obj)
00502       return NULL;
00503 
00504    if (INTERNAL_OBJ(c) == NULL)
00505       return NULL;
00506 
00507    p = ast_calloc(1, sizeof(*p));
00508    if (!p)
00509       return NULL;
00510 
00511    i = abs(c->hash_fn(user_data, OBJ_POINTER));
00512 
00513    ao2_lock(c);
00514    i %= c->n_buckets;
00515    p->astobj = obj;
00516    p->version = ast_atomic_fetchadd_int(&c->version, 1);
00517    AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
00518    ast_atomic_fetchadd_int(&c->elements, 1);
00519 
00520    /* the last two operations (ao2_ref, ao2_unlock) must be done by the calling func */
00521    return p;
00522 }

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

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

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

void* _ao2_alloc ( size_t  data_size,
ao2_destructor_fn  destructor_fn 
)

Definition at line 359 of file astobj2.c.

References __ao2_alloc().

Referenced by _ao2_container_alloc().

00360 {
00361    return __ao2_alloc(data_size, destructor_fn, __FILE__, __LINE__, __FUNCTION__);
00362 }

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

References __ao2_alloc(), and REF_FILE.

Referenced by _ao2_container_alloc_debug(), and _moh_class_malloc().

00340 {
00341    /* allocation */
00342    void *obj;
00343    FILE *refo = ref_debug ? fopen(REF_FILE,"a") : NULL;
00344 
00345    obj = __ao2_alloc(data_size, destructor_fn, file, line, funcname);
00346 
00347    if (obj == NULL)
00348       return NULL;
00349    
00350    if (refo) {
00351       fprintf(refo, "%p =1   %s:%d:%s (%s)\n", obj, file, line, funcname, tag);
00352       fclose(refo);
00353    }
00354 
00355    /* return a pointer to the user data */
00356    return obj;
00357 }

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

Definition at line 744 of file astobj2.c.

References __ao2_callback(), and DEFAULT.

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

00746 {
00747    return __ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, NULL, NULL, 0, NULL);
00748 }

void* _ao2_callback_data ( struct ao2_container c,
const enum search_flags  flags,
ao2_callback_data_fn cb_fn,
void *  arg,
void *  data 
)

Definition at line 758 of file astobj2.c.

References __ao2_callback(), and WITH_DATA.

00760 {
00761    return __ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, NULL, NULL, 0, NULL);
00762 }

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

Definition at line 750 of file astobj2.c.

References __ao2_callback(), and WITH_DATA.

00754 {
00755    return __ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, tag, file, line, funcname);
00756 }

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

References __ao2_callback(), and DEFAULT.

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

00740 {
00741    return __ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, tag, file, line, funcname);
00742 }

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

Definition at line 459 of file astobj2.c.

References __ao2_container_alloc(), _ao2_alloc(), and container_destruct().

00461 {
00462    /* XXX maybe consistency check on arguments ? */
00463    /* compute the container size */
00464 
00465    size_t container_size = sizeof(struct ao2_container) + n_buckets * sizeof(struct bucket);
00466    struct ao2_container *c = _ao2_alloc(container_size, container_destruct);
00467 
00468    return __ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn);
00469 }

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 
) [read]

Definition at line 446 of file astobj2.c.

References __ao2_container_alloc(), _ao2_alloc_debug(), and container_destruct_debug().

00449 {
00450    /* XXX maybe consistency check on arguments ? */
00451    /* compute the container size */
00452    size_t container_size = sizeof(struct ao2_container) + n_buckets * sizeof(struct bucket);
00453    struct ao2_container *c = _ao2_alloc_debug(container_size, container_destruct_debug, tag, file, line, funcname, ref_debug);
00454 
00455    return __ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn);
00456 }

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

Definition at line 772 of file astobj2.c.

References _ao2_callback(), and ao2_container::cmp_fn.

Referenced by _get_mohbyname().

00773 {
00774    return _ao2_callback(c, flags, c->cmp_fn, arg);
00775 }

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

References _ao2_callback_debug(), and ao2_container::cmp_fn.

Referenced by _get_mohbyname().

00768 {
00769    return _ao2_callback_debug(c, flags, c->cmp_fn, arg, tag, file, line, funcname);
00770 }

void* _ao2_iterator_next ( struct ao2_iterator a  ) 

Definition at line 877 of file astobj2.c.

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

00878 {
00879    struct bucket_list *p = NULL;
00880    void *ret = NULL;
00881 
00882    ret = __ao2_iterator_next(a, &p);
00883    
00884    if (p) {
00885       /* inc refcount of returned object */
00886       _ao2_ref(ret, 1);
00887    }
00888 
00889    if (!(a->flags & AO2_ITERATOR_DONTLOCK))
00890       ao2_unlock(a->c);
00891 
00892    return ret;
00893 }

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

Definition at line 859 of file astobj2.c.

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

00860 {
00861    struct bucket_list *p;
00862    void *ret = NULL;
00863 
00864    ret = __ao2_iterator_next(a, &p);
00865    
00866    if (p) {
00867       /* inc refcount of returned object */
00868       _ao2_ref_debug(ret, 1, tag, file, line, funcname);
00869    }
00870 
00871    if (!(a->flags & AO2_ITERATOR_DONTLOCK))
00872       ao2_unlock(a->c);
00873 
00874    return ret;
00875 }

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

Definition at line 535 of file astobj2.c.

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

00536 {
00537    struct bucket_list *p = __ao2_link(c, user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__);
00538 
00539    if (p) {
00540       _ao2_ref(user_data, +1);
00541       ao2_unlock(c);
00542    }
00543    return p;
00544 }

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

Definition at line 524 of file astobj2.c.

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

00525 {
00526    struct bucket_list *p = __ao2_link(c, user_data, file, line, funcname);
00527 
00528    if (p) {
00529       _ao2_ref_debug(user_data, +1, tag, file, line, funcname);
00530       ao2_unlock(c);
00531    }
00532    return p;
00533 }

int _ao2_ref ( void *  user_data,
const int  delta 
)

Definition at line 249 of file astobj2.c.

References __ao2_ref(), and INTERNAL_OBJ().

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

00250 {
00251    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00252 
00253    if (obj == NULL)
00254       return -1;
00255 
00256    return __ao2_ref(user_data, delta);
00257 }

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

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

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

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

Definition at line 569 of file astobj2.c.

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

00570 {
00571    if (INTERNAL_OBJ(user_data) == NULL)   /* safety check on the argument */
00572       return NULL;
00573 
00574    _ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data);
00575 
00576    return NULL;
00577 }

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

Definition at line 558 of file astobj2.c.

References _ao2_callback_debug(), 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_debug(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data, tag, file, line, funcname);
00565 
00566    return NULL;
00567 }

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

References ao2_container::elements.

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

00475 {
00476    return c->elements;
00477 }

void ao2_iterator_destroy ( struct ao2_iterator i  ) 

Destroy a container iterator.

destroy an iterator

Definition at line 795 of file astobj2.c.

References ao2_ref, and ao2_iterator::c.

Referenced by __iax2_show_peers(), __queues_show(), _sip_show_peers(), alias_show(), authenticate_reply(), check_access(), clear_queue(), clear_stats(), 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(), find_queue_by_name_rt(), 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(), handle_statechange(), iax2_getpeername(), iax2_getpeertrunk(), interface_exists(), 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().

00796 {
00797    ao2_ref(i->c, -1);
00798    i->c = NULL;
00799 }

struct ao2_iterator ao2_iterator_init ( struct ao2_container c,
int  flags 
) [read]

Create an iterator for a container.

initialize an iterator so we start from the first object

Definition at line 780 of file astobj2.c.

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

Referenced by __iax2_show_peers(), __queues_show(), _sip_show_peers(), alias_show(), ast_tone_zone_iterator_init(), authenticate_reply(), check_access(), clear_queue(), clear_stats(), cli_console_active(), cli_list_devices(), cli_tps_report(), compare_weight(), complete_country(), 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(), find_queue_by_name_rt(), 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(), handle_statechange(), iax2_getpeername(), iax2_getpeertrunk(), interface_exists(), 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(), 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(), and update_realtime_members().

00781 {
00782    struct ao2_iterator a = {
00783       .c = c,
00784       .flags = flags
00785    };
00786 
00787    ao2_ref(c, +1);
00788    
00789    return a;
00790 }

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 147 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_bridge_depart(), ast_bridge_destroy(), ast_bridge_dtmf_stream(), ast_bridge_merge(), ast_bridge_remove(), ast_bridge_suspend(), ast_bridge_unsuspend(), ast_get_indication_tone(), ast_get_indication_zone(), ast_register_indication_country(), ast_set_indication_country(), ast_taskprocessor_get(), ast_taskprocessor_unreference(), ast_unregister_indication_country(), attended_abort_transfer(), bridge_channel_join(), bridge_channel_join_multithreaded(), bridge_channel_join_singlethreaded(), bridge_thread(), build_callno_limits(), build_parkinglot(), clear_stats(), compare_weight(), complete_queue_remove_member(), complete_sip_user(), end_bridge_callback(), find_call(), find_queue_by_name_rt(), generic_thread_loop(), get_member_penalty(), get_member_status(), get_unused_callno(), handle_request_subscribe(), handle_statechange(), inprocess_count(), is_our_turn(), join_conference_bridge(), join_queue(), leave_conference_bridge(), leave_queue(), load_config(), load_indications(), load_realtime_queue(), manager_queues_status(), manager_queues_summary(), menu_callback(), moh_release(), mohalloc(), monmp3thread(), multiplexed_add_or_remove(), multiplexed_bridge_create(), multiplexed_bridge_destroy(), multiplexed_thread_function(), mwi_event_cb(), peercnt_add(), peercnt_remove(), play_prompt_to_channel(), post_join_marked(), post_join_unmarked(), 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(), reload_single_queue(), 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(), softmix_bridge_thread(), try_calling(), update_call_counter(), update_queue(), and update_realtime_members().

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

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

References CMP_MATCH, and CMP_STOP.

00550 {
00551    return (user_data == arg) ? (CMP_MATCH | CMP_STOP) : 0;
00552 }

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

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

00215 {
00216    struct astobj2 *p = INTERNAL_OBJ(obj);
00217    
00218    if (p == NULL)
00219       return NULL;
00220 
00221    return &p->priv_data.lock;
00222 }

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

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

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

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 169 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_bridge_depart(), ast_bridge_destroy(), ast_bridge_dtmf_stream(), ast_bridge_merge(), ast_bridge_remove(), ast_bridge_suspend(), ast_bridge_unsuspend(), ast_get_indication_tone(), ast_get_indication_zone(), ast_register_indication_country(), ast_set_indication_country(), ast_taskprocessor_get(), ast_taskprocessor_unreference(), ast_unregister_indication_country(), attended_abort_transfer(), bridge_channel_join(), bridge_channel_join_multithreaded(), bridge_channel_join_singlethreaded(), bridge_thread(), build_callno_limits(), build_parkinglot(), clear_stats(), compare_weight(), complete_queue_remove_member(), complete_sip_user(), end_bridge_callback(), find_call(), find_queue_by_name_rt(), generic_thread_loop(), get_member_penalty(), get_member_status(), get_unused_callno(), handle_request_subscribe(), handle_statechange(), inprocess_count(), is_our_turn(), join_conference_bridge(), join_queue(), leave_conference_bridge(), leave_queue(), load_config(), load_indications(), load_realtime_queue(), manager_queues_status(), manager_queues_summary(), menu_callback(), moh_release(), mohalloc(), monmp3thread(), multiplexed_add_or_remove(), multiplexed_bridge_create(), multiplexed_bridge_destroy(), multiplexed_thread_function(), mwi_event_cb(), peercnt_add(), peercnt_remove(), play_prompt_to_channel(), post_join_marked(), post_join_unmarked(), 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(), reload_single_queue(), 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(), softmix_bridge_thread(), try_calling(), update_call_counter(), update_queue(), and update_realtime_members().

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

int astobj2_init ( void   ) 

Provided by astobj2.c

Definition at line 1081 of file astobj2.c.

References ARRAY_LEN, and ast_cli_register_multiple().

Referenced by main().

01082 {
01083 #ifdef AO2_DEBUG
01084    ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
01085 #endif
01086 
01087    return 0;
01088 }

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

special callback that matches all

Definition at line 582 of file astobj2.c.

References CMP_MATCH.

Referenced by __ao2_callback().

00583 {
00584    return CMP_MATCH;
00585 }

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

similar to cb_true, but is an ao2_callback_data_fn instead

Definition at line 590 of file astobj2.c.

References CMP_MATCH.

Referenced by __ao2_callback().

00591 {
00592    return CMP_MATCH;
00593 }

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

Definition at line 898 of file astobj2.c.

References _ao2_ref().

Referenced by container_destruct().

00899 {
00900    _ao2_ref(obj, -1);
00901    return 0;
00902 }

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

Definition at line 904 of file astobj2.c.

References _ao2_ref_debug().

Referenced by container_destruct_debug().

00905 {
00906    _ao2_ref_debug(obj, -1, "deref object via container destroy",  __FILE__, __LINE__, __PRETTY_FUNCTION__);
00907    return 0;
00908 }

static void container_destruct ( void *  c  )  [static]

Definition at line 910 of file astobj2.c.

References _ao2_callback(), ast_atomic_fetchadd_int(), 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().

00911 {
00912    struct ao2_container *c = _c;
00913    int i;
00914 
00915    _ao2_callback(c, OBJ_UNLINK, cd_cb, NULL);
00916 
00917    for (i = 0; i < c->n_buckets; i++) {
00918       struct bucket_list *current;
00919 
00920       while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) {
00921          ast_free(current);
00922       }
00923    }
00924 
00925 #ifdef AO2_DEBUG
00926    ast_atomic_fetchadd_int(&ao2.total_containers, -1);
00927 #endif
00928 }

static void container_destruct_debug ( void *  c  )  [static]

Definition at line 930 of file astobj2.c.

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

Referenced by _ao2_container_alloc_debug().

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

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

Referenced by __ao2_container_alloc().

00418 {
00419    return 0;
00420 }

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

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(), LOG_ERROR, __priv_data::magic, and astobj2::priv_data.

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 by  doxygen 1.6.2