#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/astobj2.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include <execinfo.h>
Go to the source code of this file.
Data Structures | |
struct | __priv_data |
struct | ao2_container |
struct | astobj2 |
struct | bucket |
struct | bucket_list |
Defines | |
#define | AO2_MAGIC 0xa570b123 |
#define | EXTERNAL_OBJ(_p) ((_p) == NULL ? NULL : (_p)->user_data) |
convert from a pointer _p to an astobj2 object | |
#define | N1 20 |
#define | REF_FILE "/tmp/refs" |
Functions | |
static void * | __ao2_alloc (size_t data_size, ao2_destructor_fn destructor_fn) |
static void * | __ao2_callback (struct ao2_container *c, const enum search_flags flags, ao2_callback_fn *cb_fn, void *arg, char *tag, char *file, int line, const char *funcname) |
static struct ao2_container * | __ao2_container_alloc (struct ao2_container *c, const unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn) |
static struct ao2_container * | __ao2_container_alloc (struct ao2_container *c, const uint n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn) |
static void * | __ao2_iterator_next (struct ao2_iterator *a, struct bucket_list **q) |
static struct bucket_list * | __ao2_link (struct ao2_container *c, void *user_data) |
static int | __ao2_ref (void *user_data, const int delta) |
void * | _ao2_alloc (size_t data_size, ao2_destructor_fn destructor_fn) |
void * | _ao2_alloc_debug (size_t data_size, ao2_destructor_fn destructor_fn, char *tag, char *file, int line, const char *funcname) |
void * | _ao2_callback (struct ao2_container *c, const enum search_flags flags, ao2_callback_fn *cb_fn, void *arg) |
void * | _ao2_callback_debug (struct ao2_container *c, const enum search_flags flags, ao2_callback_fn *cb_fn, void *arg, char *tag, char *file, int line, const char *funcname) |
ao2_container * | _ao2_container_alloc (const unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn) |
ao2_container * | _ao2_container_alloc_debug (const unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn, char *tag, char *file, int line, const char *funcname) |
void * | _ao2_find (struct ao2_container *c, void *arg, enum search_flags flags) |
void * | _ao2_find_debug (struct ao2_container *c, void *arg, enum search_flags flags, char *tag, char *file, int line, const char *funcname) |
void * | _ao2_iterator_next (struct ao2_iterator *a) |
void * | _ao2_iterator_next_debug (struct ao2_iterator *a, char *tag, char *file, int line, const char *funcname) |
void * | _ao2_link (struct ao2_container *c, void *user_data) |
void * | _ao2_link_debug (struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname) |
int | _ao2_ref (void *user_data, const int delta) |
int | _ao2_ref_debug (void *user_data, const int delta, char *tag, char *file, int line, const char *funcname) |
void * | _ao2_unlink (struct ao2_container *c, void *user_data) |
void * | _ao2_unlink_debug (struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname) |
void | ao2_bt (void) |
int | ao2_container_count (struct ao2_container *c) |
Returns the number of elements in a container. | |
ao2_iterator | ao2_iterator_init (struct ao2_container *c, int flags) |
int | ao2_lock (void *user_data) |
Lock an object. | |
int | ao2_match_by_addr (void *user_data, void *arg, int flags) |
another convenience function is a callback that matches on address | |
void * | ao2_object_get_lockaddr (void *obj) |
Return the lock address of an object. | |
int | ao2_trylock (void *user_data) |
Try locking-- (don't block if fail). | |
int | ao2_unlock (void *user_data) |
Unlock an object. | |
int | astobj2_init (void) |
static int | cb_true (void *user_data, void *arg, int flags) |
special callback that matches all | |
static int | cd_cb (void *obj, void *arg, int flag) |
static int | cd_cb_debug (void *obj, void *arg, int flag) |
static void | container_destruct (void *c) |
static void | container_destruct_debug (void *c) |
static int | hash_zero (const void *user_obj, const int flags) |
always zero hash function | |
static struct astobj2 * | INTERNAL_OBJ (void *user_data) |
convert from a pointer _p to a user-defined object |
#define AO2_MAGIC 0xa570b123 |
#define EXTERNAL_OBJ | ( | _p | ) | ((_p) == NULL ? NULL : (_p)->user_data) |
convert from a pointer _p to an astobj2 object
Definition at line 128 of file astobj2.c.
Referenced by __ao2_alloc(), and __ao2_callback().
#define N1 20 |
Referenced by ao2_bt().
#define REF_FILE "/tmp/refs" |
static void * __ao2_alloc | ( | size_t | data_size, | |
ao2_destructor_fn | destructor_fn | |||
) | [static] |
Definition at line 301 of file astobj2.c.
References AO2_MAGIC, ast_atomic_fetchadd_int(), ast_calloc, ast_mutex_init(), and EXTERNAL_OBJ.
Referenced by _ao2_alloc(), and _ao2_alloc_debug().
00302 { 00303 /* allocation */ 00304 struct astobj2 *obj; 00305 00306 if (data_size < sizeof(void *)) 00307 data_size = sizeof(void *); 00308 00309 obj = ast_calloc(1, sizeof(*obj) + data_size); 00310 00311 if (obj == NULL) 00312 return NULL; 00313 00314 ast_mutex_init(&obj->priv_data.lock); 00315 obj->priv_data.magic = AO2_MAGIC; 00316 obj->priv_data.data_size = data_size; 00317 obj->priv_data.ref_counter = 1; 00318 obj->priv_data.destructor_fn = destructor_fn; /* can be NULL */ 00319 00320 #ifdef AO2_DEBUG 00321 ast_atomic_fetchadd_int(&ao2.total_objects, 1); 00322 ast_atomic_fetchadd_int(&ao2.total_mem, data_size); 00323 ast_atomic_fetchadd_int(&ao2.total_refs, 1); 00324 #endif 00325 00326 /* return a pointer to the user data */ 00327 return EXTERNAL_OBJ(obj); 00328 }
static void * __ao2_callback | ( | struct ao2_container * | c, | |
const enum search_flags | flags, | |||
ao2_callback_fn * | cb_fn, | |||
void * | arg, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) | [static] |
Browse the container using different stategies accoding the flags.
Definition at line 585 of file astobj2.c.
References _ao2_ref(), _ao2_ref_debug(), ao2_lock(), ao2_unlock(), ast_atomic_fetchadd_int(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), bucket_list::astobj, ao2_container::buckets, cb_true(), CMP_MATCH, CMP_STOP, ao2_container::elements, bucket_list::entry, EXTERNAL_OBJ, free, ao2_container::hash_fn, INTERNAL_OBJ(), last, LOG_WARNING, match(), ao2_container::n_buckets, OBJ_MULTIPLE, OBJ_NODATA, OBJ_POINTER, OBJ_UNLINK, and ao2_container::version.
Referenced by _ao2_callback(), and _ao2_callback_debug().
00588 { 00589 int i, last; /* search boundaries */ 00590 void *ret = NULL; 00591 00592 if (INTERNAL_OBJ(c) == NULL) /* safety check on the argument */ 00593 return NULL; 00594 00595 if ((flags & (OBJ_MULTIPLE | OBJ_NODATA)) == OBJ_MULTIPLE) { 00596 ast_log(LOG_WARNING, "multiple data return not implemented yet (flags %x)\n", flags); 00597 return NULL; 00598 } 00599 00600 /* override the match function if necessary */ 00601 if (cb_fn == NULL) /* if NULL, match everything */ 00602 cb_fn = cb_true; 00603 /* 00604 * XXX this can be optimized. 00605 * If we have a hash function and lookup by pointer, 00606 * run the hash function. Otherwise, scan the whole container 00607 * (this only for the time being. We need to optimize this.) 00608 */ 00609 if ((flags & OBJ_POINTER)) /* we know hash can handle this case */ 00610 i = c->hash_fn(arg, flags & OBJ_POINTER) % c->n_buckets; 00611 else /* don't know, let's scan all buckets */ 00612 i = -1; /* XXX this must be fixed later. */ 00613 00614 /* determine the search boundaries: i..last-1 */ 00615 if (i < 0) { 00616 i = 0; 00617 last = c->n_buckets; 00618 } else { 00619 last = i + 1; 00620 } 00621 00622 ao2_lock(c); /* avoid modifications to the content */ 00623 00624 for (; i < last ; i++) { 00625 /* scan the list with prev-cur pointers */ 00626 struct bucket_list *cur; 00627 00628 AST_LIST_TRAVERSE_SAFE_BEGIN(&c->buckets[i], cur, entry) { 00629 int match = cb_fn(EXTERNAL_OBJ(cur->astobj), arg, flags) & (CMP_MATCH | CMP_STOP); 00630 00631 /* we found the object, performing operations according flags */ 00632 if (match == 0) { /* no match, no stop, continue */ 00633 continue; 00634 } else if (match == CMP_STOP) { /* no match but stop, we are done */ 00635 i = last; 00636 break; 00637 } 00638 /* we have a match (CMP_MATCH) here */ 00639 if (!(flags & OBJ_NODATA)) { /* if must return the object, record the value */ 00640 /* it is important to handle this case before the unlink */ 00641 ret = EXTERNAL_OBJ(cur->astobj); 00642 if (tag) 00643 _ao2_ref_debug(ret, 1, tag, file, line, funcname); 00644 else 00645 _ao2_ref(ret, 1); 00646 } 00647 00648 if (flags & OBJ_UNLINK) { /* must unlink */ 00649 struct bucket_list *x = cur; 00650 00651 /* we are going to modify the container, so update version */ 00652 ast_atomic_fetchadd_int(&c->version, 1); 00653 AST_LIST_REMOVE_CURRENT(entry); 00654 /* update number of elements and version */ 00655 ast_atomic_fetchadd_int(&c->elements, -1); 00656 if (tag) 00657 _ao2_ref_debug(EXTERNAL_OBJ(x->astobj), -1, tag, file, line, funcname); 00658 else 00659 _ao2_ref(EXTERNAL_OBJ(x->astobj), -1); 00660 free(x); /* free the link record */ 00661 } 00662 00663 if ((match & CMP_STOP) || (flags & OBJ_MULTIPLE) == 0) { 00664 /* We found the only match we need */ 00665 i = last; /* force exit from outer loop */ 00666 break; 00667 } 00668 if (!(flags & OBJ_NODATA)) { 00669 #if 0 /* XXX to be completed */ 00670 /* 00671 * This is the multiple-return case. We need to link 00672 * the object in a list. The refcount is already increased. 00673 */ 00674 #endif 00675 } 00676 } 00677 AST_LIST_TRAVERSE_SAFE_END; 00678 } 00679 ao2_unlock(c); 00680 return ret; 00681 }
static struct ao2_container* __ao2_container_alloc | ( | struct ao2_container * | c, | |
const unsigned int | n_buckets, | |||
ao2_hash_fn * | hash_fn, | |||
ao2_callback_fn * | cmp_fn | |||
) | [static] |
Definition at line 416 of file astobj2.c.
References ast_atomic_fetchadd_int(), ao2_container::cmp_fn, ao2_container::hash_fn, hash_zero(), ao2_container::n_buckets, and ao2_container::version.
00418 { 00419 /* XXX maybe consistency check on arguments ? */ 00420 /* compute the container size */ 00421 00422 if (!c) 00423 return NULL; 00424 00425 c->version = 1; /* 0 is a reserved value here */ 00426 c->n_buckets = n_buckets; 00427 c->hash_fn = hash_fn ? hash_fn : hash_zero; 00428 c->cmp_fn = cmp_fn; 00429 00430 #ifdef AO2_DEBUG 00431 ast_atomic_fetchadd_int(&ao2.total_containers, 1); 00432 #endif 00433 00434 return c; 00435 }
static struct ao2_container* __ao2_container_alloc | ( | struct ao2_container * | c, | |
const uint | n_buckets, | |||
ao2_hash_fn * | hash_fn, | |||
ao2_callback_fn * | cmp_fn | |||
) | [static] |
Referenced by _ao2_container_alloc(), and _ao2_container_alloc_debug().
static void * __ao2_iterator_next | ( | struct ao2_iterator * | a, | |
struct bucket_list ** | q | |||
) | [static] |
Definition at line 726 of file astobj2.c.
References ao2_lock(), AST_LIST_NEXT, AST_LIST_TRAVERSE, ao2_iterator::bucket, ao2_container::buckets, ao2_iterator::c, ao2_iterator::c_version, bucket_list::entry, F_AO2I_DONTLOCK, ao2_iterator::flags, INTERNAL_OBJ(), ao2_container::n_buckets, ao2_iterator::obj, bucket_list::version, ao2_iterator::version, and ao2_container::version.
Referenced by _ao2_iterator_next(), and _ao2_iterator_next_debug().
00727 { 00728 int lim; 00729 struct bucket_list *p = NULL; 00730 void *ret = NULL; 00731 00732 *q = NULL; 00733 00734 if (INTERNAL_OBJ(a->c) == NULL) 00735 return NULL; 00736 00737 if (!(a->flags & F_AO2I_DONTLOCK)) 00738 ao2_lock(a->c); 00739 00740 /* optimization. If the container is unchanged and 00741 * we have a pointer, try follow it 00742 */ 00743 if (a->c->version == a->c_version && (p = a->obj) ) { 00744 if ( (p = AST_LIST_NEXT(p, entry)) ) 00745 goto found; 00746 /* nope, start from the next bucket */ 00747 a->bucket++; 00748 a->version = 0; 00749 a->obj = NULL; 00750 } 00751 00752 lim = a->c->n_buckets; 00753 00754 /* Browse the buckets array, moving to the next 00755 * buckets if we don't find the entry in the current one. 00756 * Stop when we find an element with version number greater 00757 * than the current one (we reset the version to 0 when we 00758 * switch buckets). 00759 */ 00760 for (; a->bucket < lim; a->bucket++, a->version = 0) { 00761 /* scan the current bucket */ 00762 AST_LIST_TRAVERSE(&a->c->buckets[a->bucket], p, entry) { 00763 if (p->version > a->version) 00764 goto found; 00765 } 00766 } 00767 00768 found: 00769 if (p) { 00770 a->version = p->version; 00771 a->obj = p; 00772 a->c_version = a->c->version; 00773 ret = EXTERNAL_OBJ(p->astobj); 00774 /* inc refcount of returned object */ 00775 *q = p; 00776 } 00777 00778 return ret; 00779 }
static struct bucket_list * __ao2_link | ( | struct ao2_container * | c, | |
void * | user_data | |||
) | [static] |
Definition at line 484 of file astobj2.c.
References ao2_lock(), ast_atomic_fetchadd_int(), ast_calloc, AST_LIST_INSERT_TAIL, bucket_list::entry, INTERNAL_OBJ(), and OBJ_POINTER.
Referenced by _ao2_link(), and _ao2_link_debug().
00485 { 00486 int i; 00487 /* create a new list entry */ 00488 struct bucket_list *p; 00489 struct astobj2 *obj = INTERNAL_OBJ(user_data); 00490 00491 if (!obj) 00492 return NULL; 00493 00494 if (INTERNAL_OBJ(c) == NULL) 00495 return NULL; 00496 00497 p = ast_calloc(1, sizeof(*p)); 00498 if (!p) 00499 return NULL; 00500 00501 i = c->hash_fn(user_data, OBJ_POINTER); 00502 00503 ao2_lock(c); 00504 i %= c->n_buckets; 00505 p->astobj = obj; 00506 p->version = ast_atomic_fetchadd_int(&c->version, 1); 00507 AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry); 00508 ast_atomic_fetchadd_int(&c->elements, 1); 00509 00510 /* the last two operations (ao2_ref, ao2_unlock) must be done by the calling func */ 00511 return p; 00512 }
static int __ao2_ref | ( | void * | user_data, | |
const int | delta | |||
) | [static] |
Definition at line 255 of file astobj2.c.
References ast_atomic_fetchadd_int(), ast_log(), ast_mutex_destroy(), __priv_data::data_size, __priv_data::destructor_fn, free, INTERNAL_OBJ(), __priv_data::lock, LOG_ERROR, astobj2::priv_data, and __priv_data::ref_counter.
Referenced by _ao2_ref(), and _ao2_ref_debug().
00256 { 00257 struct astobj2 *obj = INTERNAL_OBJ(user_data); 00258 int current_value; 00259 int ret; 00260 00261 /* if delta is 0, just return the refcount */ 00262 if (delta == 0) 00263 return (obj->priv_data.ref_counter); 00264 00265 /* we modify with an atomic operation the reference counter */ 00266 ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta); 00267 current_value = ret + delta; 00268 00269 #ifdef AO2_DEBUG 00270 ast_atomic_fetchadd_int(&ao2.total_refs, delta); 00271 #endif 00272 00273 /* this case must never happen */ 00274 if (current_value < 0) 00275 ast_log(LOG_ERROR, "refcount %d on object %p\n", current_value, user_data); 00276 00277 if (current_value <= 0) { /* last reference, destroy the object */ 00278 if (obj->priv_data.destructor_fn != NULL) { 00279 obj->priv_data.destructor_fn(user_data); 00280 } 00281 00282 ast_mutex_destroy(&obj->priv_data.lock); 00283 #ifdef AO2_DEBUG 00284 ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size); 00285 ast_atomic_fetchadd_int(&ao2.total_objects, -1); 00286 #endif 00287 /* for safety, zero-out the astobj2 header and also the 00288 * first word of the user-data, which we make sure is always 00289 * allocated. */ 00290 memset(obj, '\0', sizeof(struct astobj2 *) + sizeof(void *) ); 00291 free(obj); 00292 } 00293 00294 return ret; 00295 }
void* _ao2_alloc | ( | size_t | data_size, | |
ao2_destructor_fn | destructor_fn | |||
) |
Definition at line 350 of file astobj2.c.
References __ao2_alloc().
Referenced by _ao2_container_alloc().
00351 { 00352 return __ao2_alloc(data_size, destructor_fn); 00353 }
void* _ao2_alloc_debug | ( | size_t | data_size, | |
ao2_destructor_fn | destructor_fn, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 330 of file astobj2.c.
References __ao2_alloc(), and REF_FILE.
Referenced by _ao2_container_alloc_debug().
00331 { 00332 /* allocation */ 00333 void *obj; 00334 FILE *refo = fopen(REF_FILE,"a"); 00335 00336 obj = __ao2_alloc(data_size, destructor_fn); 00337 00338 if (obj == NULL) 00339 return NULL; 00340 00341 if (refo) { 00342 fprintf(refo, "%p =1 %s:%d:%s (%s)\n", obj, file, line, funcname, tag); 00343 fclose(refo); 00344 } 00345 00346 /* return a pointer to the user data */ 00347 return obj; 00348 }
void* _ao2_callback | ( | struct ao2_container * | c, | |
const enum search_flags | flags, | |||
ao2_callback_fn * | cb_fn, | |||
void * | arg | |||
) |
Definition at line 691 of file astobj2.c.
References __ao2_callback().
Referenced by _ao2_find(), _ao2_unlink(), and container_destruct().
00693 { 00694 return __ao2_callback(c,flags, cb_fn, arg, NULL, NULL, 0, NULL); 00695 }
void* _ao2_callback_debug | ( | struct ao2_container * | c, | |
const enum search_flags | flags, | |||
ao2_callback_fn * | cb_fn, | |||
void * | arg, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 683 of file astobj2.c.
References __ao2_callback().
Referenced by _ao2_find_debug(), _ao2_unlink_debug(), and container_destruct_debug().
00687 { 00688 return __ao2_callback(c,flags, cb_fn, arg, tag, file, line, funcname); 00689 }
struct ao2_container* _ao2_container_alloc | ( | const unsigned int | n_buckets, | |
ao2_hash_fn * | hash_fn, | |||
ao2_callback_fn * | cmp_fn | |||
) |
Definition at line 449 of file astobj2.c.
References __ao2_container_alloc(), _ao2_alloc(), container_destruct(), and ao2_container::n_buckets.
00451 { 00452 /* XXX maybe consistency check on arguments ? */ 00453 /* compute the container size */ 00454 00455 size_t container_size = sizeof(struct ao2_container) + n_buckets * sizeof(struct bucket); 00456 struct ao2_container *c = _ao2_alloc(container_size, container_destruct); 00457 00458 return __ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn); 00459 }
struct ao2_container* _ao2_container_alloc_debug | ( | const unsigned int | n_buckets, | |
ao2_hash_fn * | hash_fn, | |||
ao2_callback_fn * | cmp_fn, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 437 of file astobj2.c.
References __ao2_container_alloc(), _ao2_alloc_debug(), container_destruct_debug(), and ao2_container::n_buckets.
00439 { 00440 /* XXX maybe consistency check on arguments ? */ 00441 /* compute the container size */ 00442 size_t container_size = sizeof(struct ao2_container) + n_buckets * sizeof(struct bucket); 00443 struct ao2_container *c = _ao2_alloc_debug(container_size, container_destruct_debug, tag, file, line, funcname); 00444 00445 return __ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn); 00446 }
void* _ao2_find | ( | struct ao2_container * | c, | |
void * | arg, | |||
enum search_flags | flags | |||
) |
Definition at line 705 of file astobj2.c.
References _ao2_callback(), and ao2_container::cmp_fn.
00706 { 00707 return _ao2_callback(c, flags, c->cmp_fn, arg); 00708 }
void* _ao2_find_debug | ( | struct ao2_container * | c, | |
void * | arg, | |||
enum search_flags | flags, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
the find function just invokes the default callback with some reasonable flags.
Definition at line 700 of file astobj2.c.
References _ao2_callback_debug(), and ao2_container::cmp_fn.
00701 { 00702 return _ao2_callback_debug(c, flags, c->cmp_fn, arg, tag, file, line, funcname); 00703 }
void* _ao2_iterator_next | ( | struct ao2_iterator * | a | ) |
Definition at line 799 of file astobj2.c.
References __ao2_iterator_next(), _ao2_ref(), ao2_unlock(), ao2_iterator::c, F_AO2I_DONTLOCK, and ao2_iterator::flags.
00800 { 00801 struct bucket_list *p = NULL; 00802 void *ret = NULL; 00803 00804 ret = __ao2_iterator_next(a, &p); 00805 00806 if (p) { 00807 /* inc refcount of returned object */ 00808 _ao2_ref(ret, 1); 00809 } 00810 00811 if (!(a->flags & F_AO2I_DONTLOCK)) 00812 ao2_unlock(a->c); 00813 00814 return ret; 00815 }
void* _ao2_iterator_next_debug | ( | struct ao2_iterator * | a, | |
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 781 of file astobj2.c.
References __ao2_iterator_next(), _ao2_ref_debug(), ao2_unlock(), ao2_iterator::c, F_AO2I_DONTLOCK, and ao2_iterator::flags.
00782 { 00783 struct bucket_list *p; 00784 void *ret = NULL; 00785 00786 ret = __ao2_iterator_next(a, &p); 00787 00788 if (p) { 00789 /* inc refcount of returned object */ 00790 _ao2_ref_debug(ret, 1, tag, file, line, funcname); 00791 } 00792 00793 if (!(a->flags & F_AO2I_DONTLOCK)) 00794 ao2_unlock(a->c); 00795 00796 return ret; 00797 }
void* _ao2_link | ( | struct ao2_container * | c, | |
void * | user_data | |||
) |
Definition at line 525 of file astobj2.c.
References __ao2_link(), _ao2_ref(), and ao2_unlock().
00526 { 00527 struct bucket_list *p = __ao2_link(c, user_data); 00528 00529 if (p) { 00530 _ao2_ref(user_data, +1); 00531 ao2_unlock(c); 00532 } 00533 return p; 00534 }
void* _ao2_link_debug | ( | struct ao2_container * | c, | |
void * | user_data, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 514 of file astobj2.c.
References __ao2_link(), _ao2_ref_debug(), and ao2_unlock().
00515 { 00516 struct bucket_list *p = __ao2_link(c, user_data); 00517 00518 if (p) { 00519 _ao2_ref_debug(user_data, +1, tag, file, line, funcname); 00520 ao2_unlock(c); 00521 } 00522 return p; 00523 }
int _ao2_ref | ( | void * | user_data, | |
const int | delta | |||
) |
Definition at line 245 of file astobj2.c.
References __ao2_ref(), and INTERNAL_OBJ().
Referenced by __ao2_callback(), _ao2_iterator_next(), _ao2_link(), and cd_cb().
00246 { 00247 struct astobj2 *obj = INTERNAL_OBJ(user_data); 00248 00249 if (obj == NULL) 00250 return -1; 00251 00252 return __ao2_ref(user_data, delta); 00253 }
int _ao2_ref_debug | ( | void * | user_data, | |
const int | delta, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 225 of file astobj2.c.
References __ao2_ref(), __priv_data::destructor_fn, INTERNAL_OBJ(), astobj2::priv_data, __priv_data::ref_counter, and REF_FILE.
Referenced by __ao2_callback(), _ao2_iterator_next_debug(), _ao2_link_debug(), and cd_cb_debug().
00226 { 00227 struct astobj2 *obj = INTERNAL_OBJ(user_data); 00228 00229 if (obj == NULL) 00230 return -1; 00231 00232 if (delta != 0) { 00233 FILE *refo = fopen(REF_FILE,"a"); 00234 fprintf(refo, "%p %s%d %s:%d:%s (%s) [@%d]\n", user_data, (delta<0? "":"+"), delta, file, line, funcname, tag, obj->priv_data.ref_counter); 00235 fclose(refo); 00236 } 00237 if (obj->priv_data.ref_counter + delta == 0 && obj->priv_data.destructor_fn != NULL) { /* this isn't protected with lock; just for o/p */ 00238 FILE *refo = fopen(REF_FILE,"a"); 00239 fprintf(refo, "%p **call destructor** %s:%d:%s (%s)\n", user_data, file, line, funcname, tag); 00240 fclose(refo); 00241 } 00242 return __ao2_ref(user_data, delta); 00243 }
void* _ao2_unlink | ( | struct ao2_container * | c, | |
void * | user_data | |||
) |
Definition at line 559 of file astobj2.c.
References _ao2_callback(), ao2_match_by_addr, INTERNAL_OBJ(), OBJ_NODATA, OBJ_POINTER, and OBJ_UNLINK.
00560 { 00561 if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */ 00562 return NULL; 00563 00564 _ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data); 00565 00566 return NULL; 00567 }
void* _ao2_unlink_debug | ( | struct ao2_container * | c, | |
void * | user_data, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 548 of file astobj2.c.
References _ao2_callback_debug(), ao2_match_by_addr, INTERNAL_OBJ(), OBJ_NODATA, OBJ_POINTER, and OBJ_UNLINK.
00550 { 00551 if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */ 00552 return NULL; 00553 00554 _ao2_callback_debug(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data, tag, file, line, funcname); 00555 00556 return NULL; 00557 }
void ao2_bt | ( | void | ) |
Definition at line 83 of file astobj2.c.
References ast_verbose, free, and N1.
00084 { 00085 int c, i; 00086 #define N1 20 00087 void *addresses[N1]; 00088 char **strings; 00089 00090 c = backtrace(addresses, N1); 00091 strings = backtrace_symbols(addresses,c); 00092 ast_verbose("backtrace returned: %d\n", c); 00093 for(i = 0; i < c; i++) { 00094 ast_verbose("%d: %p %s\n", i, addresses[i], strings[i]); 00095 } 00096 free(strings); 00097 }
int ao2_container_count | ( | struct ao2_container * | c | ) |
Returns the number of elements in a container.
return the number of elements in the container
Definition at line 464 of file astobj2.c.
References ao2_container::elements.
Referenced by __queues_show(), _sip_show_peers(), cli_tps_report(), do_timing(), and pthread_timer_open().
00465 { 00466 return c->elements; 00467 }
struct ao2_iterator ao2_iterator_init | ( | struct ao2_container * | c, | |
int | flags | |||
) |
initialize an iterator so we start from the first object
Definition at line 713 of file astobj2.c.
References ao2_iterator::c, and ao2_iterator::flags.
Referenced by __iax2_show_peers(), __queues_show(), _sip_show_peers(), ast_odbc_request_obj(), authenticate_reply(), check_access(), cli_console_active(), cli_list_devices(), cli_tps_report(), compare_weight(), complete_iax2_peers(), complete_iax2_unregister(), complete_queue(), complete_queue_remove_member(), complete_sip_peer(), complete_sip_registered_peer(), complete_sip_user(), complete_sipch(), delete_profiles(), delete_routes(), delete_users(), destroy_pvts(), dialgroup_read(), do_parking_thread(), dump_queue_members(), free_members(), get_member_status(), handle_cli_iax2_show_users(), handle_cli_moh_show_classes(), handle_cli_moh_show_files(), handle_cli_odbc_show(), handle_feature_show(), handle_parkedcalls(), handle_request_subscribe(), handle_show_routes(), iax2_getpeername(), iax2_getpeertrunk(), interface_exists(), interface_exists_global(), manager_iax2_show_peer_list(), manager_parking_status(), manager_queues_status(), manager_queues_summary(), num_available_members(), poke_all_peers(), pp_each_user_exec(), prune_peers(), prune_users(), queue_function_qac(), queue_function_qac_dep(), queue_function_queuememberlist(), reload(), reload_queues(), rt_handle_member_record(), set_member_paused(), set_member_penalty(), sip_poke_all_peers(), sip_prune_realtime(), sip_show_channel(), sip_show_history(), sip_show_inuse(), sip_show_users(), stop_streams(), tps_taskprocessor_tab_complete(), try_calling(), unload_module(), update_queue(), update_realtime_members(), and update_status().
00714 { 00715 struct ao2_iterator a = { 00716 .c = c, 00717 .flags = flags 00718 }; 00719 00720 return a; 00721 }
int ao2_lock | ( | void * | a | ) |
Lock an object.
a | A pointer to the object we want to lock. |
Definition at line 143 of file astobj2.c.
References ast_atomic_fetchadd_int(), ast_mutex_lock(), INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.
Referenced by __ao2_callback(), __ao2_iterator_next(), __ao2_link(), __queues_show(), _sip_show_peers(), add_to_queue(), ast_taskprocessor_get(), ast_taskprocessor_unreference(), build_parkinglot(), compare_weight(), complete_queue_remove_member(), complete_sip_user(), dialog_needdestroy(), end_bridge_callback(), find_call(), find_queue_by_name_rt(), get_member_penalty(), get_member_status(), handle_request_subscribe(), interface_exists_global(), is_our_turn(), join_queue(), leave_queue(), load_config(), load_realtime_queue(), manager_queues_status(), manager_queues_summary(), moh_release(), mohalloc(), monmp3thread(), mwi_event_cb(), pthread_timer_disable_continuous(), pthread_timer_enable_continuous(), pthread_timer_open(), pthread_timer_set_rate(), queue_function_qac(), queue_function_qac_dep(), queue_function_queuememberlist(), queue_function_queuewaitingcount(), queue_function_var(), recalc_holdtime(), record_abandoned(), reload_queue_members(), reload_queues(), remove_from_queue(), ring_entry(), run_timer(), set_member_paused(), set_member_penalty(), sip_poke_all_peers(), sip_prune_realtime(), sip_show_inuse(), sip_show_user(), sip_show_users(), try_calling(), update_call_counter(), update_queue(), update_realtime_members(), and update_status().
00147 { 00148 struct astobj2 *p = INTERNAL_OBJ(user_data); 00149 00150 if (p == NULL) 00151 return -1; 00152 00153 #ifdef AO2_DEBUG 00154 ast_atomic_fetchadd_int(&ao2.total_locked, 1); 00155 #endif 00156 00157 #ifndef DEBUG_THREADS 00158 return ast_mutex_lock(&p->priv_data.lock); 00159 #else 00160 return __ast_pthread_mutex_lock(file, line, func, var, &p->priv_data.lock); 00161 #endif 00162 }
int ao2_match_by_addr | ( | void * | user_data, | |
void * | arg, | |||
int | flags | |||
) |
void* ao2_object_get_lockaddr | ( | void * | obj | ) |
Return the lock address of an object.
[in] | obj | A pointer to the object we want. |
Definition at line 210 of file astobj2.c.
References INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.
00211 { 00212 struct astobj2 *p = INTERNAL_OBJ(obj); 00213 00214 if (p == NULL) 00215 return NULL; 00216 00217 return &p->priv_data.lock; 00218 }
int ao2_trylock | ( | void * | a | ) |
Try locking-- (don't block if fail).
a | A pointer to the object we want to lock. |
Definition at line 187 of file astobj2.c.
References ast_atomic_fetchadd_int(), ast_mutex_trylock(), INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.
00191 { 00192 struct astobj2 *p = INTERNAL_OBJ(user_data); 00193 int ret; 00194 00195 if (p == NULL) 00196 return -1; 00197 #ifndef DEBUG_THREADS 00198 ret = ast_mutex_trylock(&p->priv_data.lock); 00199 #else 00200 ret = __ast_pthread_mutex_trylock(file, line, func, var, &p->priv_data.lock); 00201 #endif 00202 00203 #ifdef AO2_DEBUG 00204 if (!ret) 00205 ast_atomic_fetchadd_int(&ao2.total_locked, 1); 00206 #endif 00207 return ret; 00208 }
int ao2_unlock | ( | void * | a | ) |
Unlock an object.
a | A pointer to the object we want unlock. |
Definition at line 165 of file astobj2.c.
References ast_atomic_fetchadd_int(), ast_mutex_unlock(), INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.
Referenced by __ao2_callback(), __queues_show(), _ao2_iterator_next(), _ao2_iterator_next_debug(), _ao2_link(), _ao2_link_debug(), _sip_show_peers(), add_to_queue(), ast_taskprocessor_get(), ast_taskprocessor_unreference(), build_parkinglot(), compare_weight(), complete_queue_remove_member(), complete_sip_user(), dialog_needdestroy(), end_bridge_callback(), find_call(), find_queue_by_name_rt(), get_member_penalty(), get_member_status(), handle_request_subscribe(), interface_exists_global(), is_our_turn(), join_queue(), leave_queue(), load_config(), load_realtime_queue(), manager_queues_status(), manager_queues_summary(), moh_release(), mohalloc(), monmp3thread(), mwi_event_cb(), pthread_timer_disable_continuous(), pthread_timer_enable_continuous(), pthread_timer_open(), pthread_timer_set_rate(), queue_function_qac(), queue_function_qac_dep(), queue_function_queuememberlist(), queue_function_queuewaitingcount(), queue_function_var(), recalc_holdtime(), record_abandoned(), reload_queue_members(), reload_queues(), remove_from_queue(), ring_entry(), run_timer(), set_member_paused(), set_member_penalty(), sip_poke_all_peers(), sip_prune_realtime(), sip_show_inuse(), sip_show_user(), sip_show_users(), try_calling(), update_call_counter(), update_queue(), update_realtime_members(), and update_status().
00169 { 00170 struct astobj2 *p = INTERNAL_OBJ(user_data); 00171 00172 if (p == NULL) 00173 return -1; 00174 00175 #ifdef AO2_DEBUG 00176 ast_atomic_fetchadd_int(&ao2.total_locked, -1); 00177 #endif 00178 00179 #ifndef DEBUG_THREADS 00180 return ast_mutex_unlock(&p->priv_data.lock); 00181 #else 00182 return __ast_pthread_mutex_unlock(file, line, func, var, &p->priv_data.lock); 00183 #endif 00184 }
int astobj2_init | ( | void | ) |
Provided by astobj2.c
Definition at line 1003 of file astobj2.c.
References ARRAY_LEN, and ast_cli_register_multiple().
Referenced by main().
01004 { 01005 #ifdef AO2_DEBUG 01006 ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2)); 01007 #endif 01008 01009 return 0; 01010 }
static int cb_true | ( | void * | user_data, | |
void * | arg, | |||
int | flags | |||
) | [static] |
special callback that matches all
Definition at line 572 of file astobj2.c.
References CMP_MATCH.
Referenced by __ao2_callback().
00573 { 00574 return CMP_MATCH; 00575 }
static int cd_cb | ( | void * | obj, | |
void * | arg, | |||
int | flag | |||
) | [static] |
Definition at line 820 of file astobj2.c.
References _ao2_ref().
Referenced by container_destruct().
00821 { 00822 _ao2_ref(obj, -1); 00823 return 0; 00824 }
static int cd_cb_debug | ( | void * | obj, | |
void * | arg, | |||
int | flag | |||
) | [static] |
Definition at line 826 of file astobj2.c.
References _ao2_ref_debug().
Referenced by container_destruct_debug().
00827 { 00828 _ao2_ref_debug(obj, -1, "deref object via container destroy", __FILE__, __LINE__, __PRETTY_FUNCTION__); 00829 return 0; 00830 }
static void container_destruct | ( | void * | c | ) | [static] |
Definition at line 832 of file astobj2.c.
References _ao2_callback(), ast_free, AST_LIST_REMOVE_HEAD, ao2_container::buckets, cd_cb(), bucket_list::entry, ao2_container::n_buckets, and OBJ_UNLINK.
Referenced by _ao2_container_alloc().
00833 { 00834 struct ao2_container *c = _c; 00835 int i; 00836 00837 _ao2_callback(c, OBJ_UNLINK, cd_cb, NULL); 00838 00839 for (i = 0; i < c->n_buckets; i++) { 00840 struct bucket_list *current; 00841 00842 while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) { 00843 ast_free(current); 00844 } 00845 } 00846 00847 #ifdef AO2_DEBUG 00848 ast_atomic_fetchadd_int(&ao2.total_containers, -1); 00849 #endif 00850 }
static void container_destruct_debug | ( | void * | c | ) | [static] |
Definition at line 852 of file astobj2.c.
References _ao2_callback_debug(), ast_free, AST_LIST_REMOVE_HEAD, ao2_container::buckets, cd_cb_debug(), ao2_container::n_buckets, and OBJ_UNLINK.
Referenced by _ao2_container_alloc_debug().
00853 { 00854 struct ao2_container *c = _c; 00855 int i; 00856 00857 _ao2_callback_debug(c, OBJ_UNLINK, cd_cb_debug, NULL, "container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__); 00858 00859 for (i = 0; i < c->n_buckets; i++) { 00860 struct bucket_list *current; 00861 00862 while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) { 00863 ast_free(current); 00864 } 00865 } 00866 00867 #ifdef AO2_DEBUG 00868 ast_atomic_fetchadd_int(&ao2.total_containers, -1); 00869 #endif 00870 }
static int hash_zero | ( | const void * | user_obj, | |
const int | flags | |||
) | [static] |
always zero hash function
it is convenient to have a hash function that always returns 0. This is basically used when we want to have a container that is a simple linked list.
Definition at line 408 of file astobj2.c.
Referenced by __ao2_container_alloc().
static struct astobj2* INTERNAL_OBJ | ( | void * | user_data | ) | [inline, static] |
convert from a pointer _p to a user-defined object
Definition at line 105 of file astobj2.c.
References AO2_MAGIC, ast_log(), and LOG_ERROR.
Referenced by __ao2_callback(), __ao2_iterator_next(), __ao2_link(), __ao2_ref(), _ao2_ref(), _ao2_ref_debug(), _ao2_unlink(), _ao2_unlink_debug(), ao2_lock(), ao2_object_get_lockaddr(), ao2_trylock(), and ao2_unlock().
00106 { 00107 struct astobj2 *p; 00108 00109 if (!user_data) { 00110 ast_log(LOG_ERROR, "user_data is NULL\n"); 00111 return NULL; 00112 } 00113 00114 p = (struct astobj2 *) ((char *) user_data - sizeof(*p)); 00115 if (AO2_MAGIC != (p->priv_data.magic) ) { 00116 ast_log(LOG_ERROR, "bad magic number 0x%x for %p\n", p->priv_data.magic, p); 00117 p = NULL; 00118 } 00119 00120 return p; 00121 }