Wed Oct 28 11:51:42 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 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 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)
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 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(), __ao2_callback(), and __ao2_iterator_next().

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

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

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

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

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

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

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

00756 {
00757    int lim;
00758    struct bucket_list *p = NULL;
00759    void *ret = NULL;
00760 
00761    *q = NULL;
00762    
00763    if (INTERNAL_OBJ(a->c) == NULL)
00764       return NULL;
00765 
00766    if (!(a->flags & AO2_ITERATOR_DONTLOCK))
00767       ao2_lock(a->c);
00768 
00769    /* optimization. If the container is unchanged and
00770     * we have a pointer, try follow it
00771     */
00772    if (a->c->version == a->c_version && (p = a->obj) ) {
00773       if ( (p = AST_LIST_NEXT(p, entry)) )
00774          goto found;
00775       /* nope, start from the next bucket */
00776       a->bucket++;
00777       a->version = 0;
00778       a->obj = NULL;
00779    }
00780 
00781    lim = a->c->n_buckets;
00782 
00783    /* Browse the buckets array, moving to the next
00784     * buckets if we don't find the entry in the current one.
00785     * Stop when we find an element with version number greater
00786     * than the current one (we reset the version to 0 when we
00787     * switch buckets).
00788     */
00789    for (; a->bucket < lim; a->bucket++, a->version = 0) {
00790       /* scan the current bucket */
00791       AST_LIST_TRAVERSE(&a->c->buckets[a->bucket], p, entry) {
00792          if (p->version > a->version)
00793             goto found;
00794       }
00795    }
00796 
00797 found:
00798    if (p) {
00799       a->version = p->version;
00800       a->obj = p;
00801       a->c_version = a->c->version;
00802       ret = EXTERNAL_OBJ(p->astobj);
00803       /* inc refcount of returned object */
00804       *q = p;
00805    }
00806 
00807    return ret;
00808 }

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

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

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

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

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

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

void* _ao2_alloc ( size_t  data_size,
ao2_destructor_fn  destructor_fn 
)

Definition at line 354 of file astobj2.c.

References __ao2_alloc().

Referenced by _ao2_container_alloc().

00355 {
00356    return __ao2_alloc(data_size, destructor_fn, __FILE__, __LINE__, __FUNCTION__);
00357 }

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

References __ao2_alloc(), and REF_FILE.

Referenced by _ao2_container_alloc_debug().

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

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

Definition at line 709 of file astobj2.c.

References __ao2_callback().

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

00711 {
00712    return __ao2_callback(c,flags, cb_fn, arg, NULL, NULL, 0, NULL);
00713 }

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

References __ao2_callback().

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

00705 {
00706    return __ao2_callback(c,flags, cb_fn, arg, tag, file, line, funcname);
00707 }

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

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

00456 {
00457    /* XXX maybe consistency check on arguments ? */
00458    /* compute the container size */
00459 
00460    size_t container_size = sizeof(struct ao2_container) + n_buckets * sizeof(struct bucket);
00461    struct ao2_container *c = _ao2_alloc(container_size, container_destruct);
00462 
00463    return __ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn);
00464 }

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

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

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

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

Definition at line 723 of file astobj2.c.

References _ao2_callback(), and ao2_container::cmp_fn.

00724 {
00725    return _ao2_callback(c, flags, c->cmp_fn, arg);
00726 }

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

References _ao2_callback_debug(), and ao2_container::cmp_fn.

00719 {
00720    return _ao2_callback_debug(c, flags, c->cmp_fn, arg, tag, file, line, funcname);
00721 }

void* _ao2_iterator_next ( struct ao2_iterator a  ) 

Definition at line 828 of file astobj2.c.

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

00829 {
00830    struct bucket_list *p = NULL;
00831    void *ret = NULL;
00832 
00833    ret = __ao2_iterator_next(a, &p);
00834    
00835    if (p) {
00836       /* inc refcount of returned object */
00837       _ao2_ref(ret, 1);
00838    }
00839 
00840    if (!(a->flags & AO2_ITERATOR_DONTLOCK))
00841       ao2_unlock(a->c);
00842 
00843    return ret;
00844 }

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

Definition at line 810 of file astobj2.c.

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

00811 {
00812    struct bucket_list *p;
00813    void *ret = NULL;
00814 
00815    ret = __ao2_iterator_next(a, &p);
00816    
00817    if (p) {
00818       /* inc refcount of returned object */
00819       _ao2_ref_debug(ret, 1, tag, file, line, funcname);
00820    }
00821 
00822    if (!(a->flags & AO2_ITERATOR_DONTLOCK))
00823       ao2_unlock(a->c);
00824 
00825    return ret;
00826 }

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

Definition at line 530 of file astobj2.c.

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

00531 {
00532    struct bucket_list *p = __ao2_link(c, user_data);
00533    
00534    if (p) {
00535       _ao2_ref(user_data, +1);
00536       ao2_unlock(c);
00537    }
00538    return p;
00539 }

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

Definition at line 519 of file astobj2.c.

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

00520 {
00521    struct bucket_list *p = __ao2_link(c, user_data);
00522    
00523    if (p) {
00524       _ao2_ref_debug(user_data, +1, tag, file, line, funcname);
00525       ao2_unlock(c);
00526    }
00527    return p;
00528 }

int _ao2_ref ( void *  user_data,
const int  delta 
)

Definition at line 244 of file astobj2.c.

References __ao2_ref(), and INTERNAL_OBJ().

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

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

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

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

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

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

Definition at line 564 of file astobj2.c.

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

00565 {
00566    if (INTERNAL_OBJ(user_data) == NULL)   /* safety check on the argument */
00567       return NULL;
00568 
00569    _ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data);
00570 
00571    return NULL;
00572 }

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

Definition at line 553 of file astobj2.c.

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

00555 {
00556    if (INTERNAL_OBJ(user_data) == NULL)   /* safety check on the argument */
00557       return NULL;
00558 
00559    _ao2_callback_debug(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data, tag, file, line, funcname);
00560 
00561    return NULL;
00562 }

void ao2_bt ( void   ) 

Definition at line 79 of file astobj2.c.

00079 {}

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

00470 {
00471    return c->elements;
00472 }

void ao2_iterator_destroy ( struct ao2_iterator i  ) 

Destroy a container iterator.

destroy an iterator

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

00747 {
00748    ao2_ref(i->c, -1);
00749    i->c = NULL;
00750 }

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 731 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(), 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(), 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().

00732 {
00733    struct ao2_iterator a = {
00734       .c = c,
00735       .flags = flags
00736    };
00737 
00738    ao2_ref(c, +1);
00739    
00740    return a;
00741 }

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 142 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(), 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().

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

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

References CMP_MATCH, and CMP_STOP.

00545 {
00546    return (user_data == arg) ? (CMP_MATCH | CMP_STOP) : 0;
00547 }

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

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

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

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

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

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

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 164 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(), 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().

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

int astobj2_init ( void   ) 

Provided by astobj2.c

Definition at line 1032 of file astobj2.c.

References ARRAY_LEN, and ast_cli_register_multiple().

Referenced by main().

01033 {
01034 #ifdef AO2_DEBUG
01035    ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
01036 #endif
01037 
01038    return 0;
01039 }

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

special callback that matches all

Definition at line 577 of file astobj2.c.

References CMP_MATCH.

Referenced by __ao2_callback().

00578 {
00579    return CMP_MATCH;
00580 }

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

Definition at line 849 of file astobj2.c.

References _ao2_ref().

Referenced by container_destruct().

00850 {
00851    _ao2_ref(obj, -1);
00852    return 0;
00853 }

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

Definition at line 855 of file astobj2.c.

References _ao2_ref_debug().

Referenced by container_destruct_debug().

00856 {
00857    _ao2_ref_debug(obj, -1, "deref object via container destroy",  __FILE__, __LINE__, __PRETTY_FUNCTION__);
00858    return 0;
00859 }

static void container_destruct ( void *  c  )  [static]

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

00862 {
00863    struct ao2_container *c = _c;
00864    int i;
00865 
00866    _ao2_callback(c, OBJ_UNLINK, cd_cb, NULL);
00867 
00868    for (i = 0; i < c->n_buckets; i++) {
00869       struct bucket_list *current;
00870 
00871       while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) {
00872          ast_free(current);
00873       }
00874    }
00875 
00876 #ifdef AO2_DEBUG
00877    ast_atomic_fetchadd_int(&ao2.total_containers, -1);
00878 #endif
00879 }

static void container_destruct_debug ( void *  c  )  [static]

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

00882 {
00883    struct ao2_container *c = _c;
00884    int i;
00885 
00886    _ao2_callback_debug(c, OBJ_UNLINK, cd_cb_debug, NULL, "container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__);
00887 
00888    for (i = 0; i < c->n_buckets; i++) {
00889       struct bucket_list *current;
00890 
00891       while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) {
00892          ast_free(current);
00893       }
00894    }
00895 
00896 #ifdef AO2_DEBUG
00897    ast_atomic_fetchadd_int(&ao2.total_containers, -1);
00898 #endif
00899 }

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

Referenced by __ao2_container_alloc().

00413 {
00414    return 0;
00415 }

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 on Wed Oct 28 11:51:42 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6