Wed Mar 3 22:45:23 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 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_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.
struct ao2_iterator ao2_iterator_init (struct ao2_container *c, int flags)
int ao2_lock (void *user_data)
 Lock an object.
int ao2_match_by_addr (void *user_data, void *arg, int flags)
 another convenience function is a callback that matches on address
void * ao2_object_get_lockaddr (void *obj)
 Return the lock address of an object.
int ao2_trylock (void *user_data)
 Try locking-- (don't block if fail).
int ao2_unlock (void *user_data)
 Unlock an object.
 AST_LIST_HEAD_NOLOCK (bucket, bucket_list)
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(), ao2_container::buckets, cb_true(), CMP_MATCH, CMP_STOP, ao2_container::elements, 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       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 744 of file astobj2.c.

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

Referenced by _ao2_iterator_next(), and _ao2_iterator_next_debug().

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

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, ao2_container::buckets, ao2_container::elements, ao2_container::hash_fn, INTERNAL_OBJ(), ao2_container::n_buckets, OBJ_POINTER, and ao2_container::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 = 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 817 of file astobj2.c.

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

00818 {
00819    struct bucket_list *p = NULL;
00820    void *ret = NULL;
00821 
00822    ret = __ao2_iterator_next(a, &p);
00823    
00824    if (p) {
00825       /* inc refcount of returned object */
00826       _ao2_ref(ret, 1);
00827    }
00828 
00829    if (!(a->flags & F_AO2I_DONTLOCK))
00830       ao2_unlock(a->c);
00831 
00832    return ret;
00833 }

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

Definition at line 799 of file astobj2.c.

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

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

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

00470 {
00471    return c->elements;
00472 }

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

initialize an iterator so we start from the first object

Definition at line 731 of file astobj2.c.

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

Referenced by __iax2_show_peers(), __queues_show(), _sip_show_peers(), ast_odbc_request_obj(), authenticate_reply(), check_access(), cli_console_active(), cli_list_devices(), cli_tps_report(), compare_weight(), complete_iax2_peers(), complete_iax2_unregister(), complete_queue(), complete_queue_remove_member(), complete_sip_peer(), complete_sip_registered_peer(), complete_sip_user(), complete_sipch(), delete_profiles(), delete_routes(), delete_users(), destroy_pvts(), dialgroup_read(), do_parking_thread(), dump_queue_members(), 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_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    return a;
00739 }

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(), 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(), 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(), 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(), 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 }

AST_LIST_HEAD_NOLOCK ( bucket  ,
bucket_list   
)
int astobj2_init ( void   ) 

Provided by astobj2.c

Definition at line 1021 of file astobj2.c.

References ARRAY_LEN, and ast_cli_register_multiple().

Referenced by main().

01022 {
01023 #ifdef AO2_DEBUG
01024    ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
01025 #endif
01026 
01027    return 0;
01028 }

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

References _ao2_ref().

Referenced by container_destruct().

00839 {
00840    _ao2_ref(obj, -1);
00841    return 0;
00842 }

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

Definition at line 844 of file astobj2.c.

References _ao2_ref_debug().

Referenced by container_destruct_debug().

00845 {
00846    _ao2_ref_debug(obj, -1, "deref object via container destroy",  __FILE__, __LINE__, __PRETTY_FUNCTION__);
00847    return 0;
00848 }

static void container_destruct ( void *  c  )  [static]

Definition at line 850 of file astobj2.c.

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

Referenced by _ao2_container_alloc().

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

static void container_destruct_debug ( void *  c  )  [static]

Definition at line 870 of file astobj2.c.

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

00871 {
00872    struct ao2_container *c = _c;
00873    int i;
00874 
00875    _ao2_callback_debug(c, OBJ_UNLINK, cd_cb_debug, NULL, "container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__);
00876 
00877    for (i = 0; i < c->n_buckets; i++) {
00878       struct bucket_list *current;
00879 
00880       while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) {
00881          ast_free(current);
00882       }
00883    }
00884 
00885 #ifdef AO2_DEBUG
00886    ast_atomic_fetchadd_int(&ao2.total_containers, -1);
00887 #endif
00888 }

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 3 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1